Kafka相关内容总结(存储和性能)

Stella981
• 阅读 530

Kafka消息的存储

  • Kafka的设计基于一种非常简单的指导思想:不是要在内存中保存尽可能多的数据,在需要时将这些数据刷新(flush)到文件系统,而是要做完全相反的事情。所有数据都要立即写入文件系统中持久化的日志中,但不进行刷新数据的任何调用。实际中这样做意味着,数据被传输到OS内核的页面缓存中了,OS随后会将这些数据刷新到磁盘。

  • 大家普遍为“磁盘很慢”,因而人们都对持久化(persistent structure)结构能够提供说得过去的性能抱有怀疑态度。实际上,同人们的期望值相比,磁盘可以说是既很慢又很快,这取决决于磁盘的使用方式。设计的很好的磁盘结构可以和网络一样快。在一个由6个7200rpm的SATA硬盘组成的RAID-5磁盘阵列上,线性写入(linear write)的速度大约是600MB/秒,但随机写入却只有100k/秒,其中的差距接近6000倍。

  • Kafka并没有在内存中创建缓冲区,然后再向磁盘write的方法,而是直接使用了PageCache。

  • OS在文件系统的读写上已经做了太多的优化,PageCache就是其中最重要的一种方法.

  • 直接使用PageCache有如下几个好处:

    • 减少内存开销: Java对象的内存开销(overhead)非常大,往往是对象中存储的数据所占内存的两倍以上。
    • 避免GC问题:Java中的内存垃圾回收会随着堆内数据不断增长而变得越来越不明确,回收所花费的代价也会越来越大。
    • 简单可靠:OS会调用所有的空闲内存作为PageCache,并在其上做了大量的优化:预读,后写,flush管理等,这些都不用应用层操心,而是由OS自动完成。
  • 由于这些因素,使用文件系统并依赖于PageCache页面缓存要优于自己在内存中维护一个缓存或者什么其他别的结构。

读写空中接力

  • 当写操作发生时,它只是将数据写入Page Cache中,并将该页置上dirty标志。

  • 当读操作发生时,它会首先在Page Cache中查找内容,如果有就直接返回了,没有的话就会从磁盘读取文件再写回Page Cache。

  • 可见,只要生产者与消费者的速度相差不大,消费者会直接读取之前生产者写入Page Cache的数据,大家在内存里完成接力,根本没有磁盘访问。而比起在内存中维护一份消息数据的传统做法,这既不会重复浪费一倍的内存,Page Cache又不需要GC(可以放心使用大把内存了),而且即使Kafka重启了,Page Cache还依然在

相关内核参数

  • 不能及时flush的话,OS crash(不是应用crash) 可能引起数据丢失;

  • 内核线程pdflush负责将有dirty标记的页面,发送给IO调度层。内核会为每个磁盘起一条pdflush线程,每5秒(/proc/sys/vm/dirty_writeback_centisecs)唤醒一次,根据下面三个参数来决定行为:

    • /proc/sys/vm/dirty_expire_centiseconds:如果page dirty的时间超过了30秒(单位是10ms),就会被刷到磁盘,所以crash时最多丢30秒左右的数据。

    • /proc/sys/vm/dirty_background_ratio:如果dirty page的总大小已经超过了10%的可用内存(cat /proc/meminfo里 MemFree+ Cached - Mapped),则会在后台启动pdflush 线程写盘,但不影响当前的write(2)操作。增减这个值是最主要的flush策略里调优手段。

    • /proc/sys/vm/dirty_ratio:如果wrte(2)的速度太快,比pdflush还快,dirty page 迅速涨到 10%的总内存(cat /proc/meminfo里的MemTotal),则此时所有应用的写操作都会被block,各自在自己的时间片里去执行flush,因为操作系统认为现在已经来不及写盘了,如果crash会丢太多数据,要让大家都冷静点。这个代价有点大,要尽量避免。在Redis2.8以前,Rewrite AOF就经常导致这个大面积阻塞,现在已经改为Redis每32Mb先主动flush()一下了。

原理分析结论

  • Kafka使用文件系统来交换消息,性能是否比使用内存来交换消息的系统要低很多?

    • 在Apache Kafka里,消息的读写都发生在内存中(Pagecache),真正写盘的就是那条pdflush内核线程,根本不在Kafka的主流程中,读操作大多数会命中Pagecache,同时由于预读机制存在,所以性能非常好,从原理上有保证的。
  • 每个分区一个文件,那么多个分区会有多个文件同时读写,是否会极大的降低性能?

    • 首先,由于Kafka读写流程是发生在PageCache中,后台的flush不在主流程中触发,所以正常情况下理论上是没有影响的,除非PageCache占用内存过大,或是释放导致读写消耗Kafka进程的CPU时间
    • 再次,文件都是顺序读写,OS层面有预读和后写机制,即使一台服务器上有多个Partition文件,经过合并和排序后都能获得很好的性能,不会出现文件多了变成随机读写的情况,但是当达到相当多的数量之后,也会存在一定的影响。
    • 当PageCache过大,大量触发磁盘I/O的时候,超过了/proc/sys/vm/dirty_ratio,Flush会占用各个应用自己的CPU时间,会对主流程产生影响,让主流程变慢。
  • 使用SSD盘并不能显著地改善 Kafka 的性能,主要有两个原因:

    • Kafka写磁盘是异步的,不是同步的。就是说,除了启动、停止之外,Kafka的任何操作都不会去等待磁盘同步(sync)完成;而磁盘同步(syncs)总是在后台完成的。这就是为什么Kafka消息至少复制到三个副本是至关重要的,因为一旦单个副本崩溃,这个副本就会丢失数据无法同步写到磁盘。
    • 每一个Kafka Partition被存储为一个串行的WAL(Write Ahead Log)日志文件。因此,除了极少数的数据查询,Kafka中的磁盘读写都是串行的。现代的操作系统已经对串行读写做了大量的优化工作。
  • 如何对Kafka Broker上持久化的数据进行加密

    • 目前,Kafka不提供任何机制对Broker上持久化的数据进行加密。用户可以自己对写入到Kafka的数据进行加密,即是,生产者(Producers)在写Kafka之前加密数据,消费者(Consumers)能解密收到的消息。这就要求生产者(Producers)把加密协议(protocols)和密钥(keys)分享给消费者(Consumers)。
    • 另外一种选择,就是使用软件提供的文件系统级别的加密,例如Cloudera Navigator Encrypt。Cloudera Navigator Encrypt是Cloudera企业版(Cloudera Enterprise)的一部分,在应用程序和文件系统之间提供了一个透明的加密层。
  • Kafka是否支持跨数据中心的可用性

    • Kafka跨数据中心可用性的推荐解决方案是使用MirrorMaker。在你的每一个数据中心都搭建一个Kafka集群,在Kafka集群之间使用MirrorMaker来完成近实时的数据复制。
    • 使用MirrorMaker的架构模式是为每一个”逻辑”的topic在每一个数据中心创建一个topic:例如,在逻辑上你有一个”clicks”的topic,那么你实际上有”DC1.clicks”和“DC2.clicks”两个topic(DC1和DC2指得是你的数据中心)。DC1向DC1.clicks中写数据,DC2向DC2.clicks中写数据。MirrorMaker将复制所有的DC1 topics到DC2,并且复制所有的DC2 topics到DC1。现在每个DC上的应用程序都能够访问写入到两个DC的事件。这个应用程序能够合并信息和处理相应的冲突。
    • 另一种更复杂的模式是在每一个DC都搭建本地和聚合Kafka集群。这个模式已经被Linkedin使用,Linkedin Kafka运维团队已经在 这篇Blog 中有详细的描述(参见“Tiers and Aggregation”)。

参考

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Django之Django模板
1、问:html页面从数据库中读出DateTimeField字段时,显示的时间格式和数据库中存放的格式不一致,比如数据库字段内容为2012082616:00:00,但是页面显示的却是Aug.26,2012,4p.m.答:为了页面和数据库中显示一致,需要在页面格式化时间,需要添加<td{{dayrecord.p\_time|date:
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Kafka连接器深度解读之错误处理和死信队列
Kafka连接器是Kafka的一部分,是在Kafka和其它技术之间构建流式管道的一个强有力的框架。它可用于将数据从多个地方(包括数据库、消息队列和文本文件)流式注入到Kafka,以及从Kafka将数据流式传输到目标端(如文档存储、NoSQL、数据库、对象存储等)中。现实世界并不完美,出错是难免的,因此在出错时Kafka的管道能尽可能优雅地处理是最好的。一
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这