Kafka必知必会

什么是Kafka

Kafka是一个分布式流处理平台。一个流平台有这三个关键功能:
1. 发布和订阅记录流,类似一个消息队列或者企业消息系统。
2. 能够以较强的容错性存储流记录。
3. 能够及时处理流记录。

应用场景

Kafka通常用于两类广泛的应用:
1. 构建实时流数据管道,让系统之间或应用之间可靠的获取数据
2. 构建能够改变或响应流数据的实时流应用

实现原理

为了理解Kafka如何实现这些,我们会从下往上研究Kafka的功能。
1. Kafka作为一个集群运行在一个或者多个可跨数据中心的服务器上。
2. Kafka集群以分类的形式存储流记录,称之为主题(topics)。
3. 每一条记录包含键(key),值(value),时间戳(timestamp)。

在Kafka中,客户端和服务器之间通信通过简单,高性能,语言无关的TCP协议实现。该协议自带版本标识,默认向后兼容旧版本协议。官方提供Java的客户端,其他语言由第三方提供。

相关名词

生产者(Producers)

所谓生产者,就是产生消息的服务,它们可以选择发布消息到指定主题。生产者负责选择指定的记录发布到指定主题的指定分区,负载均衡算法有轮询以及根据记录关键字分区。

消费者(Consumers)

所谓的消费者是指,消费kafka消息的服务,通常是各种客户端。

每个消费者使用消费组标识自己(consumer group name)。当消费组里只有一个实例时,当前的消费者消费全部分区的消息。Kafka是通过分区来实现扩展性和容错性。

假设Kafka集群有2个Server(Server1 Server2),4个分区(P0 P1 P2 P3),2个消费组(Consumer Group A Consumer Group B),每个消费组分别有2个和4个消费者(C1 — C6)。见下图:

那么整体消费可能情况如下表:

消费者/分区 Server1(P0) Server1(P3) Server2(P1) Server2(P2)
C1
C2
C3
C4
C5
C6

Kafka实现消费的方式是尽可能的平均分配相关分区,每个分区都只拥有一个消费者。消费者的添加和删除会动态的改变分区的分配,分区会动态分配到其他消费者。

Kafka只保证同一个分区的记录顺序,不同分区的顺序无法保证。通过分区排序和按键(key)分区满足大多数应用的需求。如果需要全局的顺序呢,只能使用一个分区的主题,这个分区只有一个消费者。这意味这同一个分区,如果有2个消费者消费的话,另外一个消费者会”很闲”,也就是无法处理消息。

主题和日志(Topics and Logs)

所谓的主题是,发布记录的类别或者订阅名称。主题一般是多订阅者的,这意味着可以有0个,1个,多个订阅者等订阅写入的数据。

Kafka对每一个主题维护一个分区日志,每个分区都是一个有序的,以不可变的记录,也就是不断追加到结构化的提交日志。分区中每个记录都一个连续的id,称为偏移(offset),唯一标识分区内的记录。这个偏移由消费者控制,所以消费者可以以任何顺序消费消息。

Kafka集群使用可配置的保留时间,来持久化存储全部已发布的消息,无论是否被客户端消费。

分区日志的作用是,可以减少日志的大小,单个服务器可以存储下,更多的作用是方便进行扩展。

分布式(Distribution)

Kafka通过zookeeper实现分区容错性,只需要n/2+1个节点存活,就可以保证较好的容错性。每个分区都在可配置的服务器上进行复制,以便实现容错。

GEO复制(Geo-Replication)

Kafka采用MirrorMaker实现集群的地理复制功能,可以跨数据中心或者多个云。

多租户(Multi-tenancy)

Kafka也支持多租户的配置方案。

保证(Guarantees)

高级别的Kafka提供以下保证:
1. 生产者发送到特定主题分区的消息将按照其发送的顺序追加。也就是说,哪一条记录先发送就具有更低的偏移且在日志中出现得更早。
2. 消费者按照分区日志的顺序查看记录。
3. 对有N个复制者的主题,最多能容忍N-1个服务器挂掉,而不会丢失任何提交到日志的记录。

消息系统(Kafka as a Messaging System)

Kafka作为消息系统的优势:
1. 每个主题可以自动进行扩展,可以有多个订阅者。
2. 比起传统的消息系统,有更好的顺序保证。
3. 通过分区的概念,提供顺序保证和自动负载均衡,提高并发处理的能力。

存储系统(Kafka as a Storage System)

由于kafka较好的存储并且允许客户端控制读取的位置,你可以将其认为是一个高性能,低延迟提交日志存储,用于复制和传播,专用分布式文件系统。

流处理(Kafka for Stream Processing)

Kafka不仅可以读取,写入和存储数据流,还可以实现流的实时处理目的。

为什么Kafka会这么快

大多数人,选择Kafka的特性之一就是极佳的性能,为什么Kafka会这么快?

顺序写入/Sequential IO

Kafka尽量会避免随机磁盘访问,采用了顺序写入的策略。大多数服务器都是采用的SATA硬盘这类机械硬盘,当Kafka收到消息后,会顺序写入到当前的分区文件的末尾,也就是所谓的分区其实就是一个文件。如果所有服务器采用SSD硬盘的话,这个策略的优势提升不大。这个技巧还用在MySQL InnoDB上,运用事务日志把随机IO转成顺序IO。

代价 顺序IO 随机IO
寻道时间 较短(3ms) 较长(15ms)
旋转延迟 较短(2ms) 较大(4ms)
处理资源
IOPS(Input/Output Operations Per Second)
内存映射(Memory Mapped Files)

将操作系统的内存与磁盘上的文件进行映射,也就是虚拟内存页(Page),可以像对硬盘一样读写虚拟内存,通过操作系统的策略稍后定时同步到磁盘上,提升数据写入的效率。

读取数据

采用了零拷贝技术,实现性能极大提升。所谓的零拷贝技术,就是减少了用户空间与内核空间的文件拷贝,避免CPU操作无效的数据存储拷贝,主要还是通过系统mmap实现。

参考链接

  1. Kafka Introduction
  2. KAFKA官方文档
  3. Kafka 官方文档翻译[20171016]
  4. KAFKA官方文档 简介
  5. 20 Best Practices for Working With Apache Kafka at Scale
  6. Apache Kafka Best Practices
  7. Kafka最佳实践 / Kafka Best Practices
  8. Kafka Best Practices
  9. 为什么Kafka这么快
  10. 为什么Kafka这么快
  11. 磁盘I/O那些事
  12. 随机 I/O & 顺序 I/O
  13. Understanding I/O: Random vs Sequential
  14. Kafka消费者:从Kafka中读取数据
  15. Linux下的零拷贝
  16. Here’s what makes Apache Kafka so fast
  17. Why Is Kafka So Fast

RabbitMQ必知必会

什么是RabbitMQ

RabbitMQ是一个消息队列(MQ=Message Queue),它实现了高级消息队列协议(AMQP=Advanced Message Queue Protocol)。所谓的AMQP就是,用于统一面向消息中间件实现的一套标准协议,这种消息协议,可使符合要求的客户端与符合要求的消息代理进行通信。

实现原理

交换机(exchange)

AMQP的实体将消息发送到交换机。交换机接受消息并将其路由到对应的队列。除了4中交换机类型,交换机还有一些特殊的属性。交换机可以是持久的或者临时的。消息代理重启后,具有持久化属性的交换机可以保证消息不丢失,临时的则不行。

交换机相关名词

路由键(routing key)

消息中自带的属性,主要用于直连、主题等交换机。

信道(channels)

保持大量的TCP连接,成本比较高,会消耗较多的系统资源,AMQP协议采用了可共享单个TCP连接的轻量级连接,简称为信道。

虚拟主机(Virtual Hosts)

单个消息代理可以隔离用户组,交换机,队列等,相当于有着自己的独立环境。

消息确认(Message Acknowledgements)
  1. 消息自动确认机制,消息代理发送消息到应用后,例如调用AMQP协议中的方法basic.deliver或basic.get-ok。
  2. 消息显式确认机制,调用AMQP协议中的方法basic.ack。

交换机的类型

默认(Direct)

实际上也是Direct类型的交换机,默认为无名称预定义的消息代理。它有一个特殊的属性,使它在简单的应用中非常有用:每一个队列自动创建一个名称与队列名称一致的路由键为并绑定到相同名称的队列。

直连(Direct)

直接转发相关的消息到指定的队列。直连交换机通过路由键来传递消息到队列。
1. 队列通过路由键 K 绑定到交换机
2. 消息带有一个路由键 R会发送到该直连路由,当K=R时,直连交换机将消息发送到该队列。

广播(Fanout)

大多数人喜欢翻译为扇出,我觉得这个概念可能和广播类似,直接将消息广播到所有绑定的队列。

主题(Topic)

基于主题的队列,实现消息的路由键的精准匹配或者模糊匹配。每一个匹配条件是或的关系。

通过对消息的路由键进行匹配:
1. * 星号匹配一个单词
2. # 井号匹配0到多个单词。

匹配关系如下面的表格:

路由键 *.orange.* *.*.rabbit lazy.#
quick.orange.rabbit
lazy.orange.elephant
quick.orange.fox
lazy.brown.fox
lazy.pink.rabbit
quick.brown.fox
orange
quick.orange.male.rabbit
lazy.orange.male.rabbit
头交换机(Headers)

根据消息的headers参数动态的路由相关消息。当采用headers交换机时,路由键就失效了。可以利用参数x-match的值(any/all)来确认是匹配全部还是部分。

交换机特殊的属性

名称(Name)

每一个交换机需要定义个名称,作为唯一标识。

持久性(Durability)

标识该交换机里的消息,是否需要进行持久化,即使消息代理重新启动了。

自动删除

当最后一个队列取消绑定时删除掉交换机。

为什么选择RabbitMQ

大多数人可能会拿RabbitMQ vs Kafka作对比,我只想说,性能只是消息队列里众多的特性之一。大多数情况下,RabbitMQ采用3-7个节点就可以获得很好的性能。下面列举一个表格对比这这者之间的差异:

特性/场景 RabbitMQ Kafka
没有复杂的路由
最大吞吐量100k/s
至少按照分区顺序传送一次
流处理
事件溯源
兼容复杂的协议
指定的消息确认
复杂的路由规则
开发体验 官方提供11个客户端 官方提供Java客户端,第三方补充
安全和操作性 HTTP API 管理CLI由shell脚本构成
管理监控Web UI
良好的 CLI工具
Zookeeper依赖 依赖ZK提供HA,大约比例为3个Kafka+5台ZK
性能 20k/s 容易 最高100k/s

RabbitMQ最佳实践

cloudamqp写了4篇关于RabbitMQ的文章,讲述了RabbitMQ的最佳实践,非常值得一看。
1. Part 1: RabbitMQ Best Practice
2. Part 2 – Best Practice for High Performance
3. Part 3 – Best Practice for High Availability
4. Part 4 – 13 common RabbitMQ mistakes

参考链接

  1. 高级消息队列协议
  2. AMQP 0-9-1 Model Explained
  3. RabbitMQ Tutorial
  4. AMQP 0-9-1 读后感
  5. Understanding When to use RabbitMQ or Apache Kafka
  6. rabbitmq 实现原理
  7. 深入了解RabbitMQ工作原理及简单使用
  8. RabbitMQ – Best Practices For Designing Exchanges, Queues And Bindings?

HAProxy必知必会

什么是HAProxy

HAProxy是一款提供高可用性、负载均衡以及基于TCP和HTTP应用的高性能代理。典型的用于作为MySQL的负载均衡,还可以用于保持Seesion会话的Http应用,甚至还可以用于自定义的API网关。

实现原理

前端 (frontend)

用于定义需要监听的sockets(套接字)以及接受客户端的连接。

控制列表(ACL Access Control Lists)

通过acl定义frontend的请求如何转发给后端的服务器。

后端(backend)

用于定义一组服务器,代理将客户端的请求转发到这些服务器。

健康检查

HAProxy可以定时对后端的服务器进行健康状态检查。

高可用性

HAProxy通过多种策略算法对后端服务进行负载均衡,保证后端服务的高可用性。常见的策略有:
1. roundrobin 轮询算法,可以支持权重,支持运行时调整权重。
2. static-rr 基于权重的轮询,不支持运行时调整权重。
3. leastconn 适用于长连接的会话,将新情求转发至后端连接数最少的服务。
4. first 顺序算法,按照服务器id最少的负载,最大连接已满,就请求至下一个服务,必须设置maxconn参数,否则无效。
5. source 将请求的原地址进行hash运算,根据后端服务权重转发指定的服务器。常用与五cookie功能的基于TCP协议的负载均衡。
6. uri 对问号之前的uri进行hash路由,加上服务器权重,使得同一个uri总是路由到相同的服务器。仅仅用于Http后端服务场景。
7. uri_param 根据Http GET请求的参数,即问号之后的参数,加上服务器权重进行路由。设置了check_post参数才会检查post请求。
8. hdr<name> 查找Http Header<name>请求头信息并路由。相当于ACL的hdr函数,请求头不区分大小写。
9. random 通过一致性hash函数随机到一台服务器,可以同时采用服务器权重。常用于大量后端服务或者添加删除频繁的场景。hash-balance-factor参数可进一步提升在响应时间经常变化场景下的公平性。
10. rdp-cookie(name) 根据cookie(name)进行哈希,适用于持久化请求,将同一个用户或者同一个session路由到同一台服务器。如果没有cookie,默认采用roundrobin。服务器权重在此场景不起作用。

但HAProxy服务自身的可用性是如何保证的呢?你想想,这么请求都是通过HAProxy负责转发,万一HAProxy挂掉了呢?所以针对HAProxy本身,也是有高可用的需求。常用的方案是使用Keeplived实现。首先设置内网VIP(Virtual IP/Floating IP),提供对外的服务,Keeplived服务对每一个master和slave进行心跳检测,发现master挂掉了话,会通过ARP协议更新VIP对应的MAC地址。这里有一张图,可以很清晰的了解整个过程。

how floating ip working

高性能

HAProxy是一个单线程,事件驱动,基于优先级调度的高速IO层的非阻塞引擎。它从设计之初就考虑到了数据转发,其架构进行了优化,使其用尽可能少的操作可以快速移动数据。它实现了一个分层模型,在每一个级别提供旁路机制,确保数据除非必要,否则不需要转发到更高的级别。最后发现处理时间的花费,大约85%在内核,15%在HAProxy。

常用配置

代理服务名称的正则表达式为[a-zA-Z0-9-_.:]

为什么选择HAProxy

还有一些其他的选择,比如:
1. Nginx : 实际上Nginx已经成为第二个事实上标准的Http服务器。
2. LVS 是工作在Linux内核的第四层网络上,基于包的负载均衡服务。
3. Varnish是一个智能缓存反向代理,可能是最好的Web应用加速器。

将这些常用的服务进行对比,看看为什么没有选择它们。

特点 Nginx LVS Varnish HAProxy 备注
10K Problem 1w并发
TCP load balancer/TCP Proxy
UDP load balancer
Http load balancer
Https load balancer
Http Server/Web Server
Cache Server/Cache Proxy 缓存代理
Http Reverse Proxy/Gateway 反向代理
Sticky Sessions 会话保持
load balancing algorithms 4 9 负载均衡策略
health check 健康检查
Http Proxy 正向代理 Squid

HAProxy最佳实践

官方发布了PPT介绍HAProxy主要功能,非常清楚的介绍了HAProxy最佳实践

参考链接

  1. HAProxy用法详解 全网最详细中文文档
  2. 谈一谈使用 HAProxy 构建 API 网关服务的思路
  3. haproxy configuation balance
  4. haproxy intro
  5. Introduction to HAProxy ACLs
  6. Quick introduction to load balancing and load balancers
  7. How To Configure MySQL Group Replication on Ubuntu 16.04
  8. How To Use HAProxy As A Layer 4 Load Balancer for WordPress Application Servers on Ubuntu 14.04
  9. An Introduction to HAProxy and Load Balancing Concepts
  10. 虚拟IP和IP漂移
  11. Floating IP Resources
  12. How To Set Up Highly Available Web Servers with Keepalived and Floating IPs on Ubuntu 14.04
  13. HAProxy和负载均衡概念介绍
  14. Haproxy best practice
  15. HAProxy 最佳实践笔记
  16. 使用 Haproxy + Keepalived 构建基于 Docker 的高可用负载均衡服务(一)
  17. How to configure floating IP on Ubuntu