1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-20 22:17:09 +08:00

Merge pull request #3 from Snailclimb/master

更新
This commit is contained in:
RyzeZhao 2019-10-14 22:02:44 +08:00 committed by GitHub
commit fbf80476b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 365 additions and 4 deletions

View File

@ -190,6 +190,7 @@
- [消息队列总结](docs/system-design/data-communication/message-queue.md) - [消息队列总结](docs/system-design/data-communication/message-queue.md)
- [RabbitMQ 入门](docs/system-design/data-communication/rabbitmq.md) - [RabbitMQ 入门](docs/system-design/data-communication/rabbitmq.md)
- [RocketMQ的几个简单问题与答案](docs/system-design/data-communication/RocketMQ-Questions.md) - [RocketMQ的几个简单问题与答案](docs/system-design/data-communication/RocketMQ-Questions.md)
- [Kafka入门看这一篇就够了](docs/system-design/data-communication/Kafka入门看这一篇就够了.md)
- [Kafka系统设计开篇-面试看这篇就够了](docs/system-design/data-communication/Kafka系统设计开篇-面试看这篇就够了.md) - [Kafka系统设计开篇-面试看这篇就够了](docs/system-design/data-communication/Kafka系统设计开篇-面试看这篇就够了.md)
### 网站架构 ### 网站架构
@ -241,8 +242,7 @@
### 实战项目推荐 ### 实战项目推荐
- [onemall](https://github.com/YunaiV/onemall) : mall 商城,基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。 - [Github 上热门的 Spring Boot 项目实战推荐](docs/data/spring-boot-practical-projects.md)
-
### Github 历史榜单 ### Github 历史榜单

View File

@ -8,3 +8,6 @@
[GitHub](<https://github.com/Snailclimb/JavaGuide>) [GitHub](<https://github.com/Snailclimb/JavaGuide>)
[开始阅读](#java) [开始阅读](#java)
![](./media/pictures/rostyslav-savchyn-5joK905gcGc-unsplash.jpg)

View File

@ -27,6 +27,7 @@
- [《Java 核心技术卷 1+卷 2》](https://book.douban.com/subject/25762168/)(推荐): 很棒的两本书,建议有点 Java 基础之后再读,介绍的还是比较深入的,非常推荐。这两本书我一般也会用来巩固知识点,是两本适合放在自己身边的好书。 - [《Java 核心技术卷 1+卷 2》](https://book.douban.com/subject/25762168/)(推荐): 很棒的两本书,建议有点 Java 基础之后再读,介绍的还是比较深入的,非常推荐。这两本书我一般也会用来巩固知识点,是两本适合放在自己身边的好书。
- [《JAVA 网络编程 第 4 版》](https://book.douban.com/subject/26259017/) 可以系统的学习一下网络的一些概念以及网络编程在 Java 中的使用。 - [《JAVA 网络编程 第 4 版》](https://book.douban.com/subject/26259017/) 可以系统的学习一下网络的一些概念以及网络编程在 Java 中的使用。
- [《Java 编程思想 (第 4 版)》](https://book.douban.com/subject/2130190/)(推荐,豆瓣评分 9.13.2K+人评价大部分人称之为Java领域的圣经但我不推荐初学者阅读有点劝退的味道。稍微有点基础后阅读更好。 - [《Java 编程思想 (第 4 版)》](https://book.douban.com/subject/2130190/)(推荐,豆瓣评分 9.13.2K+人评价大部分人称之为Java领域的圣经但我不推荐初学者阅读有点劝退的味道。稍微有点基础后阅读更好。
- [《Java性能权威指南》](https://book.douban.com/subject/26740520/)(推荐,豆瓣评分 8.20.1K+人评价O'Reilly 家族书,性能调优的入门书,我个人觉得性能调优是每个 Java 从业者必备知识,这本书的缺点就是太老了,但是这本书可以作为一个实战书,尤其是 JVM 调优!不适合初学者。前置书籍:《深入理解 Java 虚拟机》
### 并发 ### 并发
@ -93,6 +94,7 @@
- [《RabbitMQ 实战指南》](https://book.douban.com/subject/27591386/)《RabbitMQ 实战指南》从消息中间件的概念和 RabbitMQ 的历史切入,主要阐述 RabbitMQ 的安装、使用、配置、管理、运维、原理、扩展等方面的细节。如果你想浅尝 RabbitMQ 的使用,这本书是你最好的选择;如果你想深入 RabbitMQ 的原理,这本书也是你最好的选择;总之,如果你想玩转 RabbitMQ这本书一定是最值得看的书之一 - [《RabbitMQ 实战指南》](https://book.douban.com/subject/27591386/)《RabbitMQ 实战指南》从消息中间件的概念和 RabbitMQ 的历史切入,主要阐述 RabbitMQ 的安装、使用、配置、管理、运维、原理、扩展等方面的细节。如果你想浅尝 RabbitMQ 的使用,这本书是你最好的选择;如果你想深入 RabbitMQ 的原理,这本书也是你最好的选择;总之,如果你想玩转 RabbitMQ这本书一定是最值得看的书之一
- [《Spring Cloud 微服务实战》](https://book.douban.com/subject/27025912/):从时下流行的微服务架构概念出发,详细介绍了 Spring Cloud 针对微服务架构中几大核心要素的解决方案和基础组件。对于各个组件的介绍《Spring Cloud 微服务实战》主要以示例与源码结合的方式来帮助读者更好地理解这些组件的使用方法以及运行原理。同时,在介绍的过程中,还包含了作者在实践中所遇到的一些问题和解决思路,可供读者在实践中作为参考。 - [《Spring Cloud 微服务实战》](https://book.douban.com/subject/27025912/):从时下流行的微服务架构概念出发,详细介绍了 Spring Cloud 针对微服务架构中几大核心要素的解决方案和基础组件。对于各个组件的介绍《Spring Cloud 微服务实战》主要以示例与源码结合的方式来帮助读者更好地理解这些组件的使用方法以及运行原理。同时,在介绍的过程中,还包含了作者在实践中所遇到的一些问题和解决思路,可供读者在实践中作为参考。
- [《第一本 Docker 书》](https://book.douban.com/subject/26780404/)Docker 入门书籍! - [《第一本 Docker 书》](https://book.douban.com/subject/26780404/)Docker 入门书籍!
- [《Spring Boot编程思想核心篇](https://book.douban.com/subject/33390560/)(推荐,豆瓣评分 6.2SpringBoot深入书不适合初学者。书尤其的厚评分低的的理由是书某些知识过于拖沓评分高的理由是书中对SpringBoot内部原理讲解很清楚。作者小马哥Apache Dubbo PMC、Spring Cloud Alibaba项目架构师。B站作者地址https://space.bilibili.com/327910845?from=search&seid=17095917016893398636。
### 网站架构 ### 网站架构
@ -107,6 +109,7 @@
## 其他 ## 其他
- [《黑客与画家》](https://read.douban.com/ebook/387525/?dcs=subject-rec&dcm=douban&dct=2243615)这本书是硅谷创业之父Y Combinator 创始人 Paul Graham 的文集。之所以叫这个名字,是因为作者认为黑客(并非负面的那个意思)与画家有着极大的相似性,他们都是在创造,而不是完成某个任务。 - [《黑客与画家》](https://read.douban.com/ebook/387525/?dcs=subject-rec&dcm=douban&dct=2243615)这本书是硅谷创业之父Y Combinator 创始人 Paul Graham 的文集。之所以叫这个名字,是因为作者认为黑客(并非负面的那个意思)与画家有着极大的相似性,他们都是在创造,而不是完成某个任务。
- [《图解密码技术》](https://book.douban.com/subject/26265544/)(推荐,豆瓣评分 9.10.3K+人评价):本书以**图配文**的形式第一部分讲述了密码技术的历史沿革、对称密码、分组密码模式包括ECB、CBC、CFB、OFB、CTR、公钥、混合密码系统。第二部分重点介绍了认证方面的内容涉及单向散列函数、消息认证码、数字签名、证书等。第三部分讲述了密钥、随机数、PGP、SSL/TLS 以及密码技术在现实生活中的应用。关键字JWT 前置知识、区块链密码技术前置知识。属于密码知识入门书籍。

View File

@ -0,0 +1,35 @@
### mall
- **Github地址** [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
- **star**: 22.9k
- **介绍**: mall项目是一套电商系统包括前台商城系统及后台管理系统基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
### jeecg-boot
- **Github地址**[https://github.com/zhangdaiscott/jeecg-boot](https://github.com/zhangdaiscott/jeecg-boot)
- **star**: 6.4k
- **介绍**: 一款基于代码生成器的JAVA快速开发平台采用最新技术前后端分离架构SpringBoot 2.xAnt Design&VueMybatisShiroJWT。强大的代码生成器让前后端代码一键生成无需写任何代码绝对是全栈开发福音 JeecgBoot的宗旨是提高UI能力的同时,降低前后分离的开发成本JeecgBoot还独创在线开发模式No代码概念一系列在线智能开发在线配置表单、在线配置报表、在线设计流程等等。
### eladmin
- **Github地址**[https://github.com/elunez/eladmin](https://github.com/elunez/eladmin)
- **star**: 3.9k
- **介绍**: 项目基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前后端分离的后台管理系统项目采用分模块开发方式 权限控制采用 RBAC支持数据字典与数据权限管理支持一键生成前后端代码支持动态路由。
### paascloud-master
- **Github地址**[https://github.com/paascloud/paascloud-master](https://github.com/paascloud/paascloud-master)
- **star**: 5.9k
- **介绍**: spring cloud + vue + oAuth2.0全家桶实战,前后端分离模拟商城,完整的购物流程、后端运营平台,可以实现快速搭建企业级微服务项目。支持微信登录等三方登录。
### vhr
- **Github地址**[https://github.com/lenve/vhr](https://github.com/lenve/vhr)
- **star**: 10.6k
- **介绍**: 微人事是一个前后端分离的人力资源管理系统项目采用SpringBoot+Vue开发。
### One mall
- **Github地址**[https://github.com/YunaiV/onemall](https://github.com/YunaiV/onemall)
- **star**: 1.2k
- **介绍**: mall 商城,基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。

View File

@ -384,7 +384,7 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面6种
线程创建之后它将处于 **NEW新建** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY可运行** 状态。可运行状态的线程获得了 cpu 时间片timeslice后就处于 **RUNNING运行** 状态。 线程创建之后它将处于 **NEW新建** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY可运行** 状态。可运行状态的线程获得了 cpu 时间片timeslice后就处于 **RUNNING运行** 状态。
> 操作系统隐藏 Java虚拟机JVM中的 RUNNABLE 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinjava.com/)[Java Thread Life Cycle and Thread States](https://howtodoinjava.com/java/multi-threading/java-thread-life-cycle-and-thread-states/)),所以 Java 系统一般将这两个状态统称为 **RUNNABLE运行中** 状态 。 > 操作系统隐藏 Java虚拟机JVM中的 READY 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinjava.com/)[Java Thread Life Cycle and Thread States](https://howtodoinjava.com/java/multi-threading/java-thread-life-cycle-and-thread-states/)),所以 Java 系统一般将这两个状态统称为 **RUNNABLE运行中** 状态 。
![RUNNABLE-VS-RUNNING](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/RUNNABLE-VS-RUNNING.png) ![RUNNABLE-VS-RUNNING](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/RUNNABLE-VS-RUNNING.png)

View File

@ -0,0 +1,321 @@
> 本文由 JavaGuide 读者推荐JavaGuide 对文章进行了整理排版原文地址https://www.wmyskxz.com/2019/07/17/kafka-ru-men-jiu-zhe-yi-pian/ 作者:我没有三颗心脏。
# 一、Kafka 简介
------
## Kafka 创建背景
**Kafka** 是一个消息系统,原本开发自 LinkedIn用作 LinkedIn 的活动流Activity Stream和运营数据处理管道Pipeline的基础。现在它已被[多家不同类型的公司](https://cwiki.apache.org/confluence/display/KAFKA/Powered+By) 作为多种类型的数据管道和消息系统使用。
**活动流数据**是几乎所有站点在对其网站使用情况做报表时都要用到的数据中最常规的部分。活动数据包括页面访问量Page View、被查看内容方面的信息以及搜索情况等内容。这种数据通常的处理方式是先把各种活动以日志的形式写入某种文件然后周期性地对这些文件进行统计分析。**运营数据**指的是服务器的性能数据CPU、IO 使用率、请求时间、服务日志等等数据)。运营数据的统计方法种类繁多。
近年来,活动和运营数据处理已经成为了网站软件产品特性中一个至关重要的组成部分,这就需要一套稍微更加复杂的基础设施对其提供支持。
## Kafka 简介
**Kafka 是一种分布式的,基于发布 / 订阅的消息系统。**
主要设计目标如下:
- 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。
- 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输。
- 支持 Kafka Server 间的消息分区,及分布式消费,同时保证每个 Partition 内的消息顺序传输。
- 同时支持离线数据处理和实时数据处理。
- Scale out支持在线水平扩展。
## Kafka 基础概念
### 概念一:生产者与消费者
![生产者与消费者](./../../../media/pictures/kafaka/生产者和消费者.png)
对于 Kafka 来说客户端有两种基本类型:
1. **生产者Producer**
2. **消费者Consumer**
除此之外,还有用来做数据集成的 Kafka Connect API 和流式处理的 Kafka Streams 等高阶客户端但这些高阶客户端底层仍然是生产者和消费者API它们只不过是在上层做了封装。
这很容易理解生产者也称为发布者创建消息而消费者也称为订阅者负责消费or读取消息。
### 概念二主题Topic与分区Partition
![主题Topic与分区Partition](./../../../media/pictures/kafaka/主题与分区.png)
在 Kafka 中,消息以**主题Topic**来分类,每一个主题都对应一个 **「消息队列」**,这有点儿类似于数据库中的表。但是如果我们把所有同类的消息都塞入到一个“中心”队列中,势必缺少可伸缩性,无论是生产者/消费者数目的增加,还是消息数量的增加,都可能耗尽系统的性能或存储。
我们使用一个生活中的例子来说明:现在 A 城市生产的某商品需要运输到 B 城市走的是公路那么单通道的高速公路不论是在「A 城市商品增多」还是「现在 C 城市也要往 B 城市运输东西」这样的情况下都会出现「吞吐量不足」的问题。所以我们现在引入**分区Partition**的概念,类似“允许多修几条道”的方式对我们的主题完成了水平扩展。
### 概念三Broker 和集群Cluster
一个 Kafka 服务器也称为 Broker它接受生产者发送的消息并存入磁盘Broker 同时服务消费者拉取分区消息的请求,返回目前已经提交的消息。使用特定的机器硬件,一个 Broker 每秒可以处理成千上万的分区和百万量级的消息。(现在动不动就百万量级..我特地去查了一把,好像确实集群的情况下吞吐量挺高的..嗯..
若干个 Broker 组成一个集群Cluster其中集群内某个 Broker 会成为集群控制器Cluster Controller它负责管理集群包括分配分区到 Broker、监控 Broker 故障等。在集群内,一个分区由一个 Broker 负责,这个 Broker 也称为这个分区的 Leader当然一个分区可以被复制到多个 Broker 上来实现冗余,这样当存在 Broker 故障时可以将其分区重新分配到其他 Broker 来负责。下图是一个样例:
![Broker和集群](./../../../media/pictures/kafaka/Broker和集群.png)
Kafka 的一个关键性质是日志保留retention我们可以配置主题的消息保留策略譬如只保留一段时间的日志或者只保留特定大小的日志。当超过这些限制时老的消息会被删除。我们也可以针对某个主题单独设置消息过期策略这样对于不同应用可以实现个性化。
### 概念四:多集群
随着业务发展,我们往往需要多集群,通常处于下面几个原因:
- 基于数据的隔离;
- 基于安全的隔离;
- 多数据中心(容灾)
当构建多个数据中心时,往往需要实现消息互通。举个例子,假如用户修改了个人资料,那么后续的请求无论被哪个数据中心处理,这个更新需要反映出来。又或者,多个数据中心的数据需要汇总到一个总控中心来做数据分析。
上面说的分区复制冗余机制只适用于同一个 Kafka 集群内部,对于多个 Kafka 集群消息同步可以使用 Kafka 提供的 MirrorMaker 工具。本质上来说MirrorMaker 只是一个 Kafka 消费者和生产者,并使用一个队列连接起来而已。它从一个集群中消费消息,然后往另一个集群生产消息。
# 二、Kafka 的设计与实现
------
上面我们知道了 Kafka 中的一些基本概念,但作为一个成熟的「消息队列」中间件,其中有许多有意思的设计值得我们思考,下面我们简单列举一些。
## 讨论一Kafka 存储在文件系统上
是的,**您首先应该知道 Kafka 的消息是存在于文件系统之上的**。Kafka 高度依赖文件系统来存储和缓存消息,一般的人认为 “磁盘是缓慢的”,所以对这样的设计持有怀疑态度。实际上,磁盘比人们预想的快很多也慢很多,这取决于它们如何被使用;一个好的磁盘结构设计可以使之跟网络速度一样快。
现代的操作系统针对磁盘的读写已经做了一些优化方案来加快磁盘的访问速度。比如,**预读**会提前将一个比较大的磁盘快读入内存。**后写**会将很多小的逻辑写操作合并起来组合成一个大的物理写操作。并且,操作系统还会将主内存剩余的所有空闲内存空间都用作**磁盘缓存**,所有的磁盘读写操作都会经过统一的磁盘缓存(除了直接 I/O 会绕过磁盘缓存)。综合这几点优化特点,**如果是针对磁盘的顺序访问,某些情况下它可能比随机的内存访问都要快,甚至可以和网络的速度相差无几。**
**上述的 Topic 其实是逻辑上的概念,面相消费者和生产者,物理上存储的其实是 Partition**,每一个 Partition 最终对应一个目录,里面存储所有的消息和索引文件。默认情况下,每一个 Topic 在创建时如果不指定 Partition 数量时只会创建 1 个 Partition。比如我创建了一个 Topic 名字为 test ,没有指定 Partition 的数量,那么会默认创建一个 test-0 的文件夹,这里的命名规则是:`<topic_name>-<partition_id>`
![主题Topic与分区Partition](./../../../media/pictures/kafaka/kafka存在文件系统上.png)
任何发布到 Partition 的消息都会被追加到 Partition 数据文件的尾部,这样的顺序写磁盘操作让 Kafka 的效率非常高(经验证,顺序写磁盘效率比随机写内存还要高,这是 Kafka 高吞吐率的一个很重要的保证)。
每一条消息被发送到 Broker 中,会根据 Partition 规则选择被存储到哪一个 Partition。如果 Partition 规则设置的合理,所有消息可以均匀分布到不同的 Partition中。
## 讨论二Kafka 中的底层存储设计
假设我们现在 Kafka 集群只有一个 Broker我们创建 2 个 Topic 名称分别为「topic1」和「topic2」Partition 数量分别为 1、2那么我们的根目录下就会创建如下三个文件夹
```shell
| --topic1-0
| --topic2-0
| --topic2-1
```
在 Kafka 的文件存储中,同一个 Topic 下有多个不同的 Partition每个 Partition 都为一个目录,而每一个目录又被平均分配成多个大小相等的 **Segment File**Segment File 又由 index file 和 data file 组成,他们总是成对出现,后缀 “.index” 和 “.log” 分表表示 Segment 索引文件和数据文件。
现在假设我们设置每个 Segment 大小为 500 MB并启动生产者向 topic1 中写入大量数据topic1-0 文件夹中就会产生类似如下的一些文件:
```shell
| --topic1-0
| --00000000000000000000.index
| --00000000000000000000.log
| --00000000000000368769.index
| --00000000000000368769.log
| --00000000000000737337.index
| --00000000000000737337.log
| --00000000000001105814.index | --00000000000001105814.log
| --topic2-0
| --topic2-1
```
**Segment 是 Kafka 文件存储的最小单位。**Segment 文件命名规则Partition 全局的第一个 Segment 从 0 开始,后续每个 Segment 文件名为上一个 Segment 文件最后一条消息的 offset 值。数值最大为 64 位 long 大小19 位数字字符长度没有数字用0填充。如 00000000000000368769.index 和 00000000000000368769.log。
以上面的一对 Segment File 为例,说明一下索引文件和数据文件对应关系:
![索引文件和数据文件](./../../../media/pictures/kafaka/segment是kafka文件存储的最小单位.png)
其中以索引文件中元数据 `<3, 497>` 为例,依次在数据文件中表示第 3 个 message在全局 Partition 表示第 368769 + 3 = 368772 个 message以及该消息的物理偏移地址为 497。
注意该 index 文件并不是从0开始也不是每次递增1的这是因为 Kafka 采取稀疏索引存储的方式,每隔一定字节的数据建立一条索引,它减少了索引文件大小,使得能够把 index 映射到内存,降低了查询时的磁盘 IO 开销,同时也并没有给查询带来太多的时间消耗。
因为其文件名为上一个 Segment 最后一条消息的 offset ,所以当需要查找一个指定 offset 的 message 时,通过在所有 segment 的文件名中进行二分查找就能找到它归属的 segment ,再在其 index 文件中找到其对应到文件上的物理位置,就能拿出该 message 。
由于消息在 Partition 的 Segment 数据文件中是顺序读写的,且消息消费后不会删除(删除策略是针对过期的 Segment 文件),这种顺序磁盘 IO 存储设计师 Kafka 高性能很重要的原因。
> Kafka 是如何准确的知道 message 的偏移的呢?这是因为在 Kafka 定义了标准的数据存储结构,在 Partition 中的每一条 message 都包含了以下三个属性:
>
> - offset表示 message 在当前 Partition 中的偏移量,是一个逻辑上的值,唯一确定了 Partition 中的一条 message可以简单的认为是一个 id
> - MessageSize表示 message 内容 data 的大小;
> - datamessage 的具体内容
## 讨论三:生产者设计概要
当我们发送消息之前,先问几个问题:每条消息都是很关键且不能容忍丢失么?偶尔重复消息可以么?我们关注的是消息延迟还是写入消息的吞吐量?
举个例子,有一个信用卡交易处理系统,当交易发生时会发送一条消息到 Kafka另一个服务来读取消息并根据规则引擎来检查交易是否通过将结果通过 Kafka 返回。对于这样的业务,消息既不能丢失也不能重复,由于交易量大因此吞吐量需要尽可能大,延迟可以稍微高一点。
再举个例子,假如我们需要收集用户在网页上的点击数据,对于这样的场景,少量消息丢失或者重复是可以容忍的,延迟多大都不重要只要不影响用户体验,吞吐则根据实时用户数来决定。
不同的业务需要使用不同的写入方式和配置。具体的方式我们在这里不做讨论,现在先看下生产者写消息的基本流程:
![生产者设计概要](./../../../media/pictures/kafaka/生产者设计概要.png)
图片来源:[http://www.dengshenyu.com/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/11/12/kafka-producer.html](http://www.dengshenyu.com/分布式系统/2017/11/12/kafka-producer.html)
流程如下:
1. 首先我们需要创建一个ProducerRecord这个对象需要包含消息的主题topic和值value可以选择性指定一个键值key或者分区partition
2. 发送消息时生产者会对键值和值序列化成字节数组然后发送到分配器partitioner
3. 如果我们指定了分区,那么分配器返回该分区即可;否则,分配器将会基于键值来选择一个分区并返回。
4. 选择完分区后生产者知道了消息所属的主题和分区它将这条记录添加到相同主题和分区的批量消息中另一个线程负责发送这些批量消息到对应的Kafka broker。
5. 当broker接收到消息后如果成功写入则返回一个包含消息的主题、分区及位移的RecordMetadata对象否则返回异常。
6. 生产者接收到结果后,对于异常可能会进行重试。
## 讨论四:消费者设计概要
### 消费者与消费组
假设这么个场景我们从Kafka中读取消息并且进行检查最后产生结果数据。我们可以创建一个消费者实例去做这件事情但如果生产者写入消息的速度比消费者读取的速度快怎么办呢这样随着时间增长消息堆积越来越严重。对于这种场景我们需要增加多个消费者来进行水平扩展。
Kafka消费者是**消费组**的一部分当多个消费者形成一个消费组来消费主题时每个消费者会收到不同分区的消息。假设有一个T1主题该主题有4个分区同时我们有一个消费组G1这个消费组只有一个消费者C1。那么消费者C1将会收到这4个分区的消息如下所示
![生产者设计概要](./../../../media/pictures/kafaka/消费者设计概要1.png)
如果我们增加新的消费者C2到消费组G1那么每个消费者将会分别收到两个分区的消息如下所示
![生产者设计概要](./../../../media/pictures/kafaka/消费者设计概要2.png)
如果增加到4个消费者那么每个消费者将会分别收到一个分区的消息如下所示
![生产者设计概要](./../../../media/pictures/kafaka/消费者设计概要3.png)
但如果我们继续增加消费者到这个消费组,剩余的消费者将会空闲,不会收到任何消息:
![生产者设计概要](./../../../media/pictures/kafaka/消费者设计概要4.png)
总而言之,我们可以通过增加消费组的消费者来进行水平扩展提升消费能力。这也是为什么建议创建主题时使用比较多的分区数,这样可以在消费负载高的情况下增加消费者来提升性能。另外,消费者的数量不应该比分区数多,因为多出来的消费者是空闲的,没有任何帮助。
**Kafka一个很重要的特性就是只需写入一次消息可以支持任意多的应用读取这个消息。**换句话说每个应用都可以读到全量的消息。为了使得每个应用都能读到全量消息应用需要有不同的消费组。对于上面的例子假如我们新增了一个新的消费组G2而这个消费组有两个消费者那么会是这样的
![生产者设计概要](./../../../media/pictures/kafaka/消费者设计概要5.png)
在这个场景中消费组G1和消费组G2都能收到T1主题的全量消息在逻辑意义上来说它们属于不同的应用。
最后,总结起来就是:如果应用需要读取全量消息,那么请为该应用设置一个消费组;如果该应用消费能力不足,那么可以考虑在这个消费组里增加消费者。
### 消费组与分区重平衡
可以看到,当新的消费者加入消费组,它会消费一个或多个分区,而这些分区之前是由其他消费者负责的;另外,当消费者离开消费组(比如重启、宕机等)时,它所消费的分区会分配给其他分区。这种现象称为**重平衡rebalance**。重平衡是 Kafka 一个很重要的性质,这个性质保证了高可用和水平扩展。**不过也需要注意到,在重平衡期间,所有消费者都不能消费消息,因此会造成整个消费组短暂的不可用。**而且,将分区进行重平衡也会导致原来的消费者状态过期,从而导致消费者需要重新更新状态,这段期间也会降低消费性能。后面我们会讨论如何安全的进行重平衡以及如何尽可能避免。
消费者通过定期发送心跳hearbeat到一个作为组协调者group coordinator的 broker 来保持在消费组内存活。这个 broker 不是固定的,每个消费组都可能不同。当消费者拉取消息或者提交时,便会发送心跳。
如果消费者超过一定时间没有发送心跳那么它的会话session就会过期组协调者会认为该消费者已经宕机然后触发重平衡。可以看到从消费者宕机到会话过期是有一定时间的这段时间内该消费者的分区都不能进行消息消费通常情况下我们可以进行优雅关闭这样消费者会发送离开的消息到组协调者这样组协调者可以立即进行重平衡而不需要等待会话过期。
在 0.10.1 版本Kafka 对心跳机制进行了修改,将发送心跳与拉取消息进行分离,这样使得发送心跳的频率不受拉取的频率影响。另外更高版本的 Kafka 支持配置一个消费者多长时间不拉取消息但仍然保持存活这个配置可以避免活锁livelock。活锁是指应用没有故障但是由于某些原因不能进一步消费。
### Partition 与消费模型
上面提到Kafka 中一个 topic 中的消息是被打散分配在多个 Partition(分区) 中存储的, Consumer Group 在消费时需要从不同的 Partition 获取消息,那最终如何重建出 Topic 中消息的顺序呢?
答案是没有办法。Kafka 只会保证在 Partition 内消息是有序的,而不管全局的情况。
下一个问题是Partition 中的消息可以被(不同的 Consumer Group多次消费那 Partition中被消费的消息是何时删除的 Partition 又是如何知道一个 Consumer Group 当前消费的位置呢?
无论消息是否被消费,除非消息到期 Partition 从不删除消息。例如设置保留时间为 2 天,则消息发布 2 天内任何 Group 都可以消费2 天后,消息自动被删除。
Partition 会为每个 Consumer Group 保存一个偏移量,记录 Group 消费到的位置。 如下图:
![生产者设计概要](./../../../media/pictures/kafaka/Partition与消费模型.png)
### 为什么 Kafka 是 pull 模型
消费者应该向 Broker 要数据pull还是 Broker 向消费者推送数据push作为一个消息系统Kafka 遵循了传统的方式,选择由 Producer 向 broker push 消息并由 Consumer 从 broker pull 消息。一些 logging-centric system比如 Facebook 的[Scribe](https://github.com/facebookarchive/scribe)和 Cloudera 的[Flume](https://flume.apache.org/),采用 push 模式。事实上push 模式和 pull 模式各有优劣。
**push 模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。**push 模式的目标是尽可能以最快速度传递消息,但是这样很容易造成 Consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。**而 pull 模式则可以根据 Consumer 的消费能力以适当的速率消费消息。**
**对于 Kafka 而言pull 模式更合适。**pull 模式可简化 broker 的设计Consumer 可自主控制消费消息的速率,同时 Consumer 可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。
## 讨论五Kafka 如何保证可靠性
当我们讨论**可靠性**的时候,我们总会提到*保证**这个词语。可靠性保证是基础我们基于这些基础之上构建我们的应用。比如关系型数据库的可靠性保证是ACID也就是原子性Atomicity、一致性Consistency、隔离性Isolation和持久性Durability
Kafka 中的可靠性保证有如下四点:
- 对于一个分区来说它的消息是有序的。如果一个生产者向一个分区先写入消息A然后写入消息B那么消费者会先读取消息A再读取消息B。
- 当消息写入所有in-sync状态的副本后消息才会认为**已提交committed**。这里的写入有可能只是写入到文件系统的缓存不一定刷新到磁盘。生产者可以等待不同时机的确认比如等待分区主副本写入即返回后者等待所有in-sync状态副本写入才返回。
- 一旦消息已提交,那么只要有一个副本存活,数据不会丢失。
- 消费者只能读取到已提交的消息。
使用这些基础保证,我们构建一个可靠的系统,这时候需要考虑一个问题:究竟我们的应用需要多大程度的可靠性?可靠性不是无偿的,它与系统可用性、吞吐量、延迟和硬件价格息息相关,得此失彼。因此,我们往往需要做权衡,一味的追求可靠性并不实际。
> 想了解更多戳这里http://www.dengshenyu.com/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/11/21/kafka-data-delivery.html
# 三、动手搭一个 Kafka
通过上面的描述我们已经大致了解到了「Kafka」是何方神圣了现在我们开始尝试自己动手本地搭一个来实际体验一把。
## 第一步:下载 Kafka
这里以 Mac OS 为例,在安装了 Homebrew 的情况下执行下列代码:
```shell
brew install kafka
```
由于 Kafka 依赖了 Zookeeper所以在下载的时候会自动下载。
## 第二步:启动服务
我们在启动之前首先需要修改 Kafka 的监听地址和端口为 `localhost:9092`
```shell
vi /usr/local/etc/kafka/server.properties
```
然后修改成下图的样子:
![启动服务](./../../../media/pictures/kafaka/启动服务.png)
依次启动 Zookeeper 和 Kafka
```shell
brew services start zookeeper
brew services start kafka
```
然后执行下列语句来创建一个名字为 “test” 的 Topic
```shell
kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
```
我们可以通过下列的命令查看我们的 Topic 列表:
```shell
kafka-topics --list --zookeeper localhost:2181
```
## 第三步:发送消息
然后我们新建一个控制台,运行下列命令创建一个消费者关注刚才创建的 Topic
```shell
kafka-console-consumer --bootstrap-server localhost:9092 --topic test --from-beginning
```
用控制台往刚才创建的 Topic 中添加消息,并观察刚才创建的消费者窗口:
```shel
kafka-console-producer --broker-list localhost:9092 --topic test
```
能通过消费者窗口观察到正确的消息:
![发送消息](./../../../media/pictures/kafaka/发送消息.png)
# 参考资料
------
1. https://www.infoq.cn/article/kafka-analysis-part-1 - Kafka 设计解析Kafka 背景及架构介绍
2. [http://www.dengshenyu.com/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/11/06/kafka-Meet-Kafka.html](http://www.dengshenyu.com/分布式系统/2017/11/06/kafka-Meet-Kafka.html) - Kafka系列初识Kafka
3. https://lotabout.me/2018/kafka-introduction/ - Kafka 入门介绍
4. https://www.zhihu.com/question/28925721 - Kafka 中的 Topic 为什么要进行分区? - 知乎
5. https://blog.joway.io/posts/kafka-design-practice/ - Kafka 的设计与实践思考
6. [http://www.dengshenyu.com/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/11/21/kafka-data-delivery.html](http://www.dengshenyu.com/分布式系统/2017/11/21/kafka-data-delivery.html) - Kafka系列可靠的数据传输

View File

@ -16,7 +16,6 @@
name: 'JavaGuide', name: 'JavaGuide',
repo: 'https://github.com/Snailclimb/JavaGuide', repo: 'https://github.com/Snailclimb/JavaGuide',
maxLevel: 3,//最大支持渲染的标题层级 maxLevel: 3,//最大支持渲染的标题层级
homepage: 'HomePage.md',
coverpage: true,//封面,_coverpage.md coverpage: true,//封面,_coverpage.md
auto2top: true,//切换页面后是否自动跳转到页面顶部 auto2top: true,//切换页面后是否自动跳转到页面顶部
//ga: 'UA-138586553-1', //ga: 'UA-138586553-1',

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB