- 从代码提交记录以及实现上看,该模块一开始可能并没有考虑动态增删节点的情况,加上在本地和共享内存中使用动态数组存储探测节点,节点状态以及数组索引容易错乱,代码不容易理解和维护,所以会遇到很多问题。 回到需求本身,主动健康检查模块功能其实比较简单,就是增删节点以及查询节点状态,对应红黑树的增删查操作,底层存储结构更适合使用红黑树, 不存在本地和共享内存中节点数组索引混乱以及通过节点delete状态复用数组元素空间的需求,从根本上避免了下述第1点和第2点带来的已发现以及尚未发现的问题,针对第3点合理控制共享内存锁粒度即可。
- 该模块在本地和共享内存中使用动态数组存储探测节点,需要处理好以下几点,但实际代码并没有处理好,很多问题稍微测试就能发现
- 第1点-如何复用数组节点空间
- 第2点-多进程时,如何保证本地节点正确关联到共享内存节点,如果通过index,需要保证本地数组index以及共享内存数组index的有效性以及关联的正确性
- 第3点-多进程并发读写共享内存节点数组需要保证互斥
- 共享内存节点数组元素使用delete成员变量表示节点状态(PEER_NORMAL|PEER_DELETING|PEER_DELETED),当状态为PEER_DELETED表示节点可复用,需要正确处理好状态切换,本地节点数组元素使用delete成员变量表示节点状态(0|1)表示节点是否可以复用,程序到处都是节点状态判断的逻辑,一旦出现问题就会导致指向错误的节点。 --- 实际上不需要这么复杂且容易出错的处理逻辑。
- 已发现以下问题:
- status接口显示的节点index应该是共享内存的Index,而不是本地数组的Index
- 查询节点状态时传递的index是共享内存节点数组Index,不能用来索引本地节点数组元素
- 多进程时,某个进程检测到节点不通时,会将共享节点状态标记为PEER_DELETING,所以进程都检测到节点不通时,才会标记状态为PEER_DELETED,会导致会向已经不通的节点转发请求,实际上此时不应该转发
- status接口没有判断本地节点delete状态过滤已删除的节点
- 检查节点状态时没有判断delete值
- 修复未启用主动健康检测功能时存在的segfault问题
- 误用节点index索引
- 在增加/删除节点时,使用index建立本地节点和共享内存节点对应关系,查询节点状态时,获取共享内存节点数组Index下标对应元素。因为多进程时,本地和共享内存节点数组元素顺序通常会不一致,本地节点Index和共享内存中的Index很容易混乱
- 已发现以下问题:
- 因为底层数组结构是数组,在增加节点以及查找可复用节点时都需要for循环,当节点数量较多时,使用数组并不高效
- 代码冗余太多,尤其是status模块和探测模块的数据结构定义完全一致,只是结构体名称不一样,调整结构体成员变量时两边都需要修改,其实只需要共同包含一份定义即可
- 不完全支持配置探测时使用长连接
- 官方仓库最近一次提交日期是 Jun 4, 2021,一直没有更新
- 基于上述分析,我针对之前写的健康探测模块做了拓展,使其能和upstream相结合,完全支持
主动健康检查模块
的功能,主要区别就是底层存储结构使用的是红黑树以及部分功能增强,代码也更容易理解和维护。