海量并发下充电业务优化实践

摘要

目前在进行充电业务开发时,面对的是充电终端上报的海量并发数据。访问缓存的TPM可达120w,访问数据库的TPM在3w左右,高峰时段面对的是近二十万终端上传的百万条并发的实时数据。在这样的场景下有些无伤大雅的小漏洞最终酿成了生产环境的大问题,正所谓千里之堤毁于蚁穴,面对这样的场景,必须深刻理解系统所使用的技术并对于常见问题有必备运维经验和分析能力。本文针对这些问题及解决过程进行分析,总结过往,以飨将来。html

海量并发时遇到的问题

本文中以问题为驱动,以故障分析为轴线。在分析问题的过程当中总结海量并发场景中对于充电业务的优化实践经验。这些问题的产生缘由大多并不复杂,可是正如谚语所说:会者不难,难者不会。若是没有合适的分析手段,每每对于故障问题一筹莫展。但愿在阅读完本文后,能够对于之后可能发生的问题有些分析手段和分析方向有些许帮助。数据库

首先来看下本文中所涉及的生产环境问题:编程

  1. 服务器CPU持续太高
  2. 访问存储的频率太高
  3. 高并发时的数据乱序
  4. 其余致使实时数据处理能力降低的问题

服务器CPU太高

服务器的CPU使用率是重要的性能指标。通常的状况下,CPU在10~20%足以应对数据处理的须要,可是在生产环境中屡次发生CPU由于某种缘由持续超过75%而且没法自行降低的状况。CPU异常高企经常会致使数据处理能力降低的问题。针对这种状况有必要进行深刻分析,查找问题缘由并采起有效措施防止相似事故的发生。缓存

首先须要排除因为上传数据的波动引发的性能变化。若是物联网设备离网又上线,云端首先须要获取一些数据进行初始化的工做,批量涌入的数据会致使服务器的性能压力问题,但一般不须要人为干预便可恢复正常。服务器

解决办法:针对这个问题的分析须要强大的监控图表的支持,使用监控图还原故障发生时的场景并针对海量数据的突变规模和业务系统的影响程序进行分析。固然如何进行数据接口的实时监控也是个很大的问题,若是这个作不到,故障现场就没法恢复,缘由分析也就无从谈起。对于海量数据的监控是足以写一篇论文的,在此再也不展开,有兴趣的读者能够看下influxDB(参考资料5)和grafana的相关资料。架构

其次须要检查的是相关的服务运行是否正常。若是云端的后台是由一系列的微服务构成,而服务之间是经过同步的RPC调用相互串联起来的,那么在涌入海量数据时因为某些服务的响应速度问题,形成实时数据处理模块的大量线程被占用,在.NET中若是有大量线程被唤醒,同时在进行业务处理的话,也是颇有可能会形成CPU的升高问题。并发

解决办法:针对这个问题的分析办法是抓取程序的dump,最好能间隔1~2分钟连续抓取多个dump,并经过dump分析线程池中的线程堆栈,并经过堆栈查找致使线程积压的缘由(参考资料2),是调用别的服务?仍是查询数据库?等等。找到线程大量积压的缘由,基本上就成功了大半了。app

最后的办法是检查性能计数器。性能计数器经常被人忽略,可是其在分析CPU问题时经常能起到意想不到的巨大帮助。运维

案例一:某次实时数据处理程序CPU预警,排除掉前文所述的可能缘由后,针对.NET CLR计数器进行分析,发如今CPU高企的阶段# of Exceps Thrown/Sec这个指标也相应的升高,而该指标表明的是某个时刻的程序抛出异常的统计。后来经过统计日志,也印证了前文所述,确实在那个时刻的异常很是多。微服务

CPU和该指标的关系:

CPU(%) 指标值(%)
45 5
16 5
73 11
82 11
66 7
32 5

MSDN的解释以下(参考资料3):

显示每秒引起的异常的数目。它包括.NET异常和转换成.NET 异常的非托管异常。 例如,从非托管代码返回的HRESULT转换为托管代码中的异常。
此计数器包括已处理和未经处理的异常。此计数器不是一段时间内的平均值;它显示在最后两个样本(以取样间隔持续时间来划分)中观察到的值之间的差别。

案例二:某次实时数据处理程序CPU预警,排除掉前文的可能缘由并排除异常相关指标后,在针对.NET CLR计数器的分析过程当中发现,在CPU高企的阶段% Time in GC这个指标也比较高,该指标表明GC时间在整个CPU时间中的占比。在发生预警的时段内,该指标的值基本上位于30%~60%的区间内,而非预警时段该指标的值在10%左右。

MSDN的解释以下(参考资料3):

显示自上次垃圾回收周期后执行垃圾回收所用运行时间的百分比。此计数器一般指示垃圾回收器表明该应用程序为收集和压缩内存而执行的工做。只在每次垃圾回收结束时更新此计数器。此计数器不是一个平均值;它的值反映了最近观察所得值。

针对GC形成的性能问题,首先须要经过dump分析是不是因为程序自己致使了GC过于频繁,好比不合适的字符串操做,频繁分配大对象等等。

若是从dump中没法得知GC频繁的缘由,能够尝试使用Server GC模式(参考资料4)。经过压力测试发现,在使用Server GC先后,程序的处理能力相差超过一倍,例如,假设原来的时候单节点TPM200会致使CPU高企,那么在使用Server GC后,TPM达到450时CPU也不到40%,相对于之前的表现有很大改善。所以使用Server GC能够有效缓解GC过于频繁致使的性能问题,显著提高程序的数据处理能力。

访问存储媒介的频率太高

通过统计,在充电高峰期,处理实时状态的程序访问缓存的TPM能够达到120w,访问数据库的TPM在3w左右。这个数据比其余全部模块的总和还要高。特别是访问缓存的频率很是高,致使对于缓存性能的依赖很是强,在缓存性能不稳定时很是容易影响到实时数据处理模块的性能表现。

形成该问题的缘由是多方面的,总结起来有如下几个方面的缘由:

一、程序架构缘由。由于终端数据上传至云端后,是随机分配到不一样的服务器上的程序进行处理,所以在处理数据以前必须进行上下文的恢复工做,致使访问存储的频率太高。

二、物联网通信协议缘由。受到通信协议的限制,终端只能上传当前时刻状态的数据,而没有采用重要状态转化的事件通知机制,没法表达数据自己所表明的业务含义。致使云端的程序必须经过查询终端以前的相关数据获知数据的准确意图。

三、业务逻辑的须要。充电终端上传的数据是分类按照不一样频率上传的,在处理这些实时数据的过程当中,常常涉及到状态转化相关的逻辑处理。若是须要判断状态转化则必须知道是由什么状态转换到当前状态的,因此须要常常性的从缓存或数据库中查询相关数据。

针对以上各类缘由,能够采起以下办法:

一、优化架构设计。经过适当的方法,保证终端数据能稳定传输到某个运算节点。能够有效利用服务器自己的资源缓存终端的相关数据,避免每次都须要恢复上下文。

二、优化物联网协议。减小依赖实时数据的状态转化判断逻辑,而采用事件通知机制确保重点状态的处理过程,对于实时数据则更多的用于状态监控而不是业务逻辑判断。

海量并发时的数据乱序

终端上传数据是随机分配到不一样的服务器由不一样的线程进行处理,所以不能保证数据的处理顺序跟数据的上传顺序保持一致。所以就致使了实时数据的乱序问题,便可能新的数据被老数据覆盖的问题。目前在生产环境中使用的实时数据处理程序是运行在Thrift上的,当其比较繁忙,特别是CPU占用较高时,常常出现数据延迟和数据乱序的问题,并所以致使了严重的程序逻辑错误。

对于该问题有两个备选方案:

方案一:经过严格保证数据处理的串行化来避免该问题的发生。可是这个办法有个最大的问题是致使了程序性能的降低,原本能够并行处理的业务被迫串行化实际上对于性能影响比较大。

方案二:优化通信协议,在物联网传输的报文都应该增长时间戳,经过检查时间戳判断当前数据是否有效并采起相关逻辑。该方法的最大好处是不影响业务数据的处理性能。固然该方案也有坏处,那就是在确保程序并发时还须要保证逻辑的正确性,所以须要在并发编程方面投入更多的精力。

实时数据处理能力降低

尽管CPU繁忙会致使数据处理能力降低,可是本章节所述内容与此无关。有时候虽然CPU占用率并不高,内存也很充足,可是数据处理能力莫名其妙的降低,并致使了许多业务方面的问题。

该问题的缘由比较隐蔽,经过对于业务模块的分析,发现该问题与对外推送业务有关。

正常的流程推送是:

终端数据变化->实时数据处理模块->互联互通模块->第三方

而问题的出现与第三方服务接口响应较慢有关,其传导过程以下:

第三方接口响应慢
    ->互联互通大量线程等待HTTP返回结果
    ->互联互通模块线程池无可用线程
    ->实时数据处理模块的线程同步等待互联互通模块的返回结果
    ->实时数据处理模块线程池也逐步用光
    ->数据处理能力降低

当实时数据处理模块断定状态状态变化时会经过互联互通模块进行对外推送,部分外部接口没法承接巨大的推送量而出现了访问超时等问题。因为互联互通模块设计对外推送时设置的超时时间是60s,致使大量的线程在等待外部接口的返回结果。而线程池的数量时有限制的,当互联互通模块的线程池用光后,没法再处理外部的请求,因此请求都积压在互联互通模块的数据队列中得不处处理,而因为实时数据处理模块当时是直接同步调用互联互通模块进行推送,致使其自己的大量线程也在等待互联互通接口的返回结果,进而形成由外而内的传导效应。当实时数据处理模块线程池可用线程用完,也就无法处理新来的实时数据并致使了严重的性能问题。

对于该问题的解决办法也至关简单,经过dump彻底能够看到线程的堆栈,经过堆栈肯定了问题缘由后,推送方和接收方使用消息队列相互解耦,最终避免了此类事故的再次发生。

总结

  • # of Exceps Thrown / Sec指标较高(>5)时,很容易致使CPU出现性能问题;
  • 在比较繁忙的业务中使用抛出异常的方式要慎重;
  • % Time in GC指标持续较高(>10)时,很容易致使CPU出现性能问题;
  • 使用Server GC有助于缓解GC致使的性能问题;
  • 在处理实时数据的场景中,数据必须包含时间戳;
  • 在处理实时数据的场景中,频繁恢复数据的上下文会致使较高的压力;
  • 在处理实时数据的场景中,不推荐使用无状态的处理机制;
  • 数据推送的两端有最好能经过MQ进行解耦,减小相互影响;

参考资料

  1. Lock and Thread Performance Counters
  2. 网站High CPU分析
  3. Performance Counters in the .NET Framework
  4. <gcServer> Element
  5. 互联网级监控系统必备-时序数据库之Influxdb技术
  6. 互联网级监控系统必备-时序数据库之Influxdb集群及踩过的坑
相关文章
相关标签/搜索