项目TPS(系统吞吐量)达到瓶颈时
TPS(系统吞吐量)达到瓶颈
前言
逛知乎的时候,刷到了一篇文章:物联网Java项目, 2万多TPS如何处理?
因为目前接触的项目正是物联网Java项目,所以对这个提问中的回答有一些内行人的理解和赞同;
于是针对这个问题,当项目中TPS量遇到瓶颈时,有什么公式化的应对手段;
问题
复刻简化一下提到的知乎提问:
项目原本为一个用户每30s发送一条状态信息给系统,系统进行数据落库;现如今需改成每1s发送一条状态信息给系统
于是随着用户量的增大,系统将面临如下问题:
- 系统吞吐量不够,消费上报的信息跟不上生产速度
- 服务器带宽压力,假设每个用户上报一条数据为10KB,有1W个用户,那么每秒会出现近100Mb带宽耗损。
- 接入层达到瓶颈时,延时,重试等衍生问题
- ...
方案
回到问题,首先要知道2万的TPS在物联网处理方案中是一个非常常见且已经有了最佳实例方案的场景,因此在如今的角度上看有非常非常多的方式去解决提高系统吞吐量的手段
首先是回答这个提问的第一反应方案:
框架与工具:Redis,Mysql,MongoDB,InfluxDB,Nginx,Kafka
Redis: 存储基本信息的缓存,以及存储上一次上报数据的hash以作对比是否需要更新
Mysql:记录基本信息内容
MongoDB: 构建实时状态模型
influxDB: 存储时序数据,比如每秒帧数据的实际落库点
Nginx: 负载均衡
Kafka: 时序数据业务分流
具体链路如下:
- 每条数据最先经过边缘计算,根据缓存内容以及具体模型判断是否捕捉数据
- 基本信息更新直接落库,Mysql+Redis,缓存数据一致性策略:延时双删
- 属性状态更新直接落库,MongoDB,构建模型
- 将时序数据推入Kafka中,另一系统消费 = 每帧数据记录
- ...
大致如上,其中包括对每秒数据的处理与流向落库的方式,省略了后续的查询,数据同步...,因为这涉及到的是另一个问题了。
同时还可以进一步优化:
- 使用单机应用纯内存处理缓存,适用小范围部署时的微集群方案
- 程序中更多的使用异步式的响应式编程,提高主线程流动率
- 堆服务器,软的不行来点硬的
- ...
以上是看到提问后的第一反应,很多地方都象征性的跳过,在看了各位大牛的回答后总结了如下的新方案
框架不变,目前感觉大部分物联网项目都是 关系型数据库
+ 时序数据库
+ 大数据
+ 非关系型数据库
的组合
因此主要总结的是思路与求同存异;
思路一: 设备(用户) 自行处理上报频率
这一点在不同的人的角度上有不同的见解,将这个思路转化为接收度最高的WEB开发,可以解释为:用户在个人资料表单上修改后点击保存,游览器判断哪些信息发生了变动,将变动后的结果发给后台;
从后台角度上看由于游览器将不需要更新的信息丢给了自己,只需要对传过来的进度进行判断处理及更新即可;
这样后台节省了很大一笔功夫,但是在前端的角度上看自己的性能被消耗...
所以由设备自行判断上报与否,完全处决与项目组中领导人的决策,各有各的好处;
从设备方处理,节省服务器资源,增加设备端工作量;
从后台方处理,便于后续调试,数据收集等;
思路二: 以批次上报
在允许接受N秒,比如3秒延时显示的情况下完全可采用;
由设备端创建一个收集桶,将实际每1秒上报的一条条消息,转变为每3秒一次的批次消息;
不过也存在明显的缺点:并发时,服务器处理数据KB量增大,且接入层所接收的报文长度变大;
因此采用本方案,需要考虑到Emqx的转发压力和报文截断丢失的可能;
思路三: 更多的拆分,从水平,从垂直
当系统吞吐量达到瓶颈时,最优的考虑因该是想办法将各种请求进行不同方式的分流;
首先是接入层的数据采集,这里除了使用Kafka进行消息的发布外,确实没想到也没接触过其余的天然存在分布式节点处理支持高吞吐量的消息;
这样一个Kafka吃下2Wtps
小case了,一个不够就水平上一个集群;
然后是业务层的消息处理和分发,这里的关键在于不同业务的时效性和优先级;
比方说需要实时的看到数据变化,那么就先将数据更新的业务放到主线程上,而该数据帧的采集则通过Kafka异步进行;
最后是数据库的入库,也是tps
达到瓶颈时的最大问题:
因为tps达到瓶颈,几乎可以说明数据库已经累的停不下来了;
推荐采用多数据库+按hash+月分片+数据冷存储:
多数据库:
时序数据库 + 关系型数据库 + 非关系型数据库
时序存变化的采集值,关系数据库存设备快照模型,非关系型数据库多为文档模型比如Mongodb;
按hash+月分片:
一个传感器设备的数据增长量是无法估值的,所以仅按时间或hash等规律随机数分表是无法满足庞大设备时的并发入库的(表数据量过大)
因此得采用唯一标识hash计算+月/日的分片方式分表
数据冷存储:
将过期 数据直接文件化上传,减少数据量;
这样虽无法直接提高落库的性能,但都是从多维度的去减少一张表的数据量,使db速度加快的方法。
总结
仔细看了这个提问下的所有回答和其评论,发现大伙的判断是如此的相近。
方案和技术选型上几乎一样,都认为难度在于数据落库以及接入层上。
不过仔细一想,在系统吞吐量达到瓶颈时,面临的一定不止这些问题,因为即使可以通过加机器,优化技术,也需要面对:
- 宽带费用的几何上涨
- 数据库落库与查询的压力提升
- 不加成本很容易达到下一个瓶颈
- .....
所以当系统吞吐量达到瓶颈时,基于成本和产品的考虑,感觉还是应该遵循三角形准则:成本-性能-时效。可以接收延时,另外两个就可低,反之则高