Producer 性能调优公式及验证

来源:互联网 发布:减肥软件有哪些 编辑:程序博客网 时间:2024/06/05 04:01

背景


Kafka的Producer有很多的参数可以影响到Producer的写性能. 大多数人应该会对这些参数比较困惑, 往往会混淆名称相似的参数; 即使能够区分每个参数的意义,也很难知道如何通过组合这些参数达到Producer的比较高的性能.

本人通过研究源码加上实践和思考,总结出了一个计算Producer的吞吐的公式, 这个公式包含Producer端重要的调优的参数,可以帮助大家直观的调优自己的Producer的性能, 而不用毫无头绪和方向的盲目尝试各种参数的组合.

环境


硬件

CPU: 32cors, Intel(R) Xeon(R) CPU E5-2640 v2 @ 2.00GHz

Memory: 128GB

Network: 1Gb

OS: Linux version 3.10.0-514.el7.x86_64


Topic

Topic Name
Broker Count
Partition Count per Broker
Replicas
test_topic1161test_single_partition313test_performance413


工具

使用官方提供的性能测试工具: kafka-producer-perf-test.sh. 


调优参数


Producer的参数

batch.size

send.buffer.bytes

receive.buffer.bytes //Can simply equals the send.buffer.bytes;

acks

linger.ms

max.in.flight.requests.per.connection

buffer.memory

工具模拟的参数

record-size

num-records

throughput

Data Center


为了模拟数据延迟带来的性能问题以及调优方案, 这里引入两个数据中心进行数据传输的场景. 两个数据中心之间的延迟可以通过ping得到一个经验值, 实际的延迟估算后面会详细描述.

!355 $ ping nycgmq01PING nycgmq01.fwmrm.net (10.0.13.205) 56(84) bytes of data.64 bytes from 10.0.13.205: icmp_seq=1 ttl=59 time=71.9 ms64 bytes from 10.0.13.205: icmp_seq=2 ttl=59 time=71.9 ms64 bytes from 10.0.13.205: icmp_seq=3 ttl=59 time=72.0 ms64 bytes from 10.0.13.205: icmp_seq=4 ttl=59 time=71.8 ms64 bytes from 10.0.13.205: icmp_seq=5 ttl=59 time=71.8 ms

公式


我先列出Producer的性能计算公式, 然后对这个公式做详细的解释:
if (record-size > batch.size){    packet_size = record-size; //Can not append more records into one batch;}else{    packet_size = batch.size / record-size * record-size; //make batch full of records;} request_size = packet_size * partitions_per_broker; speed = min(max.in.flight.requests.per.connection * request_size, send.buffer.size) * 1/RTT;

公式中出现的变量, 基本都被上面列出的参数包含.
公式中, 直接包含的参数有:  batch.size, record-size, send.buffer.bytes(receive.buffer.bytes), max.in.flight.requests.per.connection, record-size.
未在公式中出现的参数:
  1 acks: 这个是和公式中的RTT相关的, 后面会详细介绍;
  2 buffer.memory这个参数想对于其他参数来说,并不是很影响Producer的性能, 除非你的Producer和Brokers同在一个网络质量非常高, 延迟率非常低的网络中. 所以在本篇文章的实验测试中, 我把这个值固定在200MB, 以防止过小的值对公式的验证带来扰动.
  3 linger.ms这个参数取决于你上层应用的调用Producer的速度; 在本篇文章中, 我们通常会设置record-size大于batch-size, 这样linger.ms就没有实际用处了, 因为无法积攒多条record到一个batch中. 所以我们把它设置为0.
  4 "num-records" and "throughput" 这连个参数是用于模拟消息的发送速度和发送的总条数. 这两个参数不会影响Producer的性能.


如何计算RTT

    上图中出现了RTT这个东西. The round-trip time (RTT) is the length of time it takes for a signal to be sent plus the length of time it takes for an acknowledgment of that signal to be received. This time delay therefore consists of the propagation times between the two points of a signal.

    那如何计算RTT呢? 如果我们能保证每个Producer发送给每个Broker的Request请求都只包含一条Record, 并且我们能够知道每秒发送了多少条Record, 那么我们就能够知道每秒发送的Reques数量, 这样我们就能计算出发送一个Request的往返时间, 这样就得到了RTT.
  
    为了达到每个Request只包含一条Record这个条件, 根据上图描述的数据发送原理, 我们设计各个参数的关系如下:
      1 让record_size >= batch.size; //确保一个batch中只有一条Record;
      2 创建一个topic, 这个topic只有一个partition; //一个Request请求只包含一个batch;
      3 max.in.flight.requests.per.connection=1; 确保向一个broker一次只发送一个Request请求;

    RTT除了与Producer和Broker的传输延迟有关, 还与Broker收到Request后的处理时间有关. 所以我列出了acks等于-1,0,1三种值下, RTT的测试值:
acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokersDCs

0

11.33

1188

1

10000

1

1inter

0

10.95

133

1

90000

1

1inter012.9015190000011inter

1

0.13

13.8

1

10000

1

1inter

1

1.01

13.5

1

90000

1

1inter110.0512190000011inter

-1

0.13

13.6

1

10000

1

1inter

-1

1.13

13.2

1

90000

1

1inter-1 9.07.26190000011inter


不同的record_size下Record/s的变化



不同的record_size下Bytes/s的变化

可以看到, 在acks=1和acks=-1的条件下, 每秒发送的records数量基本在9-13条之间, 无论record_size怎么变. 排除record_size在900KB下, 发送速度为9条/S, 其他基本在13条左右(当record_size较大接近socket的发送接收缓冲区大小时, 会受数据拷贝及缓冲区满等影响, 传输速度降低, RTT升高). 可以看到RTT是比较稳定的, 基本在1s / 13 = 70ms左右.

为什么acks=0的情况下, 每秒的record的传输速度可以达到1000+呢? 原来, acks=0的情况下, Producer将数据拷贝到socket的缓冲区后即返回, 而不会等到真正Broker的response. 所以不经过网络传输,就会非常快, 所以这不是真正的RTT. 而当record_size达到900KB接近socket的缓冲区大小(这里设置的为1MB), 拷贝就会等待上一次的数据得到Broker的response确认后才会清空容纳下一次的拷贝, 这时即使acks=0, 也相当于要等待网络RTT的时间才能继续, 所以退化为等待RTT的传输速度.

高延迟网络下最重要的参数: send.buffer.bytes(receive.buffer.bytes)


在我看来, 这些性能参数中, 作重要的参数其实是这个send.buffer.bytes.  而这个参数往往会被大家忽略, 甚至Kafka的官方文档中都只把这个参数的重要度标记为medium. 如果你的应用在使用这个参数的默认值的情况下, 也能达到一个好的性能, 那么我打赌你的网络状况一定非常好. 这个参数决定了TCP的缓冲区的大小, 也就是决定了滑动窗口的大小. 下面让我用一些证据来展现给你,这个参数到底有多关键.

Producr和Broker在同一个DC内------低延迟

首先, 我想展示低延迟的网络状况下, 调大send.buffer.bytes的结果. 实验环境是: Producer和Broker在同一个DC中,这样延迟很低.
acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions

brokerssend.buffer.bytes-143 75160000011102400-14478160000011502400-144771600000111024000-144234120000011102400-145237120000011502400-1452401200000111024000-116.77175811000011102400-117.68 185411000011502400-116.631743110000111024000094493120000011102400可以看到, 在低延迟的网络环境下, 调大send.buffer.bytes不会明显的改善传输速度. 这是因为, RTT极低, 一次传输1MB和100次传输每次传输10KB的速度没有很大的区别.
一个比较有趣的事情是, 你可以看到, 网络速度本可以达到100MB/s, 但是ack=-1的情况下, 传输速度只能到45MB/S, 没有达到最大带宽. 一个解释是, broker保存record所消耗的时间的影响相对极低的RTT来说,不能忽略不计了, 因为RTT实在太低了. 这应该也是ack=-1, 并且一次发送一个reques的条件下, 能达到的最高速度.你可以看到, 当ack=0时, 网络传输速度可以达到94MB, 基本能够接近最高带宽了.

Producr和Broker在不同DC------高延迟

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions ber broker

brokers
send.buffer.bytes
-10.1313.711000011102400-10.13 13.711000011502400-10.13 13.6110000111024000-12.4012.6120000011102400-12.39 12.6120000011502400-12.4012.61200000111024000-12.41 4.3160000011102400-16.1310.7160000011502400-16.1610.81600000111024000

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
-12.4012.61200000161102400-1 6.1032.01200000161502400-16.2632.812000001611024000-12.53 4.410060000011102400-111.2120.110060000011502400-112.1221.3100600000111024000
看到了么? 用record_size=600KB, partitions per broker=1来举例: 在send.buffer.bytes为100KB的时候, 如果一次只发一个request, 那么传输速度只有2.41MB/s. 但是如果增加send.buffer.bytes 10倍到1MB, 那么传输速度可以提高3倍,
到6.16MB/S. 为什么没有相应提高10倍? 可以看下上面的公式: 当record_size*max.in.flight.requests.per.connection的积小于send.buffer.bytes时, 一次发送的数据大小由
record_size*max.in.flight.requests.per.connection决定; 再乘以1/RTT=10.8, 就是每秒的带宽流量. 上面第二张表是一次发送多个request或者多个partition的数据下, 增大send.buffer.bytes能够带来的传输速度的提升.
可以看到, 传输速度最高能够达到12.12MB/s, 这是能够达到的最高速度了. 如何计算最高速度? 根据公式:send.buffer.bytes * 1 / RTT = 13MB/S.

Performance BenchMark

max.in.flight.requests.per.connection

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
DC
-10.1313.7110000111024000inter-11371.201010000111024000inter-110189.7110010000111024000inter-11019.89.73100010000111024000inter

record_size

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
DC
-10.1313.7110000111024000inter-10.6413.4150000111024000inter-11.2413.01100000111024000inter-12.3912.61200000111024000inter-18.349.71900000111024000inter

partitions

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
DC
-11.2413.01100000111024000inter-16.1364.311000001611024000inter

brokers

  
  
brokers
send.buffer.bytes
DC
acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
DC
-11.2413.01100000111024000inter-14.8052.11100000141024000inter

能够达到的最高速度测试

acks

MB/s

Records/s

max.in.flight.requests.per.connection

record size

partitions per broker

brokers
send.buffer.bytes
DC
-113.00129.610000100000111024000inter-148.5550910000100000141024000inter113.14 13710000100000111024000inter144.6246710000100000141024000inter013.2813710000100000111024000inter049.5351910000100000141024000inter-187.4581210000100000115024000inter183.35 76910000100000115024000inter089.7981510000100000115024000inter


原创粉丝点击