美文网首页
调用链服务端优化

调用链服务端优化

作者: 千牛卫中郎将 | 来源:发表于2020-01-15 21:03 被阅读0次

一 背景

1 调用链吞吐能力低,200w/min

2 压测时,调用链kafka堆积上亿条消息,导致调用链延迟度达到小时级别

3 压测试调用链服务full gc严重,每分钟30-50次

4 随着公司业务增长,线上调用链消息在日益增长,线上调用链为每天1T左右


二 优化前调用链架构

image

优化前的项目主要具备以下功能:

  1. 暴露日志收集dubbo接口,接收调用链日志上报

  2. 消费kafka日志,多线程处理后写入到es


三 问题分析

优化前服务存在如下性能问题:

1 IO性能瓶颈

多个IO密集型功能点(kafka拉取,es写入,dubbo请求处理)耦合在一个服务中,导致IO性能成为系统性能的主要瓶颈点之一

2 Synchronized代码性能问题

代码在kafka拉取线程和写入es的线程之间交换数据的集合是传统的非线程安全的LinkedList,为了保证线程安全使用了synchronized修饰,导致方法的吞吐量上限很低

3 GC问题

在处理峰值时期,full gc次数为30-50/min,导致full gc频繁主要有如下原因:

3.1 Kafka版本过低,不能指定拉取条数,只能指定拉取大小,由于调用链日志每条日志上限为10M,所以每个partition拉取值为10M,每个topic有12个partition,导致每次会拉取上万条日志到内存中,超过jvm 大对象分配2M的阈值,直接分配到老年代,导致老年代频繁回收,出发full GC

3.2 Kafka消费服务,java对象有大量的被创建,需要被快速回收,不需要晋升等特点,jvm默认的Young,Old分配比例,及Young中的Eden Survior默认分配比例不能满足本服务对GC的要求

3.3 代码实现上,为了实现异步处理,为每个日志对象创建了一个Runnable对象,导致内存的对象翻倍,加重了GC的压力


四 解决方案

针对上面问题分析的结果,提出一下解决方案:

1 代码优化,引入disruptor代替Synchronized

2 Jvm优化,解决GC问题

代码优化

1. 为什么要使用disruptor?

 调用链服务消费kafka写入ES,天然符合生产消费者模型

 Disruptor高性能的异步处理框架,无锁(CAS)环形队列

 Disruptor的生产消费线程完全相互透明,生产消费代码解耦

 生产消费线程个数,等待策略,RingBuffer大小均由参数指定,极易扩展

2. Disruptor和ArrayBlockQueue的性能对比

主要生产消费模型:

image

各个生产消费模型下性能对比:

image

3. disruptor的性能为什么那么高?

 生产消费线程竞争基于CAS,无锁竞争

 解决CPU缓存行的伪共享问题,使部分变量的读取远高于内存读取

4. 调用链中disruptor主要参数的指定

Jvm 优化

| Tables | Are | Cool || ------------- |:-------------:| -----:|| col 3 is | right-aligned | 1600 || col 2 is | centered |12 || zebra stripes | are neat | $1 |

全部参数对比

image

差异参数对比:


五 优化效果

吞吐能力

image

服务器配置(下降一半)

image

相关文章

网友评论

      本文标题:调用链服务端优化

      本文链接:https://www.haomeiwen.com/subject/cllxzctx.html