最近接到需求, 目前项目满足不了, 需要通过中间件实现.
经过讨论和分析, 最后打算 使用 swoole
构建一个 Tcp Rpc
服务.
正常的Rpc 轮子遍地都是 , 但是我们的需求很独特, 需要根据参数
将请求分配至指定 进程
. 构建出一套同步堵塞
的服务.
场景举例:
修改用户A的资产, 通过参数 `uid` 分配器将 请求发送至固定 进程. 使得用户资产都在单进程内排队更新.
上面的场景是很好实现的, 我们也已经在线上运行了一段时间, 基本告别了 过去的mysql
存储用户资产, 并发操作用户资产造成的死锁问题.
重点场景:
两个用户交易资产, 通过参数 `uid`, `bak_uid` 分配器将请求发送到固定 进程.....
显然不现实, 高并发场景下, 两个uid 分配到固定进程, 有些扯淡, 所以需要写个算法提供给两个uid 指定进程 `x`, 并且保证接下来的请求带有之前
的参数都必须都往这个执行进程 `x` 打
第一个场景 单用户 进程分配方式固定 取模
即可实现
第二个场景 多用户 进程分配方式动态算法 实现 中间坑很多 但也最终实现, 但性能堪忧, 有待测试调优.
说下开发中的坑 技术选型 swoole
go
因为是phper
所以默认选 swoole
使用swoole
的 自定义分配方法 dispatch_func
参数 实现 放在在这里相当于所有请求都经过这里, 这是一个分配进程的好地方.
之前使用 dispatch_func
方法 踩了 return -1
; 的坑, 结果死循环, 前面文章有提到过.
在调优过程中 通过观察 server->stats
参数如下
[stats] => Array
(
[start_time] => 1544262210
[connection_num] => 14889
[accept_count] => 14889
[close_count] => 0
[tasking_num] => 0
[request_count] => 518771
[worker_request_count] => 5
)
connection_num
当前连接数 竟然都没有释放
配合 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
查看 CLOSE_WAIT
TIME_WAIT 4969
CLOSE_WAIT 13494
ESTABLISHED 1045
果然大量客户端异常断链 导致服务端仍保持连接
问题解决 :
// 心跳相关 https://wiki.swoole.com/wiki/page/284.html
// 'heartbeat_idle_time' => 60,
// 'heartbeat_check_interval' => 10,
// 开启 TCP keepalive https://wiki.swoole.com/wiki/page/p-tcp_keepalive.html
'open_tcp_keepalive' => 1, // 死连接检测
'tcp_keepidle' => 60, // 单位秒,连接在n秒内没有数据请求,将开始对此连接进行探测。
'tcp_keepcount' => 6, // 探测的次数,超过次数后将close此连接。
'tcp_keepinterval' => 10, // 探测的间隔时间,单位秒。
使用 tcp keepalive
保持连接即可 , 但使用定时ping
的方法并不能有效维持连接 1分钟后连接全部断了, 具体原因暂时没时间搞, 但 keepalive
较为消耗性能 最好还是用心跳包, 减少浪费流量及CPU.
未完待续...