分布式事务的性能设计
分布式事务的性能设计,主要包含吞吐量和相应延迟两方面。分布式事务更适合对吞吐量要求高,对相应延迟要求不苛刻的应用。性能设计有三个层面,分别为代码优化层、算法逻辑层以及架构设计层。
1、代码优化层
代码优化层关注代码细节优化,代码实现是否合理,是否创建了过多的对象,循环遍历是否高效,cache 使用是否高效、合理,是否重用计算结果等,具体分析如下。
循环遍历是否高效:不要在循环里调用 RPC 接口、查询分布式缓存、执行 SQL 等,要先调用批量接口组装好数据,再循环处理。
代码逻辑避免生成过多的对象或无效对象:输出 Log 时进行 Log 级别判断,避免新建无效对象。
对数据对象是否合理重用:比如通过 RPC 查到的数据能复用则必须复用。
根据数据访问特性选择合适的数据结构:如果读多写少,考虑使用 CopyOn-WriteArrayList(写时复制副本)。
是否正确初始化语句:有些全局共享的数据采用饿汉式模式,需要在用户访问之前先初始化好。
列遍历是否使用 L1 缓存:列遍历由于不满足局部性原理,需要放到 L3 cache。行遍历符合局部性原理,因此缓存命中率高,速度接近前者 2 倍。注意,CPU 缓存体系中各缓存的运行速度按从低到高的顺序排列是内存->L3->L2->L1。本质上内存使用一个大的一维数组,二维数组在内存中按行排列,先存放 a[0]行,再存放 a[1]行。
业务系统使用缓存降低响应时间、提高性能,必须要提高缓存命中率:如果对数据实时性要求很高,必须提供严格的时效性,需要慎重处理更新缓存带来的一致性问题。
时效性和缓存的冲突:比如商品服务对商品进行了缓存,由于更新缓存和更新商品不是同一个事务,若对数据实时性要求很高,如交易,则只能直接从数据库查询商品信息。
当读操作数量少于等于写操作数量的时候,没必要用缓存。
当查询条件数据量超过总数据库总量的 30%时:就不会用索引,而是直接用遍历查询。可以缩小范围,让条件覆盖的数据量少一些。也可以不查几年的,只查半个月的。
2、算法逻辑层
算法逻辑层优化主要关注算法选择是否高效、算法逻辑优化、空间时间优化任务并行处理、是否使用无锁数据结构等,具体分析如下。
用更高效的算法替换现有算法,而不改变其接口。增量式算法,复用之前的计算结果,比如一个报表服务,要从全量数据中生成。报表数据量很大,但每次的增量数据较少,则可以考虑只计算增量数据并将其与之前的计算结果合并。
并发和锁的优化:读多写少,乐观锁;读少写多,互斥锁。
系统时间是瓶颈:如缓存复用计算结果,降低时间开销,因为 CPU 时间比内存容量更重要。
数据大小是瓶颈:网络传输是瓶颈,使用系统时间换取空间,使用 HTTP 的 Gzip 压缩算法。
并行执行:如果只是逻辑调用多个 RPC 接口,而这些接口之间并没有数据依赖,则可以考虑并行调用,减少响应时间。
异步执行:分析业务中的主次流程,把次要流程拆出来异步执行或将次要流程进一步拆分成单独的模块去执行,比如消息队列,让其彻底和核心流程解耦,提高核心流程的稳定性,减少响应时间。
3、架构设计层
架构设计层的优化包括如何拆分系统,如何使各个部分系统负载更加均衡,充分发挥硬件设施的性能优势,减少系统内部开销等,具体分析如下。
系统微服务。
无状态化设计,动态水平弹性扩展。
调用链路梳理,热点数据尽量靠近用户。
分布式缓存,多级多类型缓存。
提前拒绝,保证柔性可用。
容量规划。
分布分表,读写分离,数据分片。
在基于容器云的分布式架构中,当客户端发起大流量请求时,网关、应用架构层、数据访问层可以横向扩展,但最终数据还是会落盘。因此有大流量请求时,分布式架构最终的性能瓶颈在于数据库上的热点数据。
针对数据库的热点数据,我们可以采用对数据库做分表的方法,但如果热点消息是一个数据库中的一行数据,通过数据库和缓存的分表也无法完全消除热点。
我们在进行方案设计时,最终要将吞吐量和成本结合考虑,即 ROI。实际上,即使互联网公司的电商系统做了诸多优化,在促销时也不能保证 100%请求全部成功,这不是技术的问题,而是 ROI 的考量。
版权声明: 本文为 InfoQ 作者【穿过生命散发芬芳】的原创文章。
原文链接:【http://xie.infoq.cn/article/0fe283365a592f50a1c0efd56】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论