41 |
42 |
59 |
92 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
144 |
145 |
146 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/03~Kafka/架构概念.md:
--------------------------------------------------------------------------------
1 | # Kafka 架构概念
2 |
3 | Kafka 作为一个高度可扩展可容错的消息系统,一个典型的 kafka 集群中包含若干 producer,若干 broker,若干 consumer,以及一个 Zookeeper 集群。Kafka 通过 Zookeeper 管理集群配置,选举 leader,以及在 consumer group 发生变化时进行 rebalance。producer 使用 push 模式将消息发布到 broker,consumer 使用 pull 模式从 broker 订阅并消费消息:
4 |
5 | 
6 |
7 | Kafka 专用术语:
8 |
9 | - Broker:消息中间件处理结点,一个 Kafka 节点就是一个 broker,多个 broker 可以组成一个 Kafka 集群。
10 | - Topic:一类消息,Kafka 集群能够同时负责多个 topic 的分发。
11 | - Partition:topic 物理上的分组,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。
12 | - Segment:partition 物理上由多个 segment 组成。
13 | - offset:每个 partition 都由一系列有序的、不可变的消息组成,这些消息被连续的追加到 partition 中。partition 中的每个消息都有一个连续的序列号叫做 offset,用于 partition 唯一标识一条消息。
14 | - Producer:负责发布消息到 Kafka broker。
15 | - Consumer:消息消费者,向 Kafka broker 读取消息的客户端。
16 | - Consumer Group:每个 Consumer 属于一个特定的 Consumer Group。
17 |
18 | Kafka 实现了零拷贝原理来快速移动数据,避免了内核之间的切换。Kafka 可以将数据记录分批发送,从生产者到文件系统(Kafka 主题日志)到消费者,可以端到端的查看这些批次的数据。批处理能够进行更有效的数据压缩并减少 I/O 延迟,Kafka 采取顺序写入磁盘的方式,避免了随机磁盘寻址的浪费,总结一下其实就是四个要点:
19 |
20 | - 顺序读写:因为硬盘是机械结构,每次读写都会寻址,写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最“讨厌”随机 I/O,最喜欢顺序 I/O。为了提高读写硬盘的速度,Kafka 就是使用顺序 I/O。
21 | - 零拷贝:在 Linux Kernal 2.2 之后出现了一种叫做“零拷贝(zero-copy)”系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存空间的直接映射,数据不再复制到“用户态缓冲区”系统上下文切换减少 2 次,可以提升一倍性能。
22 | - 消息压缩:消息都是经过压缩传递、存储的,降低网络与磁盘的负担。
23 | - 分批发送:批量处理是一种非常有效的提升系统吞吐量的方法,在 Kafka 内部,消息都是以“批”为单位处理的。
24 |
25 | # 消息与主题
26 |
27 | 消息是 Kafka 通信的基本单位,由一个固定长度的消息头和一个可变长度的消息体构成。在老版本中,每一条消息称为 Message;在由 Java 重新实现的客户端中,每一条消息称为 Record。为了提高效率,消息会分批次写入 Kafka,批次就代指的是一组消息。Kafka 将一组消息抽象归纳为一个主题(Topic),也就是说,一个主题就是对消息的一个分类。生产者将消息发送到特定主题,消费者订阅主题或主题的某些分区进行消费。
28 |
29 | Kafka 消息传递的事务特点如下:
30 |
31 | - at most once:最多一次,这个和 JMS 中"非持久化"消息类似,发送一次,无论成败,将不会重发。消费者 fetch 消息,然后保存 offset,然后处理消息;当 client 保存 offset 之后,但是在消息处理过程中出现了异常,导致部分消息未能继续处理。那么此后"未处理"的消息将不能被 fetch 到,这就是"at most once"。
32 | - at least once:消息至少发送一次,如果消息未能接受成功,可能会重发,直到接收成功。消费者 fetch 消息,然后处理消息,然后保存 offset。如果消息处理成功之后,但是在保存 offset 阶段 zookeeper 异常导致保存操作未能执行成功,这就导致接下来再次 fetch 时可能获得上次已经处理过的消息,这就是"at least once",原因 offset 没有及时的提交给 zookeeper,zookeeper 恢复正常还是之前 offset 状态。
33 | - exactly once:消息只会发送一次。kafka 中并没有严格的去实现(基于 2 阶段提交),我们认为这种策略在 kafka 中是没有必要的。
34 |
35 | # 生产者(Producer)
36 |
37 | 生产者(Producer)负责将消息发送给代理,也就是向 Kafka 代理发送消息的客户端。生产者会将某 topic 的消息发布到相应的 partition 中。生产者在默认情况下把消息均衡地分布到主题的所有分区上,而并不关心特定消息会被写到哪个分区。不过,在某些情况下,生产者会把消息直接写到指定的分区。
38 |
39 | 
40 |
41 | Kafka 中的生产者设计主要考虑了以下方面:
42 |
43 | - 负载均衡:由于消息 topic 由多个 partition 组成,且 partition 会均衡分布到不同 broker 上,因此,为了有效利用 broker 集群的性能,提高消息的吞吐量,producer 可以通过随机或者 hash 等方式,将消息平均发送到多个 partition 上,以实现负载均衡。
44 | - 批量发送:是提高消息吞吐量重要的方式,Producer 端可以在内存中合并多条消息后,以一次请求的方式发送了批量的消息给 broker,从而大大减少 broker 存储消息的 IO 操作次数。但也一定程度上影响了消息的实时性,相当于以时延代价,换取更好的吞吐量。
45 |
46 | # 消费者和消费组
47 |
48 | consumer 是 kafka 当中的消费者,主要用于消费 kafka 当中的数据;在 Kafka 中每一个消费者都属于一个特定消费组(ConsumerGroup),我们可以为每个消费者指定一个消费组,以 groupId 代表消费组名称,通过 group.id 配置设置。如果不指定消费组,则该消费者属于默认消费组 test-consumer-group。
49 |
50 | 同时,每个消费者也有一个全局唯一的 id,通过配置项 client.id 指定,如果客户端没有指定消费者的 id,Kafka 会自动为该消费者生成一个全局唯一的 id,格式为 `${groupId}-${hostName}-${timestamp}-${UUID 前 8 位字符}`。同一个主题的一条消息只能被同一个消费组下某一个消费者消费,但不同消费组的消费者可同时消费该消息。消费组是 Kafka 用来实现对一个主题消息进行广播和单播的手段,实现消息广播只需指定各消费者均属于不同的消费组,消息单播则只需让各消费者属于同一个消费组。
51 |
52 | 
53 |
54 | 总结而言,Kafka 中的消费者与消费组具备以下属性:
55 |
56 | - 任何 Consumer 必须属于一个 Consumer Group
57 | - 同一 Consumer Group 中的多个 Consumer 实例,不同时消费同一个 partition,等效于队列模式。如图,Consumer Group 1 的三个 Consumer 实例分别消费不同的 partition 的消息,即,TopicA-part0、TopicA-part1、TopicA-part2。
58 | - 不同 Consumer Group 的 Consumer 实例可以同时消费同一个 partition,等效于发布订阅模式。如图,Consumer Group 1 的 Consumer1 和 Consumer Group 2 的 Consumer4,同时消费 TopicA-part0 的消息。
59 | - Partition 内消息是有序的,Consumer 通过 pull 方式消费消息。
60 | - Kafka 不删除已消费的消息
61 |
62 | # 分区
63 |
64 | Kafka 将一组消息归纳为一个主题,而每个主题又被分成一个或多个分区(Partition)。每个分区由一系列有序、不可变的消息组成,是一个有序队列。同一个主题中的分区可以不在一个机器上,有可能会部署在多个机器上,由此来实现 kafka 的伸缩性;单一主题中的分区有序,但是无法保证主题中所有的分区有序。
65 |
66 | 
67 |
68 | 每个分区在物理上对应为一个文件夹,分区的命名规则为主题名称后接“—”连接符,之后再接分区编号,分区编号从 0 开始,编号最大值为分区的总数减 1。每个分区又有一至多个副本(Replica),分区的副本分布在集群的不同代理上,以提高可用性。从存储角度上分析,分区的每个副本在逻辑上抽象为一个日志(Log)对象,即分区的副本与日志对象是一一对应的。每个主题对应的分区数可以在 Kafka 启动时所加载的配置文件中配置,也可以在创建主题时指定。当然,客户端还可以在主题创建后修改主题的分区数。
69 |
70 | 
71 |
72 | 分区使得 Kafka 在并发处理上变得更加容易,分区数量决定了每个 Consumer Group 中并发消费者的最大数量。理论上来说,分区数越多吞吐量越高,但这要根据集群实际环境及业务场景而定。某一个主题下的分区数,对于消费该主题的同一个消费组下的消费者数量,应该小于等于该主题下的分区数。某一个主题有 4 个分区,那么消费组中的消费者应该小于等于 4,而且最好与分区数成整数倍 1 2 4 这样。同一个分区下的数据,在同一时刻,不能同一个消费组的不同消费者消费。
73 |
74 | 
75 |
76 | 同时,分区也是 Kafka 保证消息被顺序消费以及对消息进行负载均衡的基础。Kafka 只能保证一个分区之内消息的有序性,并不能保证跨分区消息的有序性。每条消息被追加到相应的分区中,是顺序写磁盘,因此效率非常高,这是 Kafka 高吞吐率的一个重要保证。同时与传统消息系统不同的是,Kafka 并不会立即删除已被消费的消息,由于磁盘的限制消息也不会一直被存储,因此 Kafka 提供两种删除老数据的策略,一是基于消息已存储的时间长度,二是基于分区的大小。这两种策略都能通过配置文件进行配置。
77 |
78 | # 偏移量
79 |
80 | 任何发布到分区的消息会被直接追加到日志文件(分区目录下以“.log”为文件名后缀的数据文件)的尾部,而每条消息在日志文件中的位置都会对应一个按序递增的偏移量。偏移量是一个分区下严格有序的逻辑值,它并不表示消息在磁盘上的物理位置。由于 Kafka 几乎不允许对消息进行随机读写,因此 Kafka 并没有提供额外索引机制到存储偏移量,也就是说并不会给偏移量再提供索引。
81 |
82 | 消费者可以通过控制消息偏移量来对消息进行消费,如消费者可以指定消费的起始偏移量。为了保证消息被顺序消费,消费者已消费的消息对应的偏移量也需要保存。需要说明的是,消费者对消息偏移量的操作并不会影响消息本身的偏移量。旧版消费者将消费偏移量保存到 ZooKeeper 当中,而新版消费者是将消费偏移量保存到 Kafka 内部一个主题当中。当然,消费者也可以自己在外部系统保存消费偏移量,而无需保存到 Kafka 中。
83 |
84 | # 日志段(Segment)
85 |
86 | 一个日志又被划分为多个日志段(LogSegment),日志段是 Kafka 日志对象分片的最小单位。与日志对象一样,日志段也是一个逻辑概念,一个日志段对应磁盘上一个具体日志文件和两个索引文件。日志文件是以“.log”为文件名后缀的数据文件,用于保存消息实际数据。两个索引文件分别以“.index”和“.timeindex”作为文件名后缀,分别表示消息偏移量索引文件和消息时间戳索引文件。查找某个 offset 的消息,先二分法找出消息所在的 segment 文件(因为每个 segment 的命名都是以该文件中消息 offset 最小的值命名);然后,加载对应的.index 索引文件到内存,同样二分法找出小于等于给定 offset 的最大的那个 offset 记录(相对 offset,position);最后,根据 position 到.log 文件中,顺序查找出 offset 等于给定 offset 值的消息。
87 |
88 | 由于消息在 partition 的 segment 数据文件中是顺序读写的,且消息消费后不会删除(删除策略是针对过期的 segment 文件),这种顺序磁盘 IO 存储设计是 Kafka 高性能很重要的原因。
89 |
90 | # 代理(Broker)
91 |
92 | Kafka 集群包含一个或多个服务器,我们将每一个 Kafka 实例称为代理(Broker),通常也称代理为 Kafka 服务器(KafkaServer)。broker 接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。broker 为消费者提供服务,对读取分区的请求作出响应,返回已经提交到磁盘上的消息。
93 |
94 | 在生产环境中 Kafka 集群一般包括一台或多台服务器,我们可以在一台服务器上配置一个或多个代理。每一个代理都有唯一的标识 id,这个 id 是一个非负整数。在一个 Kafka 集群中,每增加一个代理就需要为这个代理配置一个与该集群中其他代理不同的 id,id 值可以选择任意非负整数即可,只要保证它在整个 Kafka 集群中唯一,这个 id 就是代理的名字,也就是在启动代理时配置的 broker.id 对应的值,因此在本文中有时我们也称为 brokerId。由于给每个代理分配了不同的 brokerId,这样对代理进行迁移就变得更方便,从而对消费者来说是透明的,不会影响消费者对消息的消费。
95 |
96 | 每个集群中都会有一个 broker 同时充当了 集群控制器(Leader)的角色,它是由集群中的活跃成员选举出来的。每个集群中的成员都有可能充当 Leader,Leader 负责管理工作,包括将分区分配给 broker 和监控 broker。集群中,一个分区从属于一个 Leader,但是一个分区可以分配给多个 broker(非 Leader),这时候会发生分区复制。这种复制的机制为分区提供了消息冗余,如果一个 broker 失效,那么其他活跃用户会重新选举一个 Leader 接管。
97 |
98 | 
99 |
100 | # ISR
101 |
102 | Kafka 在 ZooKeeper 中动态维护了一个 ISR(In-sync Replica),即保存同步的副本列表,该列表中保存的是与 Leader 副本保持消息同步的所有副本对应的代理节点 id。如果一个 Follower 副本宕机(本书用宕机来特指某个代理失效的情景,包括但不限于代理被关闭,如代理被人为关闭或是发生物理故障、心跳检测过期、网络延迟、进程崩溃等)或是落后太多,则该 Follower 副本节点将从 ISR 列表中移除。对于 Kafka 节点,判断是”alive”有以下两个条件:
103 |
104 | - 节点必须和 Zookeeper 保持心跳连接
105 | - 如果节点是 follower,必须从 leader 节点上复制数据来备份,而且备份的数据相比 leader 而言,不能落后太多。
106 |
107 | # 副本
108 |
109 | 
110 |
111 | 由于 Kafka 副本的存在,就需要保证一个分区的多个副本之间数据的一致性,Kafka 会选择该分区的一个副本作为 Leader 副本,而该分区其他副本即为 Follower 副本,只有 Leader 副本才负责处理客户端读/写请求,Follower 副本从 Leader 副本同步数据。引入 Leader 副本后客户端只需与 Leader 副本进行交互,这样数据一致性及顺序性就有了保证。Follower 副本从 Leader 副本同步消息,对于 n 个副本只需 n−1 条通路即可,这样就使得系统更加简单而高效。副本 Follower 与 Leader 的角色并不是固定不变的,如果 Leader 失效,通过相应的选举算法将从其他 Follower 副本中选出新的 Leader 副本。
112 |
113 | Kafka 解决了 fail/recover,一条消息只有被 ISR 里的所有 Follower 都从 Leader 复制过去才会被认为已提交。这样就避免了部分数据被写进了 Leader,还没来得及被任何 Follower 复制就宕机了,而造成数据丢失(Consumer 无法消费这些数据)。
114 |
115 | # ZooKeeper
116 |
117 | Kafka 利用 ZooKeeper 保存相应元数据信息,Kafka 元数据信息包括如代理节点信息、Kafka 集群信息、旧版消费者信息及其消费偏移量信息、主题信息、分区状态信息、分区副本分配方案信息、动态配置信息等。Kafka 在启动或运行过程当中会在 ZooKeeper 上创建相应节点来保存元数据信息,Kafka 通过监听机制在这些节点注册相应监听器来监听节点元数据的变化,从而由 ZooKeeper 负责管理维护 Kafka 集群,同时通过 ZooKeeper 我们能够很方便地对 Kafka 集群进行水平扩展及数据迁移。
118 |
119 | 不过 2021 年3 月 30 日,Kafka 背后的企业 Confluent 发布博客表示,在即将发布的 2.8 版本里,用户可在完全不需要 ZooKeeper 的情况下运行 Kafka,该版本将依赖于 ZooKeeper 的控制器改造成了基于 Kafka Raft 的 Quorm 控制器。在之前的版本中,如果没有 ZooKeeper,Kafka 将无法运行。但管理部署两个不同的系统不仅让运维复杂度翻倍,还让 Kafka 变得沉重,进而限制了 Kafka 在轻量环境下的应用,同时 ZooKeeper 的分区特性也限制了 Kafka 的承载能力。
--------------------------------------------------------------------------------
/03~Kafka/消息生产与消费/消费者.md:
--------------------------------------------------------------------------------
1 | # Kafka 消费者
2 |
3 | 消息由生产者发送到 kafka 集群后,会被消费者消费。一般来说我们的消费模型有两种:推送模型(push)和拉取模型(pull)基于推送模型的消息系统,由消息代理记录消费状态。消息代理将消息推送到消费者后,标记这条消息为已经被消费,但是这种方式无法很好地保证消费的处理语义。比如当我们把已经把消息发送给消费者之后,由于消费进程挂掉或者由于网络原因没有收到这条消息,如果我们在消费代理将其标记为已消费,这个消息就永久丢失了。如果我们利用生产者收到消息后回复这种方法,消息代理需要记录消费状态,这种不可取。如果采用 push,消息消费的速率就完全由消费代理控制,一旦消费者发生阻塞,就会出现问题。Kafka 采取拉取模型(pull),由自己控制消费速度,以及消费的进度,消费者可以按照任意的偏移量进行消费。比如消费者可以消费已经消费过的消息进行重新处理,或者消费最近的消息等等。
4 |
5 | 消费者组(Consumer Group)是由一个或多个消费者实例(Consumer Instance)组成的群组,具有可扩展性和可容错性的一种机制。消费者组内的消费者共享一个消费者组 ID,这个 ID 也叫做 Group ID,组内的消费者共同对一个主题进行订阅和消费,同一个组中的消费者只能消费一个分区的消息,多余的消费者会闲置,派不上用场。换言之,同一主题的一条消息只能被同一个消费者组内的一个消费者消费,但多个消费者组可同时消费这一消息。
6 |
7 | 
8 |
9 | 这是 Kafka 用来实现一个 Topic 消息的广播(发给所有的 Consumer)和单播(发给某一个 Consumer)的手段。一个 Topic 可以对应多个 Consumer Group。如果需要实现广播,只要每个 Consumer 有一个独立的 Group 就可以了。要实现单播只要所有的 Consumer 在同一个 Group 里。用 Consumer Group 还可以将 Consumer 进行自由的分组而不需要多次发送消息到不同的 Topic。
10 |
11 | # 队列与订阅
12 |
13 | Kafka 的消息队列一般分为两种模式:点对点队列模式和发布订阅模式。如果一个生产者生产的消息由一个消费者进行消费的话,那么这种模式就是点对点模式:
14 |
15 | 
16 |
17 | 如果一个生产者或者多个生产者产生的消息能够被多个消费者同时消费的情况,这样的消息队列成为发布订阅模式的消息队列:
18 |
19 | 
20 |
21 | ## 队列模式
22 |
23 | 队列模式,指每条消息只会有一个 Consumer 消费到。Kafka 保证同一 Consumer Group 中只有一个 Consumer 会消费某条消息。
24 |
25 | - 在 Consumer Group 稳定状态下,每一个 Consumer 实例只会消费某一个或多个特定 partition 的数据,而某个 partition 的数据只会被某一个特定的 Consumer 实例所消费,也就是说 Kafka 对消息的分配是以 partition 为单位分配的,而非以每一条消息作为分配单元;
26 | - 同一 Consumer Group 中,如果 Consumer 实例数量少于 partition 数量,则至少有一个 Consumer 会消费多个 partition 的数据;如果 Consumer 的数量与 partition 数量相同,则正好一个 Consumer 消费一个 partition 的数据;而如果 Consumer 的数量多于 partition 的数量时,会有部分 Consumer 无法消费该 Topic 下任何一条消息;
27 |
28 | Kafka 消费者从属于消费者群组。一个群组中的消费者订阅的都是相同的主题,每个消费者接收主题一部分分区的消息。下面是一个 Kafka 分区消费示意图:
29 |
30 | 
31 |
32 | 上图中的主题 T1 有四个分区,分别是分区 0、分区 1、分区 2、分区 3,我们创建一个消费者群组 1,消费者群组中只有一个消费者,它订阅主题 T1,接收到 T1 中的全部消息。由于一个消费者处理四个生产者发送到分区的消息,压力有些大,需要帮手来帮忙分担任务,于是就演变为下图:
33 |
34 | 
35 |
36 | 这样一来,消费者的消费能力就大大提高了,但是在某些环境下比如用户产生消息特别多的时候,生产者产生的消息仍旧让消费者吃不消,那就继续增加消费者。
37 |
38 | 
39 |
40 | 如上图所示,每个分区所产生的消息能够被每个消费者群组中的消费者消费,如果向消费者群组中增加更多的消费者,那么多余的消费者将会闲置,如下图所示
41 |
42 | 
43 |
44 | 向群组中增加消费者是横向伸缩消费能力的主要方式。总而言之,我们可以通过增加消费组的消费者来进行水平扩展提升消费能力。这也是为什么建议创建主题时使用比较多的分区数,这样可以在消费负载高的情况下增加消费者来提升性能。另外,消费者的数量不应该比分区数多,因为多出来的消费者是空闲的,没有任何帮助。
45 |
46 | ## 发布订阅模式
47 |
48 | 发布订阅模式,又指广播模式,Kafka 保证 topic 的每条消息会被所有 Consumer Group 消费到,而对于同一个 Consumer Group,还是保证只有一个 Consumer 实例消费到这条消息。Kafka 一个很重要的特性就是,只需写入一次消息,可以支持任意多的应用读取这个消息。换句话说,每个应用都可以读到全量的消息。为了使得每个应用都能读到全量消息,应用需要有不同的消费组。对于上面的例子,假如我们新增了一个新的消费组 G2,而这个消费组有两个消费者,那么就演变为下图这样:
49 |
50 | 
51 |
52 | 在这个场景中,消费组 G1 和消费组 G2 都能收到 T1 主题的全量消息,在逻辑意义上来说它们属于不同的应用。总结起来就是如果应用需要读取全量消息,那么请为该应用设置一个消费组;如果该应用消费能力不足,那么可以考虑在这个消费组里增加消费者。
53 |
54 | # 分区重平衡
55 |
56 | 我们从上面的消费者演变图中可以知道这么一个过程:最初是一个消费者订阅一个主题并消费其全部分区的消息,后来有一个消费者加入群组,随后又有更多的消费者加入群组,而新加入的消费者实例分摊了最初消费者的部分消息,这种把分区的所有权通过一个消费者转到其他消费者的行为称为重平衡,英文名也叫做 Rebalance。如下图所示:
57 |
58 | 
59 |
60 | 重平衡非常重要,它为消费者群组带来了高可用性和伸缩性,我们可以放心的添加消费者或移除消费者,不过在正常情况下我们并不希望发生这样的行为。在重平衡期间,消费者无法读取消息,造成整个消费者组在重平衡的期间都不可用。另外,当分区被重新分配给另一个消费者时,消息当前的读取状态会丢失,它有可能还需要去刷新缓存,在它重新恢复状态之前会拖慢应用程序。
61 |
62 | 重平衡也是一把双刃剑,它为消费者群组带来高可用性和伸缩性的同时,还有有一些明显的缺点(bug),而这些 bug 到现在社区还无法修改。重平衡的过程对消费者组有极大的影响。因为每次重平衡过程中都会导致万物静止,参考 JVM 中的垃圾回收机制,也就是 Stop The World .也就是说,在重平衡期间,消费者组中的消费者实例都会停止消费,等待重平衡的完成。而且重平衡这个过程很慢。
63 |
64 | ## 重平衡算法
65 |
66 | 
67 |
68 | ## 重平衡流程
69 |
70 | 消费者通过向组织协调者(Kafka Broker)发送心跳来维护自己是消费者组的一员并确认其拥有的分区。对于不同不的消费群体来说,其组织协调者可以是不同的。只要消费者定期发送心跳,就会认为消费者是存活的并处理其分区中的消息。当消费者检索记录或者提交它所消费的记录时就会发送心跳。如果过了一段时间 Kafka 停止发送心跳了,会话(Session)就会过期,组织协调者就会认为这个 Consumer 已经死亡,就会触发一次重平衡。如果消费者宕机并且停止发送消息,组织协调者会等待几秒钟,确认它死亡了才会触发重平衡。在这段时间里,死亡的消费者将不处理任何消息。在清理消费者时,消费者将通知协调者它要离开群组,组织协调者会触发一次重平衡,尽量降低处理停顿。
71 |
72 | - 对于每个 Consumer Group,选举出一个 Broker 作为 Coordinator(0.9 版本以上),由它 Watch Zookeeper,从而监控判断是否有 partition 或者 Consumer 的增减,然后生成 Rebalance 命令,按照以上算法重新分配。
73 | - 当 Consumer Group 第一次被初始化时,Consumer 通常会读取每个 partition 的最早或最近的 offset(Zookeeper 记录),然后顺序地读取每个 partition log 的消息,在 Consumer 读取过程中,它会提交已经成功处理的消息的 offsets(由 Zookeeper 记录)。
74 | - 当一个 partition 被重新分配给 Consumer Group 中的其他 Consumer,新的 Consumer 消费的初始位置会设置为(原来 Consumer)最近提交的 offset。
75 |
76 | # 创建消费者
77 |
78 | 在读取消息之前,需要先创建一个 KafkaConsumer 对象。创建 KafkaConsumer 对象与创建 KafkaProducer 对象十分相似 --- 把需要传递给消费者的属性放在 properties 对象中,后面我们会着重讨论 Kafka 的一些配置,这里我们先简单的创建一下,使用 3 个属性就足矣,分别是 bootstrap.server,key.deserializer,value.deserializer 。
79 |
80 | 还有一个属性是 group.id 这个属性不是必须的,它指定了 KafkaConsumer 是属于哪个消费者群组。创建不属于任何一个群组的消费者也是可以的:
81 |
82 | ```java
83 | Properties properties = new Properties();
84 | properties.put("bootstrap.server", "192.168.1.9:9092");
85 | properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
86 | properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
87 | KafkaConsumer < String, String > consumer = new KafkaConsumer < > (properties);
88 | ```
89 |
90 | ## 主题订阅
91 |
92 | 创建好消费者之后,下一步就开始订阅主题了。subscribe() 方法接受一个主题列表作为参数,使用起来比较简单:
93 |
94 | ```java
95 | consumer.subscribe(Collections.singletonList("customerTopic"));
96 | ```
97 |
98 | 为了简单我们只订阅了一个主题 customerTopic,参数传入的是一个正则表达式,正则表达式可以匹配多个主题,如果有人创建了新的主题,并且主题的名字与正则表达式相匹配,那么会立即触发一次重平衡,消费者就可以读取新的主题。
99 |
100 | 要订阅所有与 test 相关的主题,可以这样做:
101 |
102 | ```java
103 | consumer.subscribe("test.*");
104 | ```
105 |
106 | ## 轮询
107 |
108 | 我们知道,Kafka 是支持订阅/发布模式的,生产者发送数据给 Kafka Broker,那么消费者是如何知道生产者发送了数据呢?其实生产者产生的数据消费者是不知道的,KafkaConsumer 采用轮询的方式定期去 Kafka Broker 中进行数据的检索,如果有数据就用来消费,如果没有就再继续轮询等待,下面是轮询等待的具体实现:
109 |
110 | ```java
111 | try {
112 | while (true) {
113 | ConsumerRecords < String, String > records = consumer.poll(Duration.ofSeconds(100));
114 | for (ConsumerRecord < String, String > record: records) {
115 | int updateCount = 1;
116 | if (map.containsKey(record.value())) {
117 | updateCount = (int) map.get(record.value() + 1);
118 | }
119 | map.put(record.value(), updateCount);
120 | }
121 | }
122 | } finally {
123 | consumer.close();
124 | }
125 | ```
126 |
127 | - 这是一个无限循环。消费者实际上是一个长期运行的应用程序,它通过轮询的方式向 Kafka 请求数据。
128 | - 第三行代码非常重要,Kafka 必须定期循环请求数据,否则就会认为该 Consumer 已经挂了,会触发重平衡,它的分区会移交给群组中的其它消费者。传给 `poll()` 方法的是一个超市时间,用 `java.time.Duration` 类来表示,如果该参数被设置为 0 ,poll() 方法会立刻返回,否则就会在指定的毫秒数内一直等待 broker 返回数据。
129 | - poll() 方法会返回一个记录列表。每条记录都包含了记录所属主题的信息,记录所在分区的信息、记录在分区中的偏移量,以及记录的键值对。我们一般会遍历这个列表,逐条处理每条记录。
130 | - 在退出应用程序之前使用 `close()` 方法关闭消费者。网络连接和 socket 也会随之关闭,并立即触发一次重平衡,而不是等待群组协调器发现它不再发送心跳并认定它已经死亡。
131 |
132 | # 提交和偏移量的概念
133 |
134 | 
135 |
136 | 如图,Last Commited Offset 指 Consumer 最近一次提交的消费记录 offset,Current Position 是当前消费的位置,High Watermark 是成功拷贝到 log 的所有副本节点(partition 的所有 ISR 节点,下文介绍)的最近消息的 offset,Log End Offset 是写入 log 中最后一条消息的 offset+1。
137 |
138 | 从 Consumer 的角度来看,最多只能读取到 High watermark 的位置,后面的消息对消费者不可见,因为未完全复制的数据还没可靠存储,有丢失可能。
139 |
140 | ## 特殊偏移
141 |
142 | 我们上面提到,消费者在每次调用 poll() 方法进行定时轮询的时候,会返回由生产者写入 Kafka 但是还没有被消费者消费的记录,因此我们可以追踪到哪些记录是被群组里的哪个消费者读取的。消费者可以使用 Kafka 来追踪消息在分区中的位置(偏移量)
143 |
144 | 消费者会向一个叫做 `_consumer_offset` 的特殊主题中发送消息,这个主题会保存每次所发送消息中的分区偏移量,这个主题的主要作用就是消费者触发重平衡后记录偏移使用的,消费者每次向这个主题发送消息,正常情况下不触发重平衡,这个主题是不起作用的,当触发重平衡后,消费者停止工作,每个消费者可能会分到对应的分区,这个主题就是让消费者能够继续处理消息所设置的。
145 |
146 | 如果提交的偏移量小于客户端最后一次处理的偏移量,那么位于两个偏移量之间的消息就会被重复处理:
147 |
148 | 
149 |
150 | 如果提交的偏移量大于最后一次消费时的偏移量,那么处于两个偏移量中间的消息将会丢失,既然`_consumer_offset` 如此重要,那么它的提交方式是怎样的呢?下面我们就来说一下提交方式,KafkaConsumer API 提供了多种方式来提交偏移量。
151 |
152 | ### 自动提交
153 |
154 | 最简单的方式就是让消费者自动提交偏移量。如果 enable.auto.commit 被设置为 true,那么每过 5s,消费者会自动把从 poll() 方法轮询到的最大偏移量提交上去。提交时间间隔由 auto.commit.interval.ms 控制,默认是 5s。与消费者里的其他东西一样,自动提交也是在轮询中进行的。消费者在每次轮询中会检查是否提交该偏移量了,如果是,那么就会提交从上一次轮询中返回的偏移量。
155 |
156 | ### 提交当前偏移量
157 |
158 | 把 auto.commit.offset 设置为 false,可以让应用程序决定何时提交偏移量。使用 commitSync() 提交偏移量。这个 API 会提交由 poll() 方法返回的最新偏移量,提交成功后马上返回,如果提交失败就抛出异常。
159 |
160 | commitSync() 将会提交由 poll() 返回的最新偏移量,如果处理完所有记录后要确保调用了 commitSync(),否则还是会有丢失消息的风险,如果发生了在均衡,从最近一批消息到发生在均衡之间的所有消息都将被重复处理。
161 |
162 | ### 异步提交
163 |
164 | 异步提交 commitAsync() 与同步提交 commitSync() 最大的区别在于异步提交不会进行重试,同步提交会一致进行重试。
165 |
166 | ### 同步和异步组合提交
167 |
168 | 一般情况下,针对偶尔出现的提交失败,不进行重试不会有太大的问题,因为如果提交失败是因为临时问题导致的,那么后续的提交总会有成功的。但是如果在关闭消费者或再均衡前的最后一次提交,就要确保提交成功。
169 |
170 | 因此,在消费者关闭之前一般会组合使用 commitAsync 和 commitSync 提交偏移量。
171 |
172 | ### 提交特定的偏移量
173 |
174 | 消费者 API 允许调用 commitSync() 和 commitAsync() 方法时传入希望提交的 partition 和 offset 的 map,即提交特定的偏移量。
175 |
--------------------------------------------------------------------------------
/03~Kafka/消息生产与消费/生产者.md:
--------------------------------------------------------------------------------
1 | # Kafka Producer
2 |
3 | 在 Kafka 中,我们把产生消息的那一方称为生产者,比如登录电商网站的时候,你的登陆信息,登陆次数都会作为消息传输到 Kafka 后台,当你浏览购物的时候,你的浏览信息,你的搜索指数,你的购物爱好都会作为一个个消息传递给 Kafka 后台,然后系统会根据你的爱好做智能推荐。
4 |
5 | 
6 |
7 | Kafka 中的生产者设计主要考虑了以下方面:
8 |
9 | - 负载均衡:由于消息 topic 由多个 partition 组成,且 partition 会均衡分布到不同 broker 上,因此,为了有效利用 broker 集群的性能,提高消息的吞吐量,producer 可以通过随机或者 hash 等方式,将消息平均发送到多个 partition 上,以实现负载均衡。
10 |
11 | - 批量发送:是提高消息吞吐量重要的方式,Producer 端可以在内存中合并多条消息后,以一次请求的方式发送了批量的消息给 broker,从而大大减少 broker 存储消息的 IO 操作次数。但也一定程度上影响了消息的实时性,相当于以时延代价,换取更好的吞吐量。
12 |
13 | # 创建 Kafka 生产者
14 |
15 | 要向 Kafka 写入消息,首先需要创建一个生产者对象,并设置一些属性。Kafka 生产者有 3 个必选的属性:
16 |
17 | - bootstrap.servers:该属性指定 broker 的地址清单,地址的格式为 host:port。清单里不需要包含所有的 broker 地址,生产者会从给定的 broker 里查找到其他的 broker 信息。不过建议至少要提供两个 broker 信息,一旦其中一个宕机,生产者仍然能够连接到集群上。
18 |
19 | - key.serializer:broker 需要接收到序列化之后的 key/value 值,所以生产者发送的消息需要经过序列化之后才传递给 Kafka Broker。生产者需要知道采用何种方式把 Java 对象转换为字节数组。key.serializer 必须被设置为一个实现了 org.apache.kafka.common.serialization.Serializer 接口的类,生产者会使用这个类把键对象序列化为字节数组。这里拓展一下 Serializer 类,Serializer 是一个接口,它表示类将会采用何种方式序列化,它的作用是把对象转换为字节,实现了 Serializer 接口的类主要有 ByteArraySerializer、StringSerializer、IntegerSerializer ,其中 ByteArraySerialize 是 Kafka 默认使用的序列化器,其他的序列化器还有很多,你可以通过 这里 查看其他序列化器。要注意的一点:key.serializer 是必须要设置的,即使你打算只发送值的内容。
20 |
21 | - value.serializer:与 key.serializer 一样,value.serializer 指定的类会将值序列化。
22 |
23 | 下面代码演示了如何创建一个 Kafka 生产者,这里只指定了必要的属性,其他使用默认的配置
24 |
25 | ```java
26 | private Properties properties = new Properties();
27 | properties.put("bootstrap.servers","broker1:9092,broker2:9092");
28 | properties.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
29 | properties.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
30 | properties = new KafkaProducer(properties);
31 | ```
32 |
33 | # Kafka 消息发送
34 |
35 | 实例化生产者对象后,接下来就可以开始发送消息了,我们从创建一个 ProducerRecord 对象开始,ProducerRecord 是 Kafka 中的一个核心类,它代表了一组 Kafka 需要发送的 key/value 键值对,它由记录要发送到的主题名称(Topic Name),可选的分区号(Partition Number)以及可选的键值对构成。在发送 ProducerRecord 时,我们需要将键值对对象由序列化器转换为字节数组,这样它们才能够在网络上传输。然后消息到达了分区器。
36 |
37 | 
38 |
39 | 如果发送过程中指定了有效的分区号,那么在发送记录时将使用该分区。如果发送过程中未指定分区,则将使用 key 的 hash 函数映射指定一个分区。如果发送的过程中既没有分区号也没有,则将以循环的方式分配一个分区。选好分区后,生产者就知道向哪个主题和分区发送数据了。ProducerRecord 还有关联的时间戳,如果用户没有提供时间戳,那么生产者将会在记录中使用当前的时间作为时间戳。Kafka 最终使用的时间戳取决于 topic 主题配置的时间戳类型。
40 |
41 | - 如果将主题配置为使用 CreateTime,则生产者记录中的时间戳将由 broker 使用。
42 | - 如果将主题配置为使用 LogAppendTime,则生产者记录中的时间戳在将消息添加到其日志中时,将由 broker 重写。
43 |
44 | 然后,这条消息被存放在一个记录批次里,这个批次里的所有消息会被发送到相同的主题和分区上。由一个独立的线程负责把它们发到 Kafka Broker 上。Kafka Broker 在收到消息时会返回一个响应,如果写入成功,会返回一个 RecordMetaData 对象,它包含了主题和分区信息,以及记录在分区里的偏移量,上面两种的时间戳类型也会返回给用户。如果写入失败,会返回一个错误。生产者在收到错误之后会尝试重新发送消息,几次之后如果还是失败的话,就返回错误消息。
45 |
46 | ## 简单消息发送
47 |
48 | Kafka 最简单的消息发送如下:
49 |
50 | ```java
51 | ProducerRecord record = new ProducerRecord("CustomerCountry","West","France");
52 | producer.send(record);
53 | ```
54 |
55 | 代码中生产者(producer)的 send() 方法需要把 ProducerRecord 的对象作为参数进行发送,ProducerRecord 有很多构造函数,这个我们下面讨论,这里调用的是:
56 |
57 | ```java
58 | public ProducerRecord(String topic, K key, V value) {}
59 | ```
60 |
61 | 这个构造函数,需要传递的是 topic 主题,key 和 value。把对应的参数传递完成后,生产者调用 send() 方法发送消息(ProducerRecord 对象)。我们可以从生产者的架构图中看出,消息是先被写入分区中的缓冲区中,然后分批次发送给 Kafka Broker。
62 |
63 | 
64 |
65 | 发送成功后,send() 方法会返回一个 Future(java.util.concurrent) 对象,Future 对象的类型是 RecordMetadata 类型,我们上面这段代码没有考虑返回值,所以没有生成对应的 Future 对象,所以没有办法知道消息是否发送成功。如果不是很重要的信息或者对结果不会产生影响的信息,可以使用这种方式进行发送。我们可以忽略发送消息时可能发生的错误或者在服务器端可能发生的错误,但在消息发送之前,生产者还可能发生其他的异常。这些异常有可能是 SerializationException(序列化失败),BufferedExhaustedException 或 TimeoutException(说明缓冲区已满),又或是 InterruptedException(说明发送线程被中断)。
66 |
67 | ## 同步发送消息
68 |
69 | 第二种消息发送机制如下所示:
70 |
71 | ```java
72 | ProducerRecord record = new ProducerRecord("CustomerCountry","West","France");
73 | try {
74 | RecordMetadata recordMetadata = producer.send(record).get();
75 | }catch(Exception e){
76 | e.printStackTrace();
77 | }
78 | ```
79 |
80 | 这种发送消息的方式较上面的发送方式有了改进,首先调用 send() 方法,然后再调用 get() 方法等待 Kafka 响应。如果服务器返回错误,get() 方法会抛出异常,如果没有发生错误,我们会得到 RecordMetadata 对象,可以用它来查看消息记录。
81 |
82 | 生产者(KafkaProducer)在发送的过程中会出现两类错误:其中一类是重试错误,这类错误可以通过重发消息来解决。比如连接的错误,可以通过再次建立连接来解决;无主错误则可以通过重新为分区选举首领来解决。KafkaProducer 被配置为自动重试,如果多次重试后仍无法解决问题,则会抛出重试异常。另一类错误是无法通过重试来解决的,比如消息过大对于这类错误,KafkaProducer 不会进行重试,直接抛出异常。
83 |
84 | ## 异步发送消息
85 |
86 | 同步发送消息都有个问题,那就是同一时间只能有一个消息在发送,这会造成许多消息无法直接发送,造成消息滞后,无法发挥效益最大化。比如消息在应用程序和 Kafka 集群之间一个来回需要 10ms。如果发送完每个消息后都等待响应的话,那么发送 100 个消息需要 1 秒,但是如果是异步方式的话,发送 100 条消息所需要的时间就会少很多很多。大多数时候,虽然 Kafka 会返回 RecordMetadata 消息,但是我们并不需要等待响应。
87 |
88 | 为了在异步发送消息的同时能够对异常情况进行处理,生产者提供了回掉支持。下面是回调的一个例子:
89 |
90 | ```java
91 | ProducerRecord < String, String > producerRecord = new ProducerRecord < String, String > ("CustomerCountry", "Huston", "America");
92 | producer.send(producerRecord, new DemoProducerCallBack());
93 |
94 | class DemoProducerCallBack implements Callback {
95 | public void onCompletion(RecordMetadata metadata, Exception exception) {
96 | if (exception != null) {
97 | exception.printStackTrace();;
98 | }
99 | }
100 | }
101 | ```
102 |
103 | 首先实现回调需要定义一个实现了 org.apache.kafka.clients.producer.Callback 的类,这个接口只有一个 onCompletion 方法。如果 kafka 返回一个错误,onCompletion 方法会抛出一个非空(non null)异常,这里我们只是简单的把它打印出来,如果是生产环境需要更详细的处理,然后在 send() 方法发送的时候传递一个 Callback 回调的对象。
104 |
105 | # 生产者分区机制
106 |
107 | Kafka 对于数据的读写是以分区为粒度的,分区可以分布在多个主机(Broker)中,这样每个节点能够实现独立的数据写入和读取,并且能够通过增加新的节点来增加 Kafka 集群的吞吐量,通过分区部署在多个 Broker 来实现负载均衡的效果。上面我们介绍了生产者的发送方式有三种:不管结果如何直接发送、发送并返回结果、发送并回调。由于消息是存在主题(topic)的分区(partition)中的,所以当 Producer 生产者发送产生一条消息发给 topic 的时候,你如何判断这条消息会存在哪个分区中呢?
108 |
109 | 这其实就设计到 Kafka 的分区机制了。
110 |
111 | ## 分区策略
112 |
113 | Kafka 的分区策略指的就是将生产者发送到哪个分区的算法。Kafka 为我们提供了默认的分区策略,同时它也支持你自定义分区策略。如果要自定义分区策略的话,你需要显示配置生产者端的参数 Partitioner.class,我们可以看一下这个类它位于 org.apache.kafka.clients.producer 包下:
114 |
115 | ```java
116 | public interface Partitioner extends Configurable, Closeable {
117 | public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
118 | public void close();
119 | default public void onNewBatch(String topic, Cluster cluster, int prevPartition) {}
120 | }
121 | ```
122 |
123 | Partitioner 类有三个方法,分别来解释一下
124 |
125 | - partition(): 这个类有几个参数: topic,表示需要传递的主题;key 表示消息中的键值;keyBytes 表示分区中序列化过后的 key,byte 数组的形式传递;value 表示消息的 value 值;valueBytes 表示分区中序列化后的值数组;cluster 表示当前集群的原数据。Kafka 给你这么多信息,就是希望让你能够充分地利用这些信息对消息进行分区,计算出它要被发送到哪个分区中。
126 | - close() : 继承了 Closeable 接口能够实现 close() 方法,在分区关闭时调用。
127 | - onNewBatch(): 表示通知分区程序用来创建新的批次
128 |
129 | 其中与分区策略息息相关的就是 partition() 方法了。
130 |
131 | ## 顺序轮询
132 |
133 | 顺序分配,消息是均匀的分配给每个 partition,即每个分区存储一次消息。
134 |
135 | 
136 |
137 | 上图表示的就是轮询策略,轮训策略是 Kafka Producer 提供的默认策略,如果你不使用指定的轮训策略的话,Kafka 默认会使用顺序轮训策略的方式。
138 |
139 | ## 随机轮询
140 |
141 | 随机轮询简而言之就是随机的向 partition 中保存消息,如下图所示。
142 |
143 | 
144 |
145 | 实现随机分配的代码只需要两行,如下:
146 |
147 | ```java
148 | List < PartitionInfo > partitions = cluster.partitionsForTopic(topic);
149 | return ThreadLocalRandom.current().nextInt(partitions.size());
150 | ```
151 |
152 | 先计算出该主题总的分区数,然后随机地返回一个小于它的正整数。本质上看随机策略也是力求将数据均匀地打散到各个分区,但从实际表现来看,它要逊于轮询策略,所以如果追求数据的均匀分布,还是使用轮询策略比较好。事实上,随机策略是老版本生产者使用的分区策略,在新版本中已经改为轮询了。
153 |
154 | ## 按照 key 进行消息保存
155 |
156 | 这个策略也叫做 key-ordering 策略,Kafka 中每条消息都会有自己的 key,一旦消息被定义了 Key,那么你就可以保证同一个 Key 的所有消息都进入到相同的分区里面,由于每个分区下的消息处理都是有顺序的,故这个策略被称为按消息键保序策略,如下图所示。
157 |
158 | 
159 |
160 | 实现这个策略的 partition 方法同样简单,只需要下面两行代码即可:
161 |
162 | ```java
163 | List < PartitionInfo > partitions = cluster.partitionsForTopic(topic);
164 | return Math.abs(key.hashCode()) % partitions.size();
165 | ```
166 |
167 | 上面这几种分区策略都是比较基础的策略,除此之外,你还可以自定义分区策略。
168 |
169 | # 生产者压缩机制
170 |
171 | 压缩一词简单来讲就是一种互换思想,它是一种经典的用 CPU 时间去换磁盘空间或者 I/O 传输量的思想,希望以较小的 CPU 开销带来更少的磁盘占用或更少的网络 I/O 传输。Kafka 的消息分为两层:消息集合 和 消息。一个消息集合中包含若干条日志项,而日志项才是真正封装消息的地方。Kafka 底层的消息日志由一系列消息集合日志项组成。Kafka 通常不会直接操作具体的一条条消息,它总是在消息集合这个层面上进行写入操作。
172 |
173 | 在 Kafka 中,压缩会发生在两个地方:Kafka Producer 和 Kafka Consumer,为什么启用压缩?说白了就是消息太大,需要变小一点 来使消息发的更快一些。Kafka Producer 中使用 compression.type 来开启压缩
174 |
175 | ```java
176 | private Properties properties = new Properties();
177 | properties.put("bootstrap.servers", "192.168.1.9:9092");
178 | properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
179 | properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
180 | properties.put("compression.type", "gzip");
181 | Producer < String, String > producer = new KafkaProducer < String, String > (properties);
182 | ProducerRecord < String, String > record = new ProducerRecord < String, String > ("CustomerCountry", "Precision Products", "France");
183 | ```
184 |
185 | 上面代码表明该 Producer 的压缩算法使用的是 GZIP
186 |
--------------------------------------------------------------------------------
/header.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
2 | Public License
3 |
4 | wx-chevalier 王下邀月熊 王下邀月熊
5 |
6 | By exercising the Licensed Rights (defined below), You accept and agree
7 | to be bound by the terms and conditions of this Creative Commons
8 | Attribution-NonCommercial-ShareAlike 4.0 International Public License
9 | ("Public License"). To the extent this Public License may be
10 | interpreted as a contract, You are granted the Licensed Rights in
11 | consideration of Your acceptance of these terms and conditions, and the
12 | Licensor grants You such rights in consideration of benefits the
13 | Licensor receives from making the Licensed Material available under
14 | these terms and conditions.
15 |
16 |
17 | Section 1 -- Definitions.
18 |
19 | a. Adapted Material means material subject to Copyright and Similar
20 | Rights that is derived from or based upon the Licensed Material
21 | and in which the Licensed Material is translated, altered,
22 | arranged, transformed, or otherwise modified in a manner requiring
23 | permission under the Copyright and Similar Rights held by the
24 | Licensor. For purposes of this Public License, where the Licensed
25 | Material is a musical work, performance, or sound recording,
26 | Adapted Material is always produced where the Licensed Material is
27 | synched in timed relation with a moving image.
28 |
29 | b. Adapter's License means the license You apply to Your Copyright
30 | and Similar Rights in Your contributions to Adapted Material in
31 | accordance with the terms and conditions of this Public License.
32 |
33 | c. BY-NC-SA Compatible License means a license listed at
34 | creativecommons.org/compatiblelicenses, approved by Creative
35 | Commons as essentially the equivalent of this Public License.
36 |
37 | d. Copyright and Similar Rights means copyright and/or similar rights
38 | closely related to copyright including, without limitation,
39 | performance, broadcast, sound recording, and Sui Generis Database
40 | Rights, without regard to how the rights are labeled or
41 | categorized. For purposes of this Public License, the rights
42 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
43 | Rights.
44 |
45 | e. Effective Technological Measures means those measures that, in the
46 | absence of proper authority, may not be circumvented under laws
47 | fulfilling obligations under Article 11 of the WIPO Copyright
48 | Treaty adopted on December 20, 1996, and/or similar international
49 | agreements.
50 |
51 | f. Exceptions and Limitations means fair use, fair dealing, and/or
52 | any other exception or limitation to Copyright and Similar Rights
53 | that applies to Your use of the Licensed Material.
54 |
55 | g. License Elements means the license attributes listed in the name
56 | of a Creative Commons Public License. The License Elements of this
57 | Public License are Attribution, NonCommercial, and ShareAlike.
58 |
59 | h. Licensed Material means the artistic or literary work, database,
60 | or other material to which the Licensor applied this Public
61 | License.
62 |
63 | i. Licensed Rights means the rights granted to You subject to the
64 | terms and conditions of this Public License, which are limited to
65 | all Copyright and Similar Rights that apply to Your use of the
66 | Licensed Material and that the Licensor has authority to license.
67 |
68 | j. Licensor means the individual(s) or entity(ies) granting rights
69 | under this Public License.
70 |
71 | k. NonCommercial means not primarily intended for or directed towards
72 | commercial advantage or monetary compensation. For purposes of
73 | this Public License, the exchange of the Licensed Material for
74 | other material subject to Copyright and Similar Rights by digital
75 | file-sharing or similar means is NonCommercial provided there is
76 | no payment of monetary compensation in connection with the
77 | exchange.
78 |
79 | l. Share means to provide material to the public by any means or
80 | process that requires permission under the Licensed Rights, such
81 | as reproduction, public display, public performance, distribution,
82 | dissemination, communication, or importation, and to make material
83 | available to the public including in ways that members of the
84 | public may access the material from a place and at a time
85 | individually chosen by them.
86 |
87 | m. Sui Generis Database Rights means rights other than copyright
88 | resulting from Directive 96/9/EC of the European Parliament and of
89 | the Council of 11 March 1996 on the legal protection of databases,
90 | as amended and/or succeeded, as well as other essentially
91 | equivalent rights anywhere in the world.
92 |
93 | n. You means the individual or entity exercising the Licensed Rights
94 | under this Public License. Your has a corresponding meaning.
95 |
96 |
97 | Section 2 -- Scope.
98 |
99 | a. License grant.
100 |
101 | 1. Subject to the terms and conditions of this Public License,
102 | the Licensor hereby grants You a worldwide, royalty-free,
103 | non-sublicensable, non-exclusive, irrevocable license to
104 | exercise the Licensed Rights in the Licensed Material to:
105 |
106 | a. reproduce and Share the Licensed Material, in whole or
107 | in part, for NonCommercial purposes only; and
108 |
109 | b. produce, reproduce, and Share Adapted Material for
110 | NonCommercial purposes only.
111 |
112 | 2. Exceptions and Limitations. For the avoidance of doubt, where
113 | Exceptions and Limitations apply to Your use, this Public
114 | License does not apply, and You do not need to comply with
115 | its terms and conditions.
116 |
117 | 3. Term. The term of this Public License is specified in Section
118 | 6(a).
119 |
120 | 4. Media and formats; technical modifications allowed. The
121 | Licensor authorizes You to exercise the Licensed Rights in
122 | all media and formats whether now known or hereafter created,
123 | and to make technical modifications necessary to do so. The
124 | Licensor waives and/or agrees not to assert any right or
125 | authority to forbid You from making technical modifications
126 | necessary to exercise the Licensed Rights, including
127 | technical modifications necessary to circumvent Effective
128 | Technological Measures. For purposes of this Public License,
129 | simply making modifications authorized by this Section 2(a)
130 | (4) never produces Adapted Material.
131 |
132 | 5. Downstream recipients.
133 |
134 | a. Offer from the Licensor -- Licensed Material. Every
135 | recipient of the Licensed Material automatically
136 | receives an offer from the Licensor to exercise the
137 | Licensed Rights under the terms and conditions of this
138 | Public License.
139 |
140 | b. Additional offer from the Licensor -- Adapted Material.
141 | Every recipient of Adapted Material from You
142 | automatically receives an offer from the Licensor to
143 | exercise the Licensed Rights in the Adapted Material
144 | under the conditions of the Adapter's License You apply.
145 |
146 | c. No downstream restrictions. You may not offer or impose
147 | any additional or different terms or conditions on, or
148 | apply any Effective Technological Measures to, the
149 | Licensed Material if doing so restricts exercise of the
150 | Licensed Rights by any recipient of the Licensed
151 | Material.
152 |
153 | 6. No endorsement. Nothing in this Public License constitutes or
154 | may be construed as permission to assert or imply that You
155 | are, or that Your use of the Licensed Material is, connected
156 | with, or sponsored, endorsed, or granted official status by,
157 | the Licensor or others designated to receive attribution as
158 | provided in Section 3(a)(1)(A)(i).
159 |
160 | b. Other rights.
161 |
162 | 1. Moral rights, such as the right of integrity, are not
163 | licensed under this Public License, nor are publicity,
164 | privacy, and/or other similar personality rights; however, to
165 | the extent possible, the Licensor waives and/or agrees not to
166 | assert any such rights held by the Licensor to the limited
167 | extent necessary to allow You to exercise the Licensed
168 | Rights, but not otherwise.
169 |
170 | 2. Patent and trademark rights are not licensed under this
171 | Public License.
172 |
173 | 3. To the extent possible, the Licensor waives any right to
174 | collect royalties from You for the exercise of the Licensed
175 | Rights, whether directly or through a collecting society
176 | under any voluntary or waivable statutory or compulsory
177 | licensing scheme. In all other cases the Licensor expressly
178 | reserves any right to collect such royalties, including when
179 | the Licensed Material is used other than for NonCommercial
180 | purposes.
181 |
182 |
183 | Section 3 -- License Conditions.
184 |
185 | Your exercise of the Licensed Rights is expressly made subject to the
186 | following conditions.
187 |
188 | a. Attribution.
189 |
190 | 1. If You Share the Licensed Material (including in modified
191 | form), You must:
192 |
193 | a. retain the following if it is supplied by the Licensor
194 | with the Licensed Material:
195 |
196 | i. identification of the creator(s) of the Licensed
197 | Material and any others designated to receive
198 | attribution, in any reasonable manner requested by
199 | the Licensor (including by pseudonym if
200 | designated);
201 |
202 | ii. a copyright notice;
203 |
204 | iii. a notice that refers to this Public License;
205 |
206 | iv. a notice that refers to the disclaimer of
207 | warranties;
208 |
209 | v. a URI or hyperlink to the Licensed Material to the
210 | extent reasonably practicable;
211 |
212 | b. indicate if You modified the Licensed Material and
213 | retain an indication of any previous modifications; and
214 |
215 | c. indicate the Licensed Material is licensed under this
216 | Public License, and include the text of, or the URI or
217 | hyperlink to, this Public License.
218 |
219 | 2. You may satisfy the conditions in Section 3(a)(1) in any
220 | reasonable manner based on the medium, means, and context in
221 | which You Share the Licensed Material. For example, it may be
222 | reasonable to satisfy the conditions by providing a URI or
223 | hyperlink to a resource that includes the required
224 | information.
225 | 3. If requested by the Licensor, You must remove any of the
226 | information required by Section 3(a)(1)(A) to the extent
227 | reasonably practicable.
228 |
229 | b. ShareAlike.
230 |
231 | In addition to the conditions in Section 3(a), if You Share
232 | Adapted Material You produce, the following conditions also apply.
233 |
234 | 1. The Adapter's License You apply must be a Creative Commons
235 | license with the same License Elements, this version or
236 | later, or a BY-NC-SA Compatible License.
237 |
238 | 2. You must include the text of, or the URI or hyperlink to, the
239 | Adapter's License You apply. You may satisfy this condition
240 | in any reasonable manner based on the medium, means, and
241 | context in which You Share Adapted Material.
242 |
243 | 3. You may not offer or impose any additional or different terms
244 | or conditions on, or apply any Effective Technological
245 | Measures to, Adapted Material that restrict exercise of the
246 | rights granted under the Adapter's License You apply.
247 |
248 |
249 | Section 4 -- Sui Generis Database Rights.
250 |
251 | Where the Licensed Rights include Sui Generis Database Rights that
252 | apply to Your use of the Licensed Material:
253 |
254 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
255 | to extract, reuse, reproduce, and Share all or a substantial
256 | portion of the contents of the database for NonCommercial purposes
257 | only;
258 |
259 | b. if You include all or a substantial portion of the database
260 | contents in a database in which You have Sui Generis Database
261 | Rights, then the database in which You have Sui Generis Database
262 | Rights (but not its individual contents) is Adapted Material,
263 | including for purposes of Section 3(b); and
264 |
265 | c. You must comply with the conditions in Section 3(a) if You Share
266 | all or a substantial portion of the contents of the database.
267 |
268 | For the avoidance of doubt, this Section 4 supplements and does not
269 | replace Your obligations under this Public License where the Licensed
270 | Rights include other Copyright and Similar Rights.
271 |
272 |
273 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
274 |
275 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
276 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
277 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
278 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
279 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
280 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
281 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
282 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
283 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
284 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
285 |
286 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
287 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
288 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
289 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
290 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
291 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
292 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
293 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
294 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
295 |
296 | c. The disclaimer of warranties and limitation of liability provided
297 | above shall be interpreted in a manner that, to the extent
298 | possible, most closely approximates an absolute disclaimer and
299 | waiver of all liability.
300 |
301 |
302 | Section 6 -- Term and Termination.
303 |
304 | a. This Public License applies for the term of the Copyright and
305 | Similar Rights licensed here. However, if You fail to comply with
306 | this Public License, then Your rights under this Public License
307 | terminate automatically.
308 |
309 | b. Where Your right to use the Licensed Material has terminated under
310 | Section 6(a), it reinstates:
311 |
312 | 1. automatically as of the date the violation is cured, provided
313 | it is cured within 30 days of Your discovery of the
314 | violation; or
315 |
316 | 2. upon express reinstatement by the Licensor.
317 |
318 | For the avoidance of doubt, this Section 6(b) does not affect any
319 | right the Licensor may have to seek remedies for Your violations
320 | of this Public License.
321 |
322 | c. For the avoidance of doubt, the Licensor may also offer the
323 | Licensed Material under separate terms or conditions or stop
324 | distributing the Licensed Material at any time; however, doing so
325 | will not terminate this Public License.
326 |
327 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
328 | License.
329 |
330 |
331 | Section 7 -- Other Terms and Conditions.
332 |
333 | a. The Licensor shall not be bound by any additional or different
334 | terms or conditions communicated by You unless expressly agreed.
335 |
336 | b. Any arrangements, understandings, or agreements regarding the
337 | Licensed Material not stated herein are separate from and
338 | independent of the terms and conditions of this Public License.
339 |
340 |
341 | Section 8 -- Interpretation.
342 |
343 | a. For the avoidance of doubt, this Public License does not, and
344 | shall not be interpreted to, reduce, limit, restrict, or impose
345 | conditions on any use of the Licensed Material that could lawfully
346 | be made without permission under this Public License.
347 |
348 | b. To the extent possible, if any provision of this Public License is
349 | deemed unenforceable, it shall be automatically reformed to the
350 | minimum extent necessary to make it enforceable. If the provision
351 | cannot be reformed, it shall be severed from this Public License
352 | without affecting the enforceability of the remaining terms and
353 | conditions.
354 |
355 | c. No term or condition of this Public License will be waived and no
356 | failure to comply consented to unless expressly agreed to by the
357 | Licensor.
358 |
359 | d. Nothing in this Public License constitutes or may be interpreted
360 | as a limitation upon, or waiver of, any privileges and immunities
361 | that apply to the Licensor or You, including from the legal
362 | processes of any jurisdiction or authority.
--------------------------------------------------------------------------------