java实战场景
2023-05-19 21:24:40 0 举报
AI智能生成
java场景问题总结,数据库,缓存,消息队列,系统架构设计,系统承载能力,系统调优总结;
作者其他创作
大纲/内容
分支主题
场景类
数据库
count(*)和count(1) 谁快
1、如果是innerdb 数据库引擎
两者一样快,两者最终执行的时候语句是一样的。但是比count(列名)快
直接遍历索引来查询;
2、myisam数据库引擎
count(*)快于或者等于count(1), myisam存储了表的总行数,可以直接获取总条数;
count(1)如果是第一列不为null,也是直接可以获取总条数,如果可以为null,那么就需要统计不为空的条数
count(列名)只统计不为null的数据,需要遍历整个表
性能调优
CPU突然飙升,系统反应慢,怎么排查?
导致cpu使用率飙升的原因
1、cpu上线文切换过多
1、在同一个时刻,每个cpu核心只能运行一个线程,如果有多个线程需要执行,cpu只能是通过上线文切花的方式来执行不同的线程
cpu上下文切换做的事情
记录线程执行的状态
让处于等待中的线程执行
过多的上下文切换,占用了过多的cpu资源,导致无法去执行用户进程中的cpu指令,导致用户进程中cpu相应速度过慢
上下文切换过多的场景
1、文件io操作
2、网络io
3、锁等待
4、线程阻塞
解决方式
多查询一些线程,是否处于阻塞状态中
如果是io导致,不管是网络,还是文件,
统一给这些io设置线程池,不让他们占用过多的系统资源
2、cpu资源过度消耗
过度消耗原因
1、创建了大量线程
2、有线程一直占用cpu资源,死循环
解决方式
linux系统解决
1、通过linux系统的top命令来找到cpu利用率过高的进程
2、ps -mp 进程号
查询进程信息,查看线程
2、shirt +H来找到进程中CPU消耗过高的线程
出现两种情况
cpu消耗过高的是同一个线程
通过jsatck工具根据线程id去下载线程的dump日志,然后定位到具体的代码
cpu消耗过高的是不同的线程
说明线程创建的比较多,拿几个线程id去下载线程的dump日志,
结果1、程序正常,在cpu飙高那一刻,用户访问量增大
结果2、也有可能程序不正常,线程池的创建相关有问题。
做针对性调整
docker
docker stats
1、查看docker的cpu占用率:
docker exec -it 容器编号 /bin/bash
2、进入cpu占用高的docker容器
查看容器中具体进程cpu占用率,执行top
查看进程中线程cpu占用率:top -H -p 进程号
将异常线程号转化为16进制: printf “%x\n” 线程号
查看线程异常的日志信息:jstack 进程号|grep 16进制异常线程号 -A90
各种监控系统辅助我们排查
线上服务内存溢出如何定位排查
排查问题方式
1、先获取堆内存快照文件
1、通过设置jvm参数
让jvm发生内存溢出的时候自动生成dump文件,并且存放在某个固定路径下面
2、通过执行dump命令来获取当前jvm的内存快照
2、通过mat工具分析dump文件
dump文件分析工具
1、mat工具
专门用来分析dump文件的
2、jprpfile工具
3、解析dump文件,得到内存统计信息总览
4、点击dominator Tree
dump文件中内存占用情况
5、获取到内存占用最高的类
6、然后再查看这个类中相信的内存占用情况
根据代码的情况惊醒调整
内存
怎么计算一个对象的内存大小?
1、通过工具类计算
1、Unsafe类计算
2、使用<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency> 包下面的 RamUsageEstimator 类种的方法计算
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency> 包下面的 RamUsageEstimator 类种的方法计算
2、通过手动计算
1、计算对象实体数据
1、对象头数据,实例数据,对齐数据
2、计算数组数据
子主题
计算对象都数据,数组长度,实体数据,对齐数据
1.对象的属性;(定义多少字段,需要分配相应的字段) 如果没有字段,内存分配这个也是没有的;
2.对象头;(固定大小的12个字节,这是64位操作系统,32位系统的是4个字节)
3.对齐数据(假如一个对象的实际存储空间的数据,不是8位的整数倍,
但是需要填充空位,填充到8 的整数倍,(这个是64位的虚拟机)) 对齐数据 有时候 有,有时候没有
2.对象头;(固定大小的12个字节,这是64位操作系统,32位系统的是4个字节)
3.对齐数据(假如一个对象的实际存储空间的数据,不是8位的整数倍,
但是需要填充空位,填充到8 的整数倍,(这个是64位的虚拟机)) 对齐数据 有时候 有,有时候没有
内存溢出其他线程还能工作吗?
可以,造成堆内存的线程会被销毁,所以这个线程创建的内存对象也会被回收,
其他线程还是可以获取到充足的内存空间来支持程序运行
其他线程还是可以获取到充足的内存空间来支持程序运行
调优
大的分类
业务调优
代码复用优化
性能调优
调优层面
设计层面
设计层面优化师优化手段的上层,根据系统的难点和潜在的问题,评估设计出合理的设计方案
具体方式
缓存使用
对象池设计
常量池
连接池
线程池
IO优化,选择多路复用
消息队列根据具体业务,设置对应的确认机制
使用序列化效率高的组件
零拷贝
io多路复用
代码层面
代码层面优化方式
合理使用设计模式
单例设计模式
减少对象的创建,减少内存消耗
减少对象的频繁创建
字符串优化
字符串操作避免内存泄露
切割查找选择最快方式
容器优化
根据当前业务查询多还是修改多,合理选用对应的容器
局部变量的容器,选择对应的操作快速的线程不安全的容器
容器的初始化长度可以,根据预估的数据量
位运算替代除法操作
避免二维数组使用
减少静态方法
GC不会回收静态方法占用的元空间数据
满足业务的情况下使用基本类型替代对象
对象需要开辟堆内存,基本类型需不要堆内存
代码中减少对第三方循环调用,第三方提批量接口
合理多使用switch 语句 替代if else
合理的使用空间换时间,或者时间换空间的思想
时间复杂度,空间复杂度
降低资源竞争
锁对象使用合理
乐观锁
io操作释放对应的资源
代码中可以手动将不再使用的大对象手动回收
同步变成异步
算法优化
针对搜索时间,内存大小设计合理的数据结构
JVM层面
编译优化
可以调整减少执行次数,再进行热点编译,针对一些执行频率很高的代码,可以在前期优化时间;
cpu核数,内存调整
根据cpu数量,内存大小和各项极限指标(qps,99线,并发量)的函数关系,做适当调整
根据对内存,cpu告警信息做适当调整
数据库层面
具体方式
sql优化
1、合理设置索引
2、合理的提前生成统计数据
3、连接池优化
4、减少关联查询
库表结构优化
1、合理分库分表
2、合理冗余字段
数据硬件优化
内存更大, 磁盘更大, cpu核数更多,运算速度更快
数据库参数优化
数据库日志刷盘策略
缓冲池大小
操作系统层面
磁盘,内存,cpu,
文件最大句柄数量
会影响io多路复用
优化评定指标
95线,99线,999线
cpu时间
内存分配
磁盘吞吐量
网络吞吐量
并发量
调优前注意事项
明确调优目的,不要为了调优而调优,盲目调优可能适得其反
数据加密算法
不可逆加密
加密方式
MD5
概述
信息摘要算法5
特点
单向不可逆,无法解密
产生一个固定长度的散列码
使用场景
密码存储
信息完成性校验
HMAC系列
概述
散列消息鉴别码
特点
SHA系列
特点
单向不可逆,无法解密
产生一个固定长度的散列码
使用场景
密码存储
信息完成性校验
不可逆特点
单向不可逆,无法解密
产生一个固定长度的散列码
可逆加密
非对称加密
概述
公钥加密,私钥解密
非对称加密方式
RSA
DSA/DSS
特点
1.比对称加密更加安全可靠;
2.加密解密比对称加密慢很多
使用场景
HTTPS建立SSL连接中有一个步骤就是,将服务端的公钥加密用于对称加密的密钥;也就是把数据传输的对称加密的密钥发送给服务端,这样客户端和服务端都知道了实际做数据传输的对称密钥了
对称加密
概述
加密解密都是用的同一个密钥
对称加密方式
DES
3DES
AES
特点
1.加密解密速度快;
2.适用于大量数据加密
3.由于需要把密钥传递给需要用的对接方,在传递的密钥的过程中容易被人抓包,造成数据不安全;
场景
HTTPS建立SSL连接之后,客户端和服务端使用的就是对称加密来传输数据;主要就是利用对称加密解密速度快的优势
对称/非对称加密区别
性能
对称加密性能高于非对称加密
安全性
非对称加密安全性比对称加密安全性高
加密解密方式
对称加密,加密解密都是用的同一个密钥;非对称加密,加密解密密钥是分开的;
可逆/不可逆区别
可逆:可以通过解密的密钥获取到加密之前的数据;不可逆:数据是没有办法做解密操作,无法拿到解密之前的数据;
加密盐
作用
增加数据被破解的难度
让相同的数据在被加密之后显示的数据是不一样的;
接口幂等性
查询和修改操作都是幂等;添加和删除不是幂等
分布式环境下怎么保证接口的幂等性
幂等性概述
1.用户对于同一操作发起的一次请求或者多次请求结果都是一样。
具体操作
查询操作
天然幂等的
删除操作
删除一次和删除多次可能返回的数据不是一样
更新操作
如果把某个字段的值设置为1,那么不管多少次都是幂等
如果把某个字段值加1,那么就不是幂等
添加操作
重复提交会有幂等性问题
幂等性解决方案
1.通过代码逻辑判断实现
一般场景:代码中通过代码逻辑判断
支付场景:通过唯一的订单id来判断重复
2.使用token机制实现
支付场景:页面跳转的时候获取全局唯一的token,把token缓存起来;等到提交到后台的时候,再校验token是否存在,第一次提交成功就会删除token
使用场景:分布式环境
3.乐观锁
分布式环境中,做重复校验,直接用乐观锁实现
使用场景:分布式环境
延时任务
redis
实现方式
通过Redis的key的事件通知机制
缺点
Redis的事件通知,消息只会发送一次,不管客户端是否有收到(无消息确认机制)
使用场景
需要对某些key的改变做监控
消息队列
RocketMQ
RocketMQ设置固定延时时间发送消息
缺点
延时的消息时间只能是十几个固定的延时时间
使用场景
RabbitMQ
实现方式
1.正常队列不设置消费者,给单个消息设置超时时间;
2.设置死信队列和死信队列的消费者,把超时未发送的消息发送到死信队列;
使用场景
kafka
实现方式
时间轮定时任务
使用场景
定时任务
实现方式
先对数据先进行落库,再对数据库进行定时轮询
缺点
对数据库压力大
使用场景
java延时队列
实现方式
实现Java的延时队列,这是固定的延时时间;
高并发问题
接口限流
限流方式
验证码
使用场景
容器限流
NGINX
Tomcat
队列
手动控制某些接口访问
gateway
使用场景
服务器限流
Semaphore类控制并发访问数量
任务线程池控制方式
锁
限流算法
令牌桶
实现
使用场景
漏斗桶
实现
使用场景
滑动窗口
实现
使用场景
计数器
实现
使用场景
子主题 5
流量计算方式
滑动窗口
子主题 2
子主题 3
秒杀系统设计
秒杀系统的特点及对应解决方式
1.读多写少
缓存
2.高并发
限流
负载均衡
缓存
异步
队列
3.资源访问冲突
不同层级对应解决方案
应用层
控制方式
按钮控制
点击之后,一段时间之后才能再次被点击
验证码控制
需要收到验证码才能点击
控制目的
降低用户秒杀系统的点击频率
网络层
CDN
负载层
负载均衡,反向代理,限流
降低服务器访问压力
服务层
缓存,异步,队列,限流,原子操作
降低对数据库的压力
数据库
乐观锁,悲观锁
CDN作用
lua脚本为啥可以原子性执行
redis缓存
数据存入缓存
首页
banner
List集合
三个豆腐块
List集合
为你推荐条件
List集合
竞拍大厅
筛选条件
骨架星级
Hash表
注册地
Hash表
车龄
Hash表
里程
Hash表
车辆级别
Hash表
排放标准
Hash表
车源属性
Hash表
燃料类型
Hash表
查询条件
场次
Hash表
拍场模式
Hash表
所有品牌车系
List集合
热门品牌
Hash表
业务城市数据
List集合
查询结果集
为你推荐
通过zset排序用户出价的品牌车系;每次出价的时候异步去更新redis的记录以及数据库
心愿单
心愿单的查询条件
车源id存放在Zset缓存,从缓存中拿到车源id;再去ES中获取数据;
我的出价
一个月前未中标
车源id存放在Zset缓存,从缓存中拿到车源id;再去ES中获取数据;
近一个月未中标
车源id存放在Zset缓存,从缓存中拿到车源id;再去ES中获取数据;
交易失败
车源id存放在Zset缓存,从缓存中拿到车源id;再去ES中获取数据;
交易成功
车源id存放在Zset缓存,从缓存中拿到车源id;再去ES中获取数据;
我的账户
账户余额
String
保证金
String
出价次数
String
INCR
做自增操作
关注次数
String
INCR
做自增操作
微服务项目
模块拆分方式
1.按照不同的业务划分不同的项目
2.同一业务下不同的功能划分
Job
同一业务下的定时任务模块
获取本业务数据
直接查询属于本业务的库
直接调用本业务的原子微服务
直接调用本服务的非原子微服务
获取其他业务数据
1.调用其他原子的微服务
2.调用其他服务的非原子微服务
MQ
同一业务下消息队列模块
获取本业务数据
直接查询属于本业务的库
直接调用本业务的原子微服务
直接调用本服务的非原子微服务
获取其他业务数据
1.调用其他原子的微服务
2.调用其他服务的非原子微服务
web
同一业务下pc端接口
获取本业务数据
直接查询属于本业务的库
直接调用本业务的原子微服务
直接调用本服务的非原子微服务
获取其他业务数据
1.调用其他原子的微服务
2.调用其他服务的非原子微服务
App
同一业务下对APP接口
获取本业务数据
直接查询属于本业务的库
直接调用本业务的原子微服务
直接调用本服务的非原子微服务
获取其他业务数据
1.调用其他原子的微服务
2.调用其他服务的非原子微服务
Ms
同一业务下原子的微服务接口
Api
同一业务下非原子的微服务接口
可以聚合其他业务的原子的微服务接口
测试
接口压测
定义:测试各个逻辑是否正确
目的
更早发现问题
缩短产品周期
更早发现底层问题
负载测试
定义
逐步增加系统租在,测试系统的性能变化,并在最终满足性能指标的情况下,测试系统所能承受的最大负载测试
目的:
检测系统运行的最大上限,使系统能够在最大压力下正常运行。获取最大上限数据
方法:
不断地在单位时间内增加请求个数,直到服务器的某一个资源(cpu,内存,网络延迟,等指标)达到饱和或者临界值
系统负载指标
并发用户数
这个是最重要的指标
持续运行时间
数据量
并发测试
目的
检查系统是否有并发问题导致的内存泄露,线程锁,资源争用问题
方法
确定用户并发数,必须直到系统锁承载的在线用户数,然后在单位时间内 同事发起一定量的请求
确定用户数的方法
平均并发用户数量
login seesion 数量* session 时间 / 考察时间段
巅峰用户数量
平均并发用户数量 + 3(平均并发用户数量 开平方根)
demo
一个oa系统有3000个用户, 平均每天大约有400人访问系统, 一天之内用户从登录到退出系统平均时间4小时,一天时间内,用户只在8个小时使用该系统
平均并发用户量
400*4/8 = 200
巅峰用户数量
200+ 3(200的整数平方根)
压力测试
定义
不断给应用增加并发数量,强制让其在极限情况下运行,观察其运行到何种程度,从而发现其性能缺陷
目的
查看系统能够承受的最大并发量,达到多少的时候系统才会奔溃
方法
以负载测试,并发测试为依据,
指标
接口响应时间
接口并发数量
内存,cpu,等指标
收获
1、通过负载,并发,压力测试,可以知道系统的极限,可以更加合理的设置系统的各项告警阈值
2、核心,频繁使用的接口,不做相关的测试,贸然上线,对系统的稳定性是一个极大的考验,并不知道接口,相关的极限值,容易把系统搞崩
3、获取到相关运行数据,可以方便之后的调优
内存,cpu数量和接口响应数据,并发数所呈现的函数关系,可以方便调节系统的内存,cpu
系统承载能力评估
评估系统的承载能力
什么是承载能力
系统在各项指标比如说cpu,内存在极限状态下所能达到最大的QPS,吞吐量,并发量,用户的最小响应耗时
如何计算系统的承载能力
通过负载,并发,压力测试得到单台机器的在极限状态下的接口影响时间,并发量数量,内存,cpu,等指标信息
通过相同的机器数量可以得到该服务的总的最大并发数量
机器数量评估
系统峰值呈现28原则, 百分之80的流量会在20%的时间内到达
峰值qps= PV* 80% /(60*60*24*20%)
pv = page view 页面浏览次数
uv = unique vistor 不同用户访问数量
访问量数据
如果业务方可以给出
根据往年的数据量,做出相应的评估结合当下的数据
机器数量 = 峰值qps / (单台压测得到的极限的qps)
服务器台数,服务的硬件,核数,jvm内存设置,磁盘大小,垃圾回收怎么设置
系统当前水位评估
需要单台服务器极限下的qps
当前单台机器的qps
当前水位 = 当前所有机器的总的qps / (单台机器的极限qps *服务器数量 )
cpu使用率
正常的使用率0%-75%之间
90%及以上cpu使用过高
qps计算
qps峰值估算
二八原则估算
峰值qps= PV* 80% /(60*60*24*20%)
demo
一天有1000w点击量
1000*10000 *80% / (60*60*24*20%) = 450
峰值的qps = 450
qps估算
qps的估算需要结合接口的99线数据,已经cpu的核数,服务器个数
单个接口的qps
获取单个接口的平均响应时间,1s除以这个99线,得到1s中单个cpu的qps,乘以cpu的总核数,乘以cpu利用率80%得到单个接口的qps数值
实际情况下,因为线程之间的切换消耗cpu资源还有cpu等待,等等原因,实际的qps数量 并不会像这种线性关系;实际还需要进行压测才行
项目整体qps
每一个接口调用频率差别很大,每一个接口的相应时间也很大,根据调用频率还有响应时间得到一个综合状态的平均响应时间,然后再通过1s除以这个综合平均响应时间,再乘以80%,得到单个cpu的qps,然后再计算总得qps
实际情况下,还是需要通过压测得到对应的关系曲线
一般情况下 8核16gb的机器,qps可以达到300-400,如果使用了缓存,qps达到1000没有啥问题
吞吐量
系统在单位时间内处理请求的数量
量化指标
TPS
QPS
系统吞吐量要素
请求对cpu的消耗,外部接口,网络磁盘IO
系统并发数估算
QPS*平均响应时间
cpu核数估算
需要结合qps的峰值,以及平均响应时间
demo:
qps的峰值2000,平均响应时间50ms
2000/((1000ms/50ms)*80%)/ 4 = 2000/16 = 128核
计算中间需要加上cpu 饱和使用率 80%
实际情况下:128核 服务器,可以拆分成几个32和或者几个16核的服务器;可以做对应的服务器拆分;
服务器的台数和cpu核数估算
是密切相关的,可以根据qps数量,平均响应时间预估得到cpu总的核数,然后再根据核数可以拆分成几台对应的服务器
jvm内存预估
预先预估
根据系统的qps,每一个请求会占用多少内存,机器的选型,年轻代应该给多少,老年代给多少,对应进入老年代速度,Full gc的频率
预估完成之后,给设定一些初始的jvm参数,堆内存,栈内存,Eden,survivor比例,新生代,老年代大小,大对象阈值,大对象进入老年代的阈值
尽量让对象都保留在年轻代,不让进如老年代,减少full gc
系统压测jvm优化
根据压测环境JVM运行状况,如发现对象过快进入老年代,就需要采用之前介绍的优化思路,合理调整新生代、老年代、Eden、Survivor各个区域的内存大小,保证对象尽量留在年轻代,不要过快进入老年代。
当对压测环境下的系统优化好JVM参数之后,观察Young GC和Full GC频率都很低,此时就可部署上线
当对压测环境下的系统优化好JVM参数之后,观察Young GC和Full GC频率都很低,此时就可部署上线
监控jvm内存
天高峰、低峰期观察线上系统的JVM运行是否正常,有无频繁Full GC的问题。有就优化,没有就平时每天都定时或每周都看看
全文索引的分词,怎么保证分词搜索的准确性;是否有算法参与;
消息队列
kafka节点挂了
共性问题及解决思路
消息堆积
导致原因
消费者消费速度过慢,生产者生产速度过快
解决方式
1、检查生产者发送消息是否正常,是否有大量重复消息,或者不必要发送的消息;检查消费者消费是否正常,是否有性能瓶颈,
如果有,需要针对型处理
2、提高消费者消费速度
1、开启多线程消费
2、添加消费者服务器节点
3、批量拉取消息
4、消息消费快速入库,快速返回成功,开启后台线程去消费消息;
消费重复消费
导致原因
消费者未能提交正确的消费成功消息,或者服务端没有接受到此消息
解决方式
代码逻辑中保证幂等性,使用消息id,获取业务id来做幂等性判断;
消费丢失
消息丢失原因
生产者向服务端发送消息失败(网络原因,或者生产者异常)
kafka
消息重试机制
生产者自己异常,导致消费发送失败,生产者会有重试机制,重新发送消息
消息确认机制
消息确认等级
ACK =0
ACK=1
ACK=all
消息确认相应机制
ACK=1(默认设置),只要分区的leader副本接受到了消息,就会给生产者发送消息接受成功(其他副本再回去同步leader的数据)。
设计上是比较折中的在一定程度上能够保证消息的不丢失,也能保证一定的吞吐量
ACK=0,生产者给服务端发送消息,不等服务端是否有接收到消息,发送完了就认为消息到被服务端接受了;而实际情况是,消息会生产者的缓冲池中待一段时间然后才会被发送到服务端,生产者就不知道消息具体在啥时候发送到服务端;
缺点:网络宕机的时候,消息会丢失
优点:满足大吞吐量的数据发送;
ACK=all,消息的分区leader还有所有的副本都接受到消息,才会给生产者发送消息已经被接受了。
优点:最大程度上保证服务器节点接受到消息;
缺点:极度影响性能,导致数据的吞吐量低
RocketMQ
RoekctMQ 事物机制来确保消息都能发送到节点上
将生产者消息发送设置成同步发送,根据发送结果来判断是否需要做重复发送,最大程度保证消息发送到了服务器
消息重投机制,消息投递失败,会再次投递
rabbitMq
1、消息确认机制
发送端把消息发送个服务端,服务端接收到消息并且把消息持持久化到磁盘就会给发送端一个异步的confirm应答
2、事物消息机制
发送端开启一个事物,再推送消息,如果投递失败;进行事物回滚,然后重新发送消息;如果服务端收到消息,发送端就提交事务。
服务端保存消息失败(写入磁盘失败)
kafka
1.ACK=all,让所有的服务器节点都获取到数据;
2.合理的设置从机的个数,设置数据的备份
参数设置:min.insync.replica
3.禁止主机挂掉,选从机作为新的主机
参数设置:unclean.leader.election.enable=false 本身默认就是flase
rocketMq
1、修改节点的消息持久化刷盘机制
将异步持久化到磁盘,修改成同步持久化到磁盘
RocketMq消息本身默认的持久化盘刷机制是异步刷盘
2、RocketMQ采用主从机构
确保主机挂了,从机上还有消息备份数据
rabbitMQ
服务端设置交换机,队列,数据的持久化;服务器宕机后,重启会读取磁盘上的持久化的数据;
问题:由于消息的持久化是一批的持久化,可能宕机了,这一批数据还持久化到磁盘
消息的持久化
1、服务端收到生产者发送过来的消息,会做消息的持久化
2、当服务宕机后, 会从磁盘当中读取相应的消息,最大程度上保证消息不在服务节点上丢失
使用confirm机制,可以让发送者的数据持久化到磁盘,再确认
也可以尝试修改刷盘策略
消费方消费丢失
kafka
设置消息消费提交偏移量为手动提交偏移量,通过代码在finnaly里面手动设置消息异常的那个前一条的偏移量做提交;
需要正确提交自己的消费正常的偏移量
rocketMq
ack机制,设置消息成功消费之后,再通知节点消息已经成功消费
rabbitMq
丢失原因
1.消费者在处理消息的时候出现异常了,那么这条消息就是没有被正常的消费;如果不采取措施,那么这个消息就会丢失
解决方案
ack机制
ack机制概述
消息只有正常消费后,反馈给服务端;服务端才会从队列里面把该条消息删除
ack机制三种模式
不确认
不会发送ack确认消息
自动确认
服务端发送完消息就自动认为该消息被成功消费
缺点:由于网络原因,造成数据从服务端发送到消费者消息丢失
手动确认
消费者消费成功之后,显示的给服务端ack信号;服务端只有收到该信号才会把数据从队列里面删除
设置手动ack,尽可能减少消费端的数据丢失问题;正常就是发送ack,异常就记录日志,然后发送nack
ack机制弊端
内存泄露
如果消费者异常没法发ack消息,服务端会认为这些数据都是没有被正常消费;就会堆积在队列当中,造成内存没法回收,内存泄露;
内存泄露解决方案
1.设置手动应答,如果异常,捕获异常记录日志,给服务端发送正常消费;
2.设置重试次数(默认是3次,三次不消费成功就会放入到默认的死信队列)
ack机制默认打开,而且是自动确认
统一概述
消费者消费消息,都应该向服务器节点正确提交消费的实际情况;
消息顺序消费
通用方式
1、将前后有逻辑的消息合并成一个消息,发送,这样不管消费者是多个,不管消费者有几个线程,消费的时候都能保证消费是顺序被消费
2、同一个topic下,将有先后逻辑顺序的消息发送到同一个队列(rocketMQ,rabbitMQ),或者同一个分区(kafka),且保证消费者只有一个也只有一个线程来消费
kafka
1、将有前后逻辑顺序的消息发送到同一个分区
1、一个topic只有一个分区,对应的也只有一个消费者
RocketMq
1、将有前后逻辑顺序的消费发送到同一个topic下的同一个队列,且保证消费方只有一个线程去消费
2、设置发送的消息是全局顺序消息
某个Topic下的所有消息都要保证顺序
RabbitMq
1、将有前后逻辑顺序的消费发送到同一个topic下的同一个队列,且保证消费方只有一个线程去消费
0 条评论
下一页
为你推荐
查看更多