工作小结

入职公司已经两年半了,也是时候做一总结了。总体来说,公司业务可以分为三部分:信息管理、监测、问答交流。其中,最核心的业务就是监测了,主要是通过自研以及第三方合作的硬件设备来采集数据,并传输采集的数据至后台服务,从而来进行展示与分析。围绕着核心的监测业务,系统还扩展出了各种相关业务,比如相关信息的管理(如机构管理、设备管理、人员管理等)、监测结果提醒(根据自定义规则触发各种提醒)、监测后的咨询服务(如可付费咨询)等等。

在公司的这段时间,除了完成业务之外,还需要经常和产品、经理沟通。在整个流程中,往往实现需求只是一部分,还需花时间是讨论与完善需求。因为需求是在不断完善与迭代的,所以良好的沟通是免不了的。这对从前只是着眼于代码实现的自己是一个不小的变化。

在公司印象最深刻的一段时间,是原先负责核心模块监测的同事突然离职的时期。因为同事离职离的比较突然,便临时让我顶上。这既是压力也是机会,压力在于没有文档与交接,刚接触到这个模块的自己可以说是两眼一抹黑。而机会在于实际开始负责了核心的监测业务。

在这段时间,自己梳理了已有的监测流程,给出了整个数据流转的文档图片。而与此同时,由于用户量变多,线上监测结果出不来的问题频发。经过分析与讨论,基本认为是由于用户网络状况导致一些出监测结果的“必要条件”没有触发。

原流程是这样的:

  • 服务器通过 mqtt 收到的开始消息更改监测状态
  • 服务器通过 mqtt 收到的结束消息更改监测状态并通知监测完成
  • app 上传监测数据
  • app 通过 http 接口通知生成报告

分析下来,发现如果要成功完成监测后需要报告,那么移动端 app 需要确保:

  1. 服务器收且只收一次通过 mqtt 发送的开始监测消息
  2. 服务器收且只收一次通过 mqtt 发送的结束监测消息
  3. 成功将监测数据上传至文件服务器
  4. 成功调用生成报告接口

也就是一共有 4 个必要条件必须完成。而第一、第二个虽然可以通过 mqtt 的 qos 机制来保证,但实际情况下,mqtt 并不能百分百保证消息仅且仅到达一次,在网络不佳的情况下,没有到达或者到达多次均有出现,而第三个数据文件没有上传和第四个接口没有成功调用更是出现的频繁。所以原先的设计本身也许没有问题,但在网络不可控的情况下,四个条件一旦有一个不满足,那么就会产生报告数据难找、找不到等问题。在这种情况下,线上经常出现相关问题也是可以预计的了。如果要解决不出监测结果的问题,那么这套流程是需要进行精炼、调整的。

而又恰逢新需求出现,需要支持离线监测,而原有的设计并不能很好的满足这个需求,于是改变这套流程是必须的。于是有了重新设计的机会。而新设计的第一步,当然是确保监测报告的正常生成。经过分析,报告生成的最小化条件很明显,那就是监测数据成功上传。

那么,能不能实现只要监测数据成功上传,就能根据监测数据生成报告?

因为文件存储服务使用的是阿里云的 oss 服务,oss 提供上传成功后的回调服务。因为服务器也是阿里云的,所以 oss 的回调本身不大可能出现因为网络问题而产生的失败。这看似是可行的,那么有没有更加万无一失的办法呢?

答案是有的。那就是扫描特定目录,如果该目录下有文件,就认为是需要分析的文件,分析完后移走即可。如此,只要客户端把监测数据上传,那么就可以出报告,免去了其余所有的条件。

接下来的问题又来了,如果是单节点点线程,实现非常容易。那如果是多线程、多节点呢?如何支持并发?这里参考了 concurrentHashMap rehash 的一些思路:通过 redis 实现分布式锁,并利用分布锁实现:

  • 从 /to_generate 获取监测文件,移至 /{clientId}/generating
  • 生成报告后,再从/{clientId}/generating 移至 /generated

其中具体的细节就不在多言,改动后的新版本上线后,报告数据丢失的情况没有再次出现,监测业务稳定性获得提升。而经历了这次重构,自己最大的感受就是分分合合。无论是业务还是设计,都各种各样的切入点。而去选择其中的优雅的切入点,是很有挑战的。但一旦选择对了,往往很多问题会变得迎刃而解。而如果选择了不适合的,可能就要为这选择打上无数的补丁、填上各种的坑。而这在公司里更是遇到不少。

有时一个需求下来,看上去上并不复杂,但这种实现起来才发觉,其中牵扯进各种其他的业务,动一发便有千丝万缕的影响。也因此,需求涉及点如滚雪球般越滚越大,补丁越打越多,代码也越来越臃肿丑陋。时常在想,如果一开始采用微服务结构,会不会好点?但这就是另外的故事了。