最近在做秒杀的服务,虽然目前由于机器性能优越可以抗着,但是被刷过于厉害的时候,显然还是可以感觉到有一定的卡顿感。整个活动基于 nodejs + redis 实现,验证码通过 golang 服务生成[有事先生成验证码,后期逐段更新,验证码单台可抗住 5K/s 并发]。
问题的继续得益于一个技术群里面抛出的问题,问题的大概如下:
使用 nodejs + redis 实现,高并发的时候如果单次请求操作 redis 次数很少的话没问题,但是如果单次请求操作 redis 很多次的话,会发现 nodejs 的内存突然飙高。
后期讨论的时候另一个人又抛出另一个问题:
高并发的时候,持续对 redis 操作,导致单进程的 redis 服务返回很久。
于是我们目前偶尔出现的卡顿也可能是由于上面的一种或者两者同时造成的。
分析第一个问题,初步猜测是由于 Nodejs 同时发起的 redis 请求太多导致自身内存飙高,同时 redis 受到的影响不大。所以想到的解决方案是如何合并每次请求导致的 redis 操作次数。redis 自身支持 lua 脚本,参见:
http://redisbook.readthedocs.org/en/latest/feature/scripting.html 【中文】
http://redis.io/commands/EVAL 【en】
目前解决的简单思路为将每个请求带来的简单操作使用 Lua 脚本合成一个,用秒杀来说:
- 判断奖品列表中POP返回是否为空。
- 更新用户设置为已抽奖。
- 在队列里面写入需要更新奖品 ID 以及其使用情况和所属情况。
…
如果都在 nodejs 中,可能每个请求都会有 2-3 或者更多的 redis 操作请求,现在请求变成了一个。变相的减少了 IO 上面的开销。具体的效果怎么样,还需要后续的测试于监控。
第二个问题是如何利用多台机器去应对 redis 的运算瓶颈。目前也还在设计中,可能需要学习 MYSQL 分表,将一些 Key 放在机器 A,一些 Key 放在机器 B,同时还需要将这些机器的数据都同步到机器 C,保证平均分布操作多台,但是数据又能得到备份。