当前位置: 移动技术网 > IT编程>数据库>其他数据库 > Kafka相关内容总结(存储和性能)

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

2019年01月04日  | 移动技术网IT编程  | 我要评论

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”)。

参考

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网