[alibaba/tengine]dyups内出现了一个已经失效的IP,导致服务504

2024-07-10 30 views
5

环境: Tengine version: Tengine/2.1.2 (nginx/1.6.2) CentOS release 6.6 (Final) 启用了 dyups

1:我们服务突然接到504报警,查看报警发现是一台一天前已经下线的机器,查新nginx日志发现流量确实被指向了这台机器;

2:查看当时异常日志发现 曾经出过core 错误日志: 2018/03/16 13:08:08 [alert] 189446#0: worker process 915157 exited on signal 11 (core dumped) 2018/03/16 13:08:08 [alert] 5021#0: [dyups] process start after abnormal exits messages log: Mar 16 13:08:07 xxxx kernel: [6292734.932259] __ratelimit: 18 callbacks suppressed Mar 16 13:08:07 xxxx kernel: [6292734.932262] nginx[915157]: segfault at 20 ip 000000000044f4c0 sp 00007fff00117348 error 4 in nginx[400000+39b000] Mar 16 13:08:08 xxx abrt[5020]: abrtd is not running. If it crashed, /proc/sys/kernel/core_pattern contains a stale value, consider resetting it to 'core'

回答

7

@maqingshan 1、产生504状态码,应该是由于连接后端超时导致(连接到被下线的机器)、你可以结合Tengine提供的主动健康模块或者针对此种场景进行重试(限制重试次数)进一步规避这种问题。 2、关于core dump问题,麻烦帮忙看看具体coredump的堆栈信息。 3、如果可以本地复现的话,请提供一个最小复现配置及环境信息。

谢谢

7

@wangfakang 1:“连接到被下线的机器”问题就在这里,我们的配置文件里已经删除了这台下线的机器,也从来没有通过dyups添加这台机器。从现象上看就是nginx core后 突然把之前的IP在dyups里添加了。 2:我们查询了日志 这台机器错误日志出现的时间就是core之后,我们reload错误IP就没有了。 3:我们线上服务器没有开启core 没有当时的堆栈信息可参考了。 4:我们之前都没有出现过这个问题,这次是第一次,我们会尝试本地复现。 5:我不知道这个是否跟之前cf未初始化那个bug有关系,所以不确定是否通过升级tengine 可以修复这个问题。

4

@maqingshan 1、这个是由于core dump的进程会被master重新拉起(fork),此时会从master进程copy最初tengine启动时解析到的配置信息(而最初这个配置是没有删除对应upstream里面的ip),所以新拉起来的这个worker里面会存在之前被删除的ip,看起来是一种“新增”的假象。 2、之所以reload就好了,是由于reload会重新加载新的配置(新配置里面已经摘掉里那个ip)。 3、可以尝试分析一下core dump前后的access和error日志,看看其请求是否有特别之处。 4、如果没有引入第三方模块的话,应该和cf未初始化这个bug关系不大。 5、升级还是有必要的,新版本中新增了不少特性以及功能修复,详细见Changelog

3

@wangfakang 这个问题近期我们也遇到了,看上去就是dyups没有处理worker coredump后,master 处理CHLD信号 fork新进程直接继承原来的静态cycle导致dyups部分上下线消息丢失。我理解,这种情况虽然通过reload可以解决 但并不合适,是否可以在dyups更新消息时,master也加个timer,定时消费队列去解决?虽然给master引入了额外工作,但至少可以保证异常情况dyups正常工作。 备注:当前版本也是2.1.2,并没有在高版本 changelog中看到相关修复

9

关于这个问题 是否还有更好地修复方式?辛苦给些建议

3

@FengXingYuXin 可以在worker init阶段从其他数据源(如磁盘)加载最新upstream数据.

3

我们使用从内存恢复的方式解决了问题,已经提PR https://github.com/alibaba/tengine/pull/1156 :1 首次处理dyups更新消息(update&delete)的worker负责记录一份消息到共享内存队列中(如果upstream有过变更,只记录最新的一条消息即可);2 worker 初始化时,遍历共享内存的历史消息队列,对变更消息进行一次全量追加(如果是reload,因为master cycle初始化时,会清空共享内存队列,所以不会引入任何操作),这就保证只有在worker coredump时才会追加消息。 相比从磁盘加载的好处: 1 磁盘加载worker需要同步全量的upstream数据,增加了每次reload的时间; 2 官方_dyups_upstream_conf指令 仅支持单个文件参数,对于线上upstream数据分类管理的情况不太适用,比如我们的业务场景就会把upstream数据分为服务粒度、泳道、set化、分组等等,需要给指令配置多个目录,增加运维; 3 Nginx原生框架中,磁盘数据都是master进程负责处理,然后fork工作进程,如果这个磁盘加载操作放到worker初始化阶段,每个worker都需要从磁盘加载,逻辑重复。 结合上面,总体上,从内存同步更合适。(备注:这里为了复用dyups原来的部分逻辑,采用队列存储历史消息,这里当然也可以使用rbtree,小伙伴可以根据情况选择)