ImageTrans可以通过WebSocket连接远程服务器,提供图片翻译服务。这个模式下有两端:

  • 服务端(ImageTrans_wsServer)跑在VPS上,接收翻译请求并调度
  • 客户端(ImageTrans)跑在家里的mac mini m4电脑上,负责实际的OCR、文字检测、翻译和排版

这套架构本身很简单,但要让它稳定运行,需要处理不少可用性问题。下面记录一下已经做的改进和发现的坑。

服务端的调度

最基本的问题是多客户端调度。服务端维护一个连接池,每个客户端连接时通过set_name_and_password上报自己的displayName,服务端据此分配任务。

调度时优先派给空闲实例。如果指定的实例正在忙,就找一个空闲的顶上。每个实例有独立的忙碌标记,用ConcurrentHashMapputIfAbsent保证原子性,避免两个请求同时抢占同一个实例。

另外还加了失败冷却机制:某个实例连续失败后,短时间内不再派给它。以及超时重派——如果实例在3秒内没有响应,或者60秒还没有完成,就把请求重新派给另一个实例。

客户端的进程隔离

客户端方面,主要做了两件事:

一是独立进程启动。翻译任务在单独的进程里执行,避免内存泄漏累积到主进程。这个通过useIndependentProcessForServer偏好设置控制,会在ExecuteWorkFlow时启用。

二是定期自行重启。客户端有一个RestartTimer,默认间隔8小时,到点后重新拉起自己。理论上可以清理掉累积的状态。

发现的问题

上面的机制看起来挺完整,但在实际运行中遇到了一些问题。

一个主要问题是客户端收到图片后进行处理,结果莫名卡死,导致该实例始终处于不可用状态。

应对方案

既然RestartTimer在卡死时靠不住,就绕过它,从进程外部动手。在宿主系统上用定时任务,每24小时pkill掉客户端进程再重新拉起。

定时kill有个明显缺陷:24小时是固定周期,不是”卡了才重启”。如果卡死发生在刚重启后10分钟,那要等23小时50分钟。

所以可以再写一个watchdog看门狗,通过服务器的list端口查看连接的客户端,如果连接的客户端的名字不存在了,就重启该进程。