十月一后正式接管金币服务,到最后基本使之稳定用了两个月。当时交易量平均每天5万条。 接收的算是一个不太好的摊子,十月一期间还出现了某几个StandaloneDealer服务挂了的现象,并且基本每天都一堆错误log,但是金币交易的整个流程我认为是没有问题的。 所以整个解决过程基本上围绕如何让错误log消失,log是程序员catch时捕获的。 首先,解决的是匿名用户重复创建的问题。当业务部门在短时间发送多个同一匿名用户的交易请求时,Dealer会先去数据库匿名表检查不存在,然后创建,EF用的是批量提交,所以在未提交时,DB检查不存在,就是在缓存中创建多个相同的匿名用户。解决方式:当一有匿名账户创建,就立即提交缓存。这是一个折衷方案,正式用户的创建是放在CBC前台创建时调用,而对于匿名用户也应该保持统一。 公司租的是电信服务器,最多支持内存16G,所以只能升级到此。数据库做了镜像,支持故障转移,查询时,只需在上面做快照,基于快照查询不影响主库。 建立读写分离,把之前耗时的job都转移到读库。 增加控制入队开关,这样可以安全关闭金币交易,不用把整个网站停掉。 之前控制缓存提交时间和数量在redis上,实际上是所有dealer公用,逻辑错误。后改为在内存中单独控制。 当查找账户时,先从ObjectContext缓存中查,没有再查DB,(后期,又增加了多次尝试从DB加载的机制,因为在DB繁忙时,偶尔会有超时现象)。 发现EF有个问题,当DB的值发生变化后,经过一次查询,Context并不更新,还是老的。 当数据库发生震荡,譬如索引重建,会有重复插入¬PartialTrade的现象。这不是必现的,所以解决这个问题时,费了很大劲。开始时,测试环境用loadrunner总是无法复现,而正式环境却不时冒出来。之前怀疑是缓存中记录之间有重复的,但经过事实证明,这个想法是错误的。然后,猜是缓存和DB之间有重复,(DB insert提交成功后,cacah 里的数据对象状态并没有从Added 变为Unchanged,导致二次提交)在经过一次偶然机会错误复现后(PartialTrade 表做碎片整理时),终于证实并解决了。 到此为止,已经没有错误log,没有丢失数据或交易的现象。但是,dealer的内存随时间会变大,个别队列会有积累上千条未处理的现象。后用.NET Memory Profiler分析,发现是ObjectContext未释放。之后,实现了一个定期释放的机制。 在这期间,还做了个监控系统,一旦有错误log,就发消息到手机上,这个晚上在家也可以及时解决,如果是严重错误,会暂停这个队列的请求。 至此,金币交易总算稳定了。用LoadRunner进行压力测试时,每个队列每秒大概能处理是十几笔交易。
时间: 2024-10-27 08:05:57