zoukankan      html  css  js  c++  java
  • 大数据时遇到的问题

      十月一后正式接管金币交易服务,到最后基本使之稳定用了不到两个月。当时交易量平均每天5万条。

      接管的算是一个不太好的摊子,十月一期间还出现了某几个消费者服务挂了的现象,并且基本每天都产生一堆错误log,但是金币交易的整个流程我认为是没有问题的。 所以整个解决过程基本上围绕如何让错误log消失,log是程序员catch时捕获的。

      首先,解决的是匿名用户金币账户重复创建的问题。当业务部门在短时间发送多个同一匿名用户的交易请求时,每个请求处理流程都是先去数据库的匿名用户金币账户表检查是否存在,若不存在,则用Entity Framework创建,因为EF用的是批量提交,所以在未提交时,只是EF缓存中存在,DB里没有,而最后提交成功时,便在DB里创建了多个匿名金币账户。解决方案:当一有匿名金币账户创建,就立即提交缓存,不再批量提交。这是一个折衷方案,其实用户金币账户的创建不应在产生交易服务时才创建,而应在创建这个用户时就创建其金币账户。

      公司租的是电信云服务器,最多支持16G内存,所以只能升级到此。数据库做了集群,支持故障转移,查询时,镜像服务器上做快照,不再影响主库。 建立读写分离,并把一些耗时的job都转移到读库。 增加控制入队开关,这样当某个队列出现问题时可以安全关闭的金币交易,不用把整个网站停掉。 之前控制EF批量提交的时间和数量在redis上存,实际上是所有消费者公用,逻辑错误。后改为在内存中单独控制。

       当查找账户时,先从ObjectContext缓存中查,没有再查DB,后期,又增加了多次尝试从DB加载的机制,因为在DB繁忙时,偶尔会有超时现象。

      发现EF有个Bug,当DB里的值发生变化后,发起查询后,ObjectContext并不更新,还是老的。另外,当数据库发生震荡,譬如索引重建,会有重复插入数据的现象。这不是必现的,所以为解决这个问题,费了很大劲。开始时,测试环境用LoadRunner总是无法复现,而正式环境却不时冒出来。之前怀疑是缓存中记录之间有重复的,但经过事实证明,这个想法是错误的。然后,猜EF 插入提交成功后,EF 缓存里的数据对象状态并没有从Added 变为Unchanged,导致二次提交。在经过一次偶然机会错误复现后(大数据表做索引重建),终于证实并解决了,即在EF抛出重复插入主键异常的catch里把此数据对象状态从Added手工改为Unchanged。

      此后,已没有错误log产生,没有丢失数据或交易失败的现象。但是,消费者进程的内存随时间会不断变大,导致个别队列会有积累上千条未处理的现象。后用.NET Memory Profiler分析,发现是ObjectContext未释放。之后,后实现了一个定期释放的机制。

      在这期间,还做了个监控系统,一旦有错误log,就发消息到手机上,这个晚上在家也可以及时解决,如果是严重错误,会暂停这个队列的请求。

      至此,金币交易总算稳定了。用LoadRunner进行压力测试时,每个队列每秒大概能处理是十几笔交易。

  • 相关阅读:
    第一篇:spring boot 初始
    数据结构 -- 线段树
    数据结构 -- 优先队列和堆排序
    javaIO -- 流的体系设计思路、基础分类
    JavaIO -- Reader 和 Writer
    javaIO -- InputStream和OutStream
    javaIO -- File源码
    数据结构 -- 二叉树(Binary Search Tree)
    数据结构 -- 链表(LinkedList)
    数据结构 -- 栈(Stack)
  • 原文地址:https://www.cnblogs.com/iwilltry/p/4963443.html
Copyright © 2011-2022 走看看