最近使用swoole写了websocket系统服务,出现cpu和内存持续增长的故障。
使用strace工具查看系统栈调用情况:
strace -cp 进程
在syscall一栏发现socket创建过于频繁,系统服务定义了一个5秒的定时器进行轮询redis队列。而在这个定时器里,每次执行都会new redis对象,频繁创建socket连接是有开销的,这也是出现cpu持续增长的原因。
解决方案有两个:
- 使用连接池,连接池事先创建好一定数量的连接保存在内存,当需要使用连接的时候从内存取出空闲的连接对象,这样的好处是避免了频繁创建socket连接的开销,使数据连接得到重复利用。
- 使用长连接,使用static变量保存连接对象,避免了每次定时器触发的时候创建redis对象。
在当前场合,因为5秒轮询一次,redis连接是长期占用,无疑使用独占连接更适合。所以选择了方案二。
使用长连接后虽然cpu占用降低了,但观察strace发现sendto函数调用非常频繁超过了5秒执行一次的预期。
后查找代码找到了原因:定时器嵌套。代码在work进程定义了每秒触发的定时器去执行定时计划,而redis轮询服务是放在计划任务里又定义了5秒轮询的服务,而最后执行的结果已经不是5秒触发一次了。
总结
- 不要在定时器里定义其他定时器。
- 不要频繁创建socket连接