记一次性能优化问题

记一次性能优化问题

参与架构

代码设计

我们总假设,温度是一次次上报的,且点与点之间没有先后的顺序

很容易写出以下代码

For(EachTimeUploadData)

Pipe.collect(in,out,now)

遇到的问题

我们的不仅需要记录温度,还要记录压力和流量,而这些属性是归属于管道

这个时候会遇到一个巨大的问题,数据库的DeadLock

我们默认聚合根是Pipe,那么为了防止聚合根在两个线程中出现,故而数据库中是要对这一行开启事务的,意味着根所在一行是要锁行的,而测试中如果遇上同一根管道的首尾同时上报数据,那么就会发生DeadLock,更不要提某些情况下是要沿着管道将沿途所有的管道锁定的问题。

解决死锁

  1. 我们不能允许数据丢失
  2. 不能够对架构做大改动

要解决死锁的问题,最简单的办法时,我们只用一个线程来操作,在不考虑集群的情况下,将原有方案变更为,数据上报时候顺序写入文件,然后开启一个线程从文件头开始反序列化数据然后逐一写入数据库。

集群环境

在集群环境下,依旧有锁冲突的问题,那么冲突时候策略就可以考虑以下了,我选择了,冲突之后将数据放入队列尾部,这个时候代码逻辑上是没什么问题了

性能

可是上线之后发现,其写入性能仅在15s,注意是s,是秒,才完成50条入队消息的消费

在各种断点之后,依旧发现瓶颈在数据库与应用中

  1. 每次查询流量系统地址,30~50ms
  2. 每次查询流量,30~50ms
  3. 每次查询管道链条300~500ms

在一些支管上,单次插入可以达到最大5000ms

解决

  1. 增加管道标记父节点字段,而非靠查找所有管道再通过计算得出父节点
  2. 增加本地缓存和Redis缓存切换,以其在没有redis环境下可以降低查询流量系统地址的时延
  3. 优化流量和压力的Opc客户端,减少数据传输量
  4. 将于数据库交互中的插入和更新变为Batch形式

测试结果

消费50条数据仅需要300ms左右,