说句实话我自己都不太信,今天这个锅是我自己亲手甩到自己脸上的。
事情是这样的——之前写了个小脚本,每天读RSS然后转推一些技术文章,跑了小半年一直没事。后来嫌它太傻,就把调度方式整个换了。当时觉得逻辑很简单嘛,读出来推送,推完记录一下ID,防止重复转发。用的Redis做去重,key带个文章ID。真的,这一整套流程我当时觉得,闭着眼睛都不会写错。
结果今天早上一起床,发现内存被打爆了,Redis直接拒绝写入,然后脚本疯狂报错重试,日志刷得像在被DDOS。
我第一反应是数据量涨了,这很正常对吧。我当时都准备去骂云服务商了。然后打开dashboard一看——好家伙,内存里的key多出一百多倍。一瞬间我就反应过来了,跑代码的时候我就觉得哪里不对,那个key设计得不对劲,但我没细想,想的是"反正就是一个去重,能有多大问题"。
实际上Redis里每个key对应一个set,set里面存所有的已推送ID,每个ID大概几十字节。关键是,我忘了数分区。整个数据被分到五十多个分区,每个分区里的每个key都存了一遍全部数据,内存直接指数膨胀。打个不恰当的比方,等于我本来只需要存一遍的东西,我存了五十多遍。
修的过程没啥好说的,写个脚本把数据重新迁移,原来的旧key全部清掉。让我有点后怕的是,如果这个脚本是部署在生产环境上的,或者我再晚一个小时发现,可能整个线上服务都要跟着遭殃。
——
这次说的比较技术,可能有人要问了,为什么不直接用SQLite,是不是Redis更好?不是广告,也谈不上推荐,纯粹因为之前顺手配了Redis,然后就懒得换回来。与其说是技术选型,不如说是惰性选型。
说句实话,这次的教训无非就是那些,代码写完不能只过自己的脑子,得有人review,哪怕是自己review。但这个道理我上次写完就忘了,今天又付了一遍学费。不知道还要付几次才能长记性。
算了,不写了,天太热,去喝口冰水。这破代码,改天再说。就说到这。