Java开发之消息队列
简介
- 介绍消息队列的重要性
- 介绍Java程序员常用的Kafka消息队列
- 介绍Kafka内部的一些机制及注意问题
为什么要使用消息队列?
比较常见的作用有3点,解耦、异步处理、流量削峰,这里分别一一介绍这些特点。
解耦
我们在设计微服务的时候经常会出现几个模块之间需要相互依赖,例如A和B服务相互依赖,那么部署一个A,必须部署一个B,导致A模块和B模块之间形成了强耦合。如果此时我们在A和B模块之间引入消息队列,那么A可以不用依赖B,只需要A和B之间规定通用的消息格式即可,这样A和B就解耦了,这样以后别的模块需要依赖A或B,可以对接消息队列的格式即可了,完全不用关心A和B服务到底是什么接口了,也就不依赖A和B的实现方式。
异步
例如A服务要执行一些耗时的操作并且还要处理客户请求,这是可以将耗时的操作发给消息队列,处理耗时操作的服务就可以单独去处理耗时操作,这样A服务就不用等待耗时操作完成之后才响应客户了。
流量削峰
如果服务的最高并发只能处理5000,但是偶尔瞬间的并发用户可能多于5000,这个时候可以使用消息队列将多于5000的请求缓存起来,当进程空闲出来再处理消息队列中的请求,防止高并发的用户请求压垮服务。
总结
服务解耦和异步处理应该是经常会用到的功能,至于流量削峰在一般情况下很少使用。我在项目中用到消息队列的场景很多,例如日志收集、监控指标的收集、数据同步、微服务模块之间的解耦等等。因此,在Java开发项目中可以说是消息队列无处不在,强烈建议每个Java开发必须熟悉1到2给常见的消息队列服务,并且明白其中的各个原理和特性。
Kafka消息队列
基本概念
生产者
发送数据到kafka的进程统称为生产者
消费者
消费kafka中的数据的进程统称为消费者
Topic
可以理解为一张存放队列数据的表,每一个存进来的数据都会有key和value,且没有格式限制,只要不超过规定的数据大小,基本可以存放各种类型的数据。
副本和分区
因为kafka也是高可用的,因此又引入了副本和分区的概念,每个topic的数据可以进行分区,将数据分发给不同的分区(这里有分区策略,待会细讲。),每个分区负责部分数据,每个分区内的数据按投递的顺序排列。每个分区又可以复制出多个副本,副本就可以分配给不同的节点,从而减少了热点数据都由一个节点来处理的问题。副本和分区基本上是高可用的标准配置,例如常见的HDFS、ElasticSearch、Redis等等都有这个概念,这里就不细说。
每个副本有leader与follower角色,leader负责读和写,follower只负责从leader同步过来数据,不能对外提供服务,只会存在一个leader和多个follower。当leader挂了的时候,会根据选举算法从新从follower中选择一个成为leader。
Offset
每个分区都有自己的offset,用来标识数据的位置,是一个自增的id值。每一个被写入的数据都会分配一个自增的offset值来表示位置,如图所示:
Broker
可以理解为kafka集群中的每个节点,每一个单独的节点就是一个broker,集群中的broker是通过zookeeper来协调的。
GroupId
消费组,每个组内的消费者共同消费数据,但组内的每个消费者只会消费一个特定分区,组内的消费者不会同时消费相同分区的数据。不同消费组互不干扰。每个消费组内的消费者默认会均匀的分配分区,例如某topic有p0,p1,p2,p3总共4个分区,那么消费组内分区的分配方式如下:
C1消费组只会消费P0和P3分区的数据,不会消费其他分区的数据。消费组A和消费组B之间互不干扰,C1消费了数据,并不影响C3继续消费相同数据。
常见问题
分区和副本分配策略
用分区号对broker总数取余来分配的,例如分区3个,broker2,那么有一个broker会分配到2给分区,其他broker只会分配到一个分区。如果分区数为3,broker为4,那么其中一个borker不会分配到该分区,其他broker会分配到一个分区。
副本的分配策略很简单,主要将相同分区的不同副本尽量划分给不同的borker节点,因此副本数量不要超过broker节点的数量,否则会直接抛错。
生产者分区策略
生产者产生的数据会投递到kafka中,kafka会根据响应的策略将数据投递到指定的分区中。
- 生产者指定分区:这种方式比较简单,通过配置指定分区,数据将全部投递到指定分区中。
- 默认分区器:如果存在key则将key取hash然后与分区数取余获取分区号;如果没有key,则采用粘性分区策略,也就是先随机选择一个分区,一直使用直到达到时间和容量要求,则切换其他分区,依次循环。
- 轮询策略:依次往不同的分区写入数据。
- 随机策略:随机往不同的分区写入数据。
消费者分区策略
消费者分区策略都是基于同一个消费组而言的,不同的消费组可以使用不用的策略,相互之间没有任何影响。
- 消费者指定分区:则一直消费该分区的数据。
- Range strategy 范围策略:例如有5个分区,消费组A内有2给消费组A1,A2,那么A1分配(0,1,2),A2分配(3,4);如果有4给分区,那么A1和A2都有2给分区。
再平衡 rebanlance
再平衡导致kafka需要给消费组内的所有消费组重新分配分区,发现再平衡的条件有如下几种:
- 同一个消费组内新增消费者
- 消费者离开当前所属的消费组,包括节点宕机或卡死等。
- 主题新增分区
Kafka数据清除策略
可以配置定期清除topic中的数据。
生产者数据如何确保数据已经投递成功?
消息的一致性保证是一个问题权衡的问题,没有一种方法能解决所有问题。我们可以发送一条确认一条,但是效率低;我们也可以积累一批数据再一起发送到kafka中,这又存在数据重传的问题。因此我们需要权衡数据丢失、数据投递顺序、性能问题。
- 数据顺序,如果要保证数据投递的顺序,那么只能使用一个分区,所有的数据都投递到该分区中(当然这里也可以利用数据的特性进行分区)。每个数据必须等前面的数据投递成功才能投递下一个数据,一断某一个出错,应该中断整个链路,禁止后续消息继续投递。
- 数据丢失问题
可以使用参数来控制,但是会牺牲性能,需要根据实际情况衡量,重要参数如下:
acks=0: 生产者不用等待服务器的回复,容易丢失数据。
acks=1: 生产者只需要等待leader成功回复即可,如果follower没有收到数据且切换成了leader,也存在丢失数据的可能,但比第一种情况要小很多。
acks=all: 所有副本都收到成功的回复消息,一致性高,但是延迟也高。注意,这种方式一定要结合副本来使用才安全,否则如果只有一个leader节点,也无法真正的保证消息不丢失。
retries: 生产者重试次数。
producer.type=sync/async 同步或异步投递数据
数据重复问题
使用同步模式下,基本不存在数据重复问题。总结
根据实际业务情况,调整核心参数,达到最优的解决方案,记住没有银弹能解决所有问题,这个一个取舍问题。
消费者如何确保成功消费?
重要参数:
enable.auto.commit: 是否自动提交
自动提交:默认情况,消费者每5秒自动提交一次offset。例如提交了一次offset后,此时offset=5,接下来的5秒内消费了2条数据且立马发生rebanlance,还没来得及提交offset,此时会导致这2条数据需要重新消费。
手动提交(同步):每次消费一条数据后手动提交offset,只有提交成功后才会继续消费下一条数据。这种方式可以保证正确的唯一消费数据,但是由于每消费一条数据都需要手动提交offset,在性能上可能会差一点。
手动同步提交自带重试功能,可以应付简单的网络异常情况。
手动提交(异步):异步提交不会阻塞后续的消费,由单独的进程去提交offset。异步提交也不会重试。异步提交失败,只能通过回调记录异常数据。
如何实现Exactly Once语义
如果要实现真正的exactly once的语义是很难的,这会涉及到很复杂的各种情况。如果大家想弄懂分布式后存在哪些问题,推荐书籍《数据密集型应用系统设计》,详细的讲解了分布式后存在的各种问题。为了实现exactly once可以在消费者实现幂等操作,即能容忍重复消费,这样消费者可以直接使用自动提交,提高处理性能。这种实现方式是公认的、容易实现的方式。
总结
kafka是一款比较优秀的消息队列工具,在使用之前一定要先了解各个功能特点,结合自身业务特点,有选择的设置合适的参数,从而发挥kafka优势和性能。经常听同时抱怨kafka丢失等问题,只要理解以上说的各个点,合理的设置生产者和消费者参数,不可能丢失数据的,请大家放心使用。
Java开发之消息队列相关推荐
- Java 帝国之消息队列
张家村的历史 Java 帝国的张家村正在迎来一次重大的变革. 5年前网上购物兴起的时候, 帝国非常看好, 决定向这个领域进军, 于是兴建了张家村, 在这里安装了Java 虚拟机和数据库, 然后部署了一 ...
- activimq java集成_Java消息队列-Spring整合ActiveMq
1.概述 首先和大家一起回顾一下Java 消息服务,在我之前的博客<Java消息队列-JMS概述>中,我为大家分析了: 消息服务:一个中间件,用于解决两个活多个程序之间的耦合,底层由Jav ...
- java中的消息队列
消息队列:可以看做是一个存储消息的容器,它是分布式系统中的重要组件之一. 目的是: 1.为了通过异步处理来提高系统的性能来减少系统响应的时间 一般的步骤是客户端发起请求给服务端,服务端在请求给数据库, ...
- Java笔试面试-消息队列面试题总结
1.消息队列的应用场景有哪些? 答:消息队列的应用场景如下. 应用解耦,比如,用户下单后,订单系统需要通知库存系统,假如库存系统无法访问,则订单减库存将失败,从而导致订单失败.订单系统与库存系统耦合, ...
- Java架构之消息队列 (一):消息队列的概述
消息队列系列分享大纲: 一.消息队列的概述 二.消息队列之RabbitMQ的使用 三.消息队列之Kafka的使用 四.消息队列之RabbitMQ的原理详解 五.消息队列之Kafka的原理详解 六.消息 ...
- JSD-2204-(业务逻辑开发)-续消息队列-Kafka-RabbitMQ-Day15
虚拟机镜像网盘路径 链接:百度网盘 请输入提取码 提取码:egno 618M:Virtualbox用的,纯净的RockyLinux 3.5G:VMware用的,安装好所有软件的RockyLinux 4 ...
- 消息队列如何使用java,想使用消息队列,先考虑下这些问题!,消息队列如何使用...
想使用消息队列,先考虑下这些问题!,消息队列如何使用原创:Java派(微信公众号:Java派),欢迎分享,转载请保留出处. 消息队列优势 消息队列(Message Queue,简称MQ),其主要用于在 ...
- rabbitmq java实例_RabbitMQ消息队列入门篇(环境配置+Java实例+基础概念)
转载http://blog.csdn.net/u013142781 一.消息队列使用场景或者其好处 消息队列一般是在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式 ...
- java并发包消息队列
消息队列常用于有生产者和消费者两类角色的多线程同步场景 BlockingQueue也是java.util.concurrent下的主要用来控制线程同步的工具. 主要的方法是:put.take一对阻塞存 ...
- Java redis实现消息队列
文章目录 一.单元测试Java多线程 二.redis实现消息队列 三.java多线程模拟生产者消费者 四.阻塞读 一.单元测试Java多线程 使用junit测试多线程代码,但是等到程序结束,输出结果不 ...
最新文章
- 3D演示帮你一眼看懂线性规划问题,这篇可视化教程火了
- 零基础python书籍推荐-非IT行业,零基础自学Python,选什么书?
- Maven中settings.xml的配置项说明
- bzoj 4009 接水果 整体二分
- mysql问题处理积累
- 一个程序员面试因为吸烟而被拒
- 使用Python从PDF文件中提取数据
- 百度景鲲:9月15日发布小度真无线智能耳机
- Java高级面试题!这是一份面向Java开发者的复习指南
- LuaForUnity7.1:Lua“类与对象”
- 五款实用的微信小程序(免费证件照)
- 程序员在哪能接到私单?
- 菠萝V1一经问世将会掀起怎样的惊涛骇浪?
- apache服务讲解
- 79个超强微生物知识,全力助你孕育99分超优宝宝
- 当当网畅销书排行爬虫(requests+BeautifulSoup)
- 微信小程序JS字符串操作方法汇总,包含切割截取split,合并字符串join,连接字符串concat,返回指定字符串charAt,提取字符串substring等
- 为什么没有下划线_资料1907:xumin字体打不出下划线?凌哥英语送您改进版!
- Logit Adjust
- android 5.0 自动接听电话
热门文章
- Android获取半透明属性
- 用AJAX方式上传图片文件
- 安卓h5 ajax上传图片,移动端通过ajax上传图片(文件)并在前台展示——通过H5的FormData对象...
- (轉貼) 人人有功練!! 有功夫,沒懦夫 (News)
- 基于Matlab的数字图像gui界面设计
- sdr 软件_购买软件定义无线电(SDR)还是传统无线电台?|追求欲望无止境
- 华为认证报名费是多少?如何准备华为HCIP网络工程师考试?
- 2017全国计算机二级office题库,2017年计算机二级office题库(附答案)
- 量子计算机王,王正汉|量子计算机:下一轮工业革命的引擎
- matlab 半正定规划,半正定规划