|
| 1 | +### 关于主动健康检查模块出现很多问题的原因分析以及优化方案 |
| 2 | + |
| 3 | +#### 主动健康检查模块出现很多问题的原因分析 |
| 4 | +##### `结论在前` |
| 5 | + - 从代码提交记录以及实现上看,该模块一开始可能并没有考虑动态增删节点的情况,加上在本地和共享内存中使用动态数组存储探测节点,节点状态以及数组索引容易错乱,代码不容易理解和维护,所以会遇到很多问题。 回到需求本身,主动健康检查模块功能其实比较简单,就是增删节点以及查询节点状态,对应红黑树的增删查操作,底层存储结构更适合使用红黑树, 不存在本地和共享内存中节点数组索引混乱以及通过节点delete状态复用数组元素空间的需求,从根本上避免了下述第1点和第2点带来的已发现以及尚未发现的问题,针对第3点合理控制共享内存锁粒度即可。 |
| 6 | +##### 具体原因分析 |
| 7 | + - 该模块在本地和共享内存中使用动态数组存储探测节点,需要处理好以下几点,但实际代码并没有处理好,很多问题稍微测试就能发现 |
| 8 | + - 第1点-如何复用数组节点空间 |
| 9 | + - 第2点-多进程时,如何保证本地节点正确关联到共享内存节点,如果通过index,需要保证本地数组index以及共享内存数组index的有效性以及关联的正确性 |
| 10 | + - 第3点-多进程并发读写共享内存节点数组需要保证互斥 |
| 11 | +###### 针对第1点-如何复用数组节点空间 |
| 12 | + - 共享内存节点数组元素使用delete成员变量表示节点状态(PEER_NORMAL|PEER_DELETING|PEER_DELETED),当状态为PEER_DELETED表示节点可复用,需要正确处理好状态切换,本地节点数组元素使用delete成员变量表示节点状态(0|1)表示节点是否可以复用,程序到处都是节点状态判断的逻辑,一旦出现问题就会导致指向错误的节点。 --- 实际上不需要这么复杂且容易出错的处理逻辑。 |
| 13 | + - 已发现以下问题: |
| 14 | + - status接口显示的节点index应该是共享内存的Index,而不是本地数组的Index |
| 15 | + - [修复多进程时健康状态显示的节点index不一致问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/30) |
| 16 | + - 查询节点状态时传递的index是共享内存节点数组Index,不能用来索引本地节点数组元素 |
| 17 | + - [修复健康检测状态节点删除期间被重用导致的segfault问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/19/diffs) |
| 18 | + - [修复实际存在可用节点时报no_live_upstream的问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/23/diffs#1a83ab4fa783ce842f1dc782ac2309f05b5ed010) |
| 19 | + - 多进程时,某个进程检测到节点不通时,会将共享节点状态标记为PEER_DELETING,所以进程都检测到节点不通时,才会标记状态为PEER_DELETED,会导致会向已经不通的节点转发请求,实际上此时不应该转发 |
| 20 | + - status接口没有判断本地节点delete状态过滤已删除的节点 |
| 21 | + - [动态upstream删减后查询status会出现Segment Fault的问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/2/diffs?commit_id=981ff041c7d4a8c6b194aa1a1760eb2c47256db8) |
| 22 | + - 检查节点状态时没有判断delete值 |
| 23 | + - [避免向已删除的动态节点转发请求](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/12/diffs#1a83ab4fa783ce842f1dc782ac2309f05b5ed010) |
| 24 | + - [修复未启用主动健康检测功能时存在的segfault问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/17/diffs) |
| 25 | + - 误用节点index索引 |
| 26 | + - [修复误用节点索引导致偶发无可用后端节点的问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/21/diffs) |
| 27 | + |
| 28 | +###### 针对第2点-多进程时,如何保证本地节点正确关联到共享内存节点,如果通过index,需要保证本地数组index以及共享内存数组index的有效性以及关联的正确性 |
| 29 | + - 在增加/删除节点时,使用index建立本地节点和共享内存节点对应关系,查询节点状态时,获取共享内存节点数组Index下标对应元素。因为多进程时,本地和共享内存节点数组元素顺序通常会不一致,本地节点Index和共享内存中的Index很容易混乱 |
| 30 | + - 已发现以下问题: |
| 31 | + - [修复健康检测节点索引错乱的问题-返回的index指向的是刚复用的节点](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/24/diffs) |
| 32 | + - [删除不必要的判断共享内存index有效性条件](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/32) |
| 33 | + |
| 34 | +###### 针对第3点-多进程并发读写共享内存节点数组需要保证互斥 |
| 35 | + - 已发现以下问题: |
| 36 | + - [修复后端节点地址连接失败时存在的死锁问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/3/diffs) |
| 37 | + - [修复健康状态节点复用情况下出现segfault的问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/15/diffs) |
| 38 | + - [修复同时使用共享内存锁与节点锁导致不恰当的并发问题](http://git.koal.com/gw-server/ngx_healthcheck_module/-/merge_requests/26/diffs) |
| 39 | +###### 其他问题 |
| 40 | + - 因为底层数组结构是数组,在增加节点以及查找可复用节点时都需要for循环,当节点数量较多时,使用数组并不高效 |
| 41 | + - 代码冗余太多,尤其是status模块和探测模块的数据结构定义完全一致,只是结构体名称不一样,调整结构体成员变量时两边都需要修改,其实只需要共同包含一份定义即可 |
| 42 | + - 不完全支持配置探测时使用长连接 |
| 43 | + - 官方仓库最近一次提交日期是 Jun 4, 2021,一直没有更新 |
| 44 | + |
| 45 | + |
| 46 | +### `优化方案` |
| 47 | + - 基于上述分析,我针对之前写的[健康探测模块](https://github.com/alexzzh/ngx_health_detect_module)做了拓展,使其能和upstream相结合,完全支持`主动健康检查模块`的功能,主要区别就是底层存储结构使用的是红黑树以及部分功能增强,代码也更容易理解和维护。 |
0 commit comments