【How-to】性能与扩展性的一点思考

  • 最近在做性能测试,发现的一些问题和《Java 并发编程》里:”性能与可伸缩性“一章,所描述的场景相似,所以记录、分享出来。
问题描述
  • QA 发起一笔5并发请求,请求完之后显示超时,测试的第一天立刻检查了日志,发现日志并没有打完,并没有太在意,于是就放到那里了。之后第二天又再次检查了一遍,发现这5笔交易的日志并不是没有打印完毕,而是约在15分钟之后(开始:22:46 -- 结束:23:02)打印出来了,全部都是显示事务超时。
问题分析
  • 我检查了这个接口的超时耗时配置为(250s)。所以如果这里5笔并发请求会串行执行总耗时约为:20.8 分钟。猜测这里可能是这些接口耗时配置的太长,导致(数据库表锁)资源没有释放,请求全部阻塞等待,导致全部超时失败。
原因分析
  1. 猜想分析:统计了这5笔的请求总共的执行时间,果然是我和之前的猜想一致,5笔的交易按照串行的模式总共执行了20分钟。基本也验证了前面的猜想。

  2. 继续看打印完整的日志,发现所有的日志卡住在一个交易流水表insert 的操作。先说一点前提:目前的应用中,每次接口的请求响应前,会将所有的请求信息登记到交易流水表中,也就是说:表锁导致了应用的串行化执行。于此同时就意味着,数据库表的性能决定了应用的性能上限了。

  3. 解决方案:调低每笔交易的超时时长,避免每笔请求长时间的占用公共表锁资源,目前表锁定的原因暂时不明,还在排查中。

  4. 系统提供了交易流水表的多个分片处理,可以路由到不同分片中。从原本都要获取同一张表资源,现在可以实现多张表的资源,降低了系统资源竞争。

思考
  1. 从前面的问题我们很容易发现,系统这种热点域的设计,在并发请求的场景下,由于某些原因很容易导致系统变成串行、效率低下、甚至是不可用的情况。
HashTable 与 ConcurrentHashMap 优化
  • 其实这样的问题很容易从前人的系统设计中找到类似的问题,对比经典的 HashTableConcurrentHashMap改进,JDK 做了从单一的synchronize-排它锁改进为 多个segment的分段锁,这里将锁的粒度细粒度化,可以提供更高的并发,提供了更强大的横向扩展能力。
水平扩展

那么究竟怎样可以提供一个良好的水平扩展能力呢?《Java并发编程实战》给出以下的优化点

软件设计层面
  1. 发现在框架中隐藏的串行部分:串行的部分往往是性能瓶颈部分,它阻碍了系统的扩展性、并发度
代码层面
  1. 避免热点域(本文)
  2. 减少线程上下文的切换
  3. 减小锁的范围:同步代码块里的代码越少越好
  4. 减小锁的粒度:锁分段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值