高并发读与高并发写的项目总结和mongodb使用中遇到的坑
来源:互联网 发布:知乎 宋茜 编辑:程序博客网 时间:2024/05/21 15:25
最近开发了一个既要高并发写又要高并发读的项目,写的QPS比读还要高,这个需求几乎是变态的,任何缓存的工具都没法使用,数据在一秒内可能变化的几十遍,只能每次请求都实时从数据库读取。下面分如下几点介绍我们是如何技术选型的。
一、选择通信协议
之前写的项目并发量很小,http+keepalive完全可以搞定了,此项目http完全架不住,因为使用http协议传递数据,那么数据最友好的格式就是json,但是亲测过json的序列化和反序列化的耗时不可以忍受,并且随着数据量的增大耗时也将成倍增长,项目的实际应用场景在写操作时每条数据最大在10KB,因此http+json的组合被kill掉。
只能选择常见的RPC方式,thrift、protobuf,protobuf需要自己实现tcp的通信方式,我们项目使用的是golang开发,这两种方式之前都没有在生产环境使用过,thrift仅仅自己玩过,因此就直接选择了thrift,编码的量级也相比protobuf降低好多,不过在代码写差不多的时候发现golang有基于protobuf开源的gRpc包。。。
通信协议选择了thrift,基本确定了C+S的架构模式,Client负责业务端的访问请求(还是走的http,貌似业务那帮人只会写业务逻辑,完全不懂架构的东西,如果懂Client都可以干掉,自己连Server就搞定了),Server负责Client通过thrift协议发来的请求,包括查询DB和计算。
二、选择数据库
数据库貌似没得选啊,MySQL肯定是可以的,但是需要对一条完整的业务数据进行拆分到多个表中,这对高并发写可能会有影响,一次要锁住多个表的多条数据,对代码的要求肯定很高,具体没有尝试过,只是猜测。MySQL的存储方案一直都没有被考虑过。
我们选择的是mongodb,版本是3.2.11,NOSQL数据库,支持嵌套文档,所有的写操作都可以通过upsert搞定,将并发写的代码要求交给mongo去完成,这样大大降低了编码的难度,mongo也属于内存型数据库吧,数据的读写速度还算可以(但是读的速度还是达不到我们项目的要求。。)。
三、架构部署
架构图就不给了吧,通过上面的叙述,有经验的一眼就能想象出来。
我们使用了24台物理机,每台物理机一虚21个docker,1Client+10Server+10Mongo,每三个Server+Mongo作为一个服务节点,因此有24个Client,前面使用Nginx做反向代理处理业务的请求,80个服务节点用于处理数据查询和计算,最主要的是打平业务的数据,每个服务节点的三个mongo作为一个副本集(数据完全是一直的),每个client会随机选择服务节点里的某个Server来处理一次请求。
代码发布是个老大难问题!!!!
240个Server、240个mongo、24个Client,每个Server都需要通过环境变量来知道自己该连哪个mongo(docker采用的host模式,通过不同端口来控制同一台物理机的mongo)。运维的同事看到这个项目的发布需求,直接就懵逼了,因为之前从来没有这么大批量的docker发布需求。整个项目调动运维+DBA+我们自己+业务等各个部门的人员,而且我们还进行了内核参数优化,机器都重启了很多遍。
不过运维的同事的某个发布系统还是帮我们扛起了发布的重担,虽然发布的时间需要很长,但是咱要求的已经不能再多了,毕竟基础设施还是不够完善,发布的大事搞定了,也能在页面上监控发布过程中是否报错,机器各项参数指标的监控等。
四、说说坑吧
变态的项目肯定很多坑,踩了很多,都不知道从哪里说起,有些是沟通的不彻底,有的是完全没有遇到过,有的真的没法彻底解决。
坑1:
上面说过,Server是通过环境变量来确定该连哪个mongo,这不,运维在发布时,配错了,顿时就傻逼了,环境变量都人肉检测了几遍。
坑2:
业务需求沟通不彻底,业务的计算算法没说清楚,导致计算结果不对,每次请求必须实时读数据库,数据库内嵌文档结构的改变,为此,单机测试了很多遍,代码也改了很多遍,因为之前的功能测试,完全不能模拟高并发的场景,一旦高并发,很多问题就暴露出来了。每次修改后发布都是个漫长的等待过程。。。
坑3:
mongo会自动发现副本集的所有机器地址,之前我们是不知道的,在发现某台mongo被手动关闭了,居然连接的Server没有报错,卧槽,在这里也折腾了比较长的时间,mgo的文档读了一遍又一遍,最后发现确实没有问题,这样反而比较好,因为一旦改成断掉就报错,那么性能反而有下降。
坑4:
这是个巨坑,一直没有填完,而且好像也不能彻底填完,花的时间也最多,做的各种尝试也最多。
swap,swap,swap,mongo在内存的available空间还很多的情况下,居然他妈的去使用swap空间,坑啊,此种项目的场景最好全部使用内存才最好,修改了内核参数也没能彻底解决,最终还是会使用几十M的swap,而且还会增长。这个后面可能是个隐患。。。
就说这么多吧,近三个月的时间,第一次写高并发读写的项目,收获还是很多的,对代码的要求也很高,挺锻炼人的,并且全程的所有代码都是我来把控的,整个完整的架构也是我来设计的,基本上还算可以吧,虽然才刚刚接入数据还没有完全上线。
安利一个自己实现的thrift客户端连接池golang的开源代码:https://github.com/xkeyideal/ThriftPool,欢迎使用,在该项目中实践了没有任何问题,用的时候希望加上,如果从pool里拿到的client连接在某次请求出错时,希望不要再放回池子里,直接关闭该连接丢弃的代码,还是很简单的。
后记
今天终于把坑4给填了,消灭了一个巨大的定时炸弹,目前mongo的swap用量都是0。
前天发现服务器上某个程序突然崩掉,使用dmesg命令查看,发现文件系统不兼容,宿主机是xfs,docker里使用的是ext4,文件落盘肯定会出现问题。发现问题后,在保障服务不中断的前提下,花了两天时间重装全部的物理机OS,重装后已经跑了一天多,尚未发现任何程序使用swap空间的痕迹。这次可谓解决了一个巨大的bug。此前一直怀疑这批机器有问题,果不其然。
0 0
- 高并发读与高并发写的项目总结和mongodb使用中遇到的坑
- 高并发读与高并发写的项目总结和mongodb使用中遇到的坑
- CyclicBarrier 高并发的使用
- 高并发-多线程的使用
- 高并发系统的瓶颈与优化总结
- web 的高并发
- MYSQL的高并发
- 高并发的关注点
- 高并发的解决方法
- 高并发的解决方法
- 高并发的处理
- 高并发的解决方案
- 高并发的解决方案
- 高并发的优化
- 大数据和高并发的解决方案总结
- 大数据和高并发的解决方案总结
- 大数据和高并发的解决方案总结
- 一个涉及到使用webservice的,对事务和并发控制要求很高的项目
- 苹果企业开发账号申请三步走
- 关于UEdit在编辑时老是弹窗提示UEdit已启用
- Git与TortoiseGit基本操作
- 解决从SVN导入maven项目pom.xml无法下载的问题
- 【caffe源码研究】第三章:源码篇(1) :caffe整体架构
- 高并发读与高并发写的项目总结和mongodb使用中遇到的坑
- 数据结构之递归(Recursion)------分而治之
- 实现一个仿华为天气的进度圆
- Swift 之 UIProgressView
- TypeError: 'module' object is not callable 原因分析
- Manifest值冲突解决方法
- FFmpeg编译.so
- Nodejs + mongoDB 使用初体验
- ConcurrentHashMap解释