字节跳动埋点数据流建设与治理实践( 五 )


首先是Flink层面的优化 , 在埋点数据流ETL场景中 , 为了减少不必要的网络传输 , 我们的Partitioner主要采用的是RescalePartitioner , 而RescalePartitioner会使用Round-Robin的方式发送数据到下游Channel中 。 由于单机问题可能导致下游个别Task反压或者处理延迟从而引起反压 , 而实际上在这个场景里面 , 数据从上游task发送到任何一个下游的Task都是可以的 , 合理的策略应该是根据下游的Task的处理能力去发送数据 , 而不是用Round-Robin方式 。
另一方面我们注意到FlinkCredit-Basedflowcontrol反压机制中 , 可以用backlogsize去判断下游Task的处理负载 , 我们也就可以将RoundRobin的发送方式修改为根据Channel的Backlogsize信息 , 去选择负载更低的下游Channel进行发送 。 这个Feature上线后 , 队列的负载变得更加均衡 , CPU的使用率也提升了10% 。
Yarn优化
字节跳动埋点数据流建设与治理实践
文章图片
Yarn层面的优化 , 第一个是队列资源层面 , 我们使用独立的Label队列可以避免高峰期被其他低优任务影响 。
第二个是对于Yarn节点上的DataNode把带宽打满或者CPU使用比较高影响节点上埋点数据流Flink任务稳定性的情况 , 通过给DataNode进行网络限速 , CPU绑核等操作 , 避免了DataNode对Flink进程的影响 。
第三个是Yarn反调度的策略 , 目前字节跳动Flink使用的YarnGangScheduler会按条件约束选择性地分配Yarn资源 , 在任务启动时均衡的放置Container , 但是由于时间的推移 , 流量的变化等各种因素 , 队列还是会出现负载不均衡的情况 , 所以反调度策略就是为了解决这种负载不均衡而生的二次调度机制 。
反调度策略中 , Yarn会定期检查不满足原有约束的Container , 并在这些Container所在节点上筛选出需要重新调度的Container返还给FlinkJobManager , 然后Flink会重新调度这些Container , 重新调度会按照原有的约束条件尝试申请等量的可用资源 , 申请成功后再进行迁移 。
另外我们会针对一些频繁出问题的节点把它们加入调度的黑名单 , 在调度的时候避免将container调度到这些节点 。
MQ优化
Databus应用
字节跳动埋点数据流建设与治理实践
文章图片
在流量迅速增长的阶段 , 埋点数据流Flink任务一开始是通过KafkaConnecter直接写入Kafka 。 但由于任务处理的流量非常大 , Flink任务中Sink并发比较多 , 导致批量发送的效率不高 , Kafka集群写入的请求量非常大 。 并且由于每个Sink一个或多个Client , Client与Kafka之间建立的连接数也非常多 。 而Kafka由于Controller的性能瓶颈无法继续扩容 , 所以为了缓解Kafka集群的压力 , 埋点数据流的Flink任务引入了Databus组件 。 Databus是一种以Agent方式部署在各个节点上的MQ写入组件 。 DatabusAgent可以配置多个Channel , 每个Channel对应一个Kafka的Topic 。 FlinkJob每个TaskManager里面的Sink会通过UnixDomainSocket的方式将数据发送到节点上DatabusAgent的Channel里面 , 再由Databus将数据批量地发送到对应的KafkaTopic 。 由于一个节点上会有多个TaskManager , 每个TaskManager都会先把数据发送到节点上的DatabusAgent , DatabusAgent中的每个Channel实际上聚合了节点上所有TaskManager写往同一个Topic数据 , 因此批量发送的效率非常高 , 极大地降低了Kafka集群的写入请求量 , 并且与Kafka集群之间建立的连接数也更少 , 通过Agent也能方便地设置数据压缩算法 , 由于批量发送的原因压缩效率比较高 。 在我们开启了Zstd压缩后 , Kafka集群的写入带宽降低了37% , 极大地缓解了Kafka集群的压力 。
Kafka迁移BMQ