中间件技术
2022-03-16 08:49:32 1 举报
AI智能生成
登录查看完整内容
编程中用到的一些中间件,包含设计思想+细节把控+面试一些问题
作者其他创作
大纲/内容
磁盘、内存、IObuffer
数据库DataPage 4K
基础常识
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
中文官网
memcached 对比
安装
Reactor线程模型
1:BIO 线程之间是相互阻塞的运行模式 称为阻塞IO
2:同步非阻塞 NIO, 基于轮询的处理模式,在用户空间内对链接进行轮询处理,请求多了以后还是会有调度成本耗费高的问题
3:多路复用 NIO 基于select事件监听,只对有请求得到客户进行响应,但是多个线程之间的调用从用户态到内核态互相切换还是有消耗
4:mmap NIO epoll的文件描述符,有共享内存区域维护一个红黑树进行数据传输,极大的减轻了系统的调用
Redis基于NIO网络模型 epoll的系统调度 可以快速响应 、 kafka也是类似原理
线程模型
Redis-cli 连接 ./redis-cli -p 10001 -a
查看帮助 ./redis-cli -h
默认16个DB
set
get
append
setrange
getrange
strlen
字符
incr
incrby
数值
setbit
bitcount
bitpos
bitop
1:用户系统统计登录天数,且窗口随机
场景
bitMap
String
lpush
lpop
栈 同向命令
rpop
队列 反向命令
lindex
数组
blpop 阻塞取,没取到阻塞
阻塞队列 单播队列
lrange key left right
循环取出
list
hash map(k-v) 命令H开头
无序、随机存放、不重复
随机事件
ZRange
Zadd
sorted sets
数据类型
SUBSCRIBE first topic1
订阅一个topic
客户端向领一个topic发布消息
发布订阅
开始
multi
执行
exec
放弃
descard
监听 标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)
watch
事务
概率解决问题,将缓存中的数据向BitMap中标记 ,可能请求的被错标 , 可以很大程度的去 减少缓存穿透,而且成本极低
如果穿透了,数据不存在,client 增加Redis中key为null , 不用走布隆过滤了 , 增加元素需要完成对布隆过滤器的添加(双写一致)
布隆过滤器
set key value ex
主动设置过期时间
设置过期时间 EXPIRE
倒计时监听
1:被动访问判定
2:周期轮询判定
过期判断原理
KEY 有效期
maxmemory
最大内存配置
返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
noeviction
碰了多少次
LFU
代码实现LinkedList链表接口,最新命中的缓存防止到链表头,当缓存满的时候清除链表最后几位
多久没碰他
LRU
回收策略
冷热数据
Redis 作为 数据库/缓存的区别
时点性
Linux中 子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程
redis 在时间点 fork 出一个进程 进行RDB备份存储 , 主进程依旧对外服务
save
fork创建子进程
save 900 1save 300 10save 60 3600
配置文件中可以去配置保存时间,默认是5分钟
bgsave
不支持Linux日期拉链,永远只有一个dump.rdb , 备份比较难
落盘时候宕机了会造成数据丢失
优点:AOF文件格式类似Java序列化,恢复速度快
弊端
快照 RDB
衔接、前一个命令的输出作为后一个命令的输入
echo $$ | more
echo $BASHPID | more
管道会出发创建子进程
父进程设置的变量、子进程对外修改,父进程并不会感知
父子进程
Linux 管道
redis的操作记录会写到文件中
RDB 和 AOF 会同时开启,恢复只会用AOF恢复,速度快,完整性好一点
体量无线变大、恢复慢
优化:RDB 落盘以后 AOF追加操作
AOF文件过大会进行重写、重新落盘
AOF配置
日志 AOF
存储层
单点故障
容量有线
存储压力 、 网络压力
单节点问题 AKF拆分可解决
同步阻塞、强一致性、破坏可用性
异步 弱一致性,暂时丢失数据、最终一致性
一致性问题
多节点
1:BGSave 2:同步
replica-save-stale-data yes
replica-read-only yes
repl-diskless-sync no
增量复制
repl-backlog-size 1mb
min-replicas-to-write 3
min-replicas-max-log 10
主从复制
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
哨兵 sentinel
哨兵会修改自己的配置文件, 可以根据主节点变化修改自身配置文件
管连接点进行通信
可以订阅topic , 查看所有通信内容
redis 发布订阅
HA
业务逻辑拆分
hash取摸是固定的,产生数据倾斜,难以新增机器
hash
随机
消息队列
random
key和设备都需要参与hash计算
产生一个hash环
优点:加节点的确可以分担其他节点的压力、不会造成全局洗牌、节点进行LRU\\LFU 淘汰算法
缺点:新增节点会造成部门节点数据失效,无法命中; 击穿、请求到mysql 双写一致性 , 可以每次取离我最近的连个物理节点
优缺点
一致性hash算法
shard分片
集群
一个key过期后,瞬时太多的请求打进来,瞬间访问数据库
这里就要用分布式锁, setnx 只允许一个线程去取这个数据,其余进程进行等待
击穿
业务数据查询不到、穿过redis
client 包含数据
算法 bitmap -> redis
redis 集成布隆
解决:布隆过滤器
穿透
大量key同时失效、见解造成访问到达数据库
击穿方案
业务层面加时间判断,零点延迟
业务不允许
业务上 均匀分布过期时间
雪崩
延迟双删先删除缓存、更新数据库、等待20ms 后再删除缓存
监听binlog中间件去监听binlog 数据库更新后自动更新缓存
一致性(双写)
缓存常见问题
RedLock
set key value [EX seconds] [PX milliseconds] [NX|XX]
setNX 过期时间 key 二次校验
Redis 分布式锁
1:尝试创建临时节点,创建成功、获得锁
2: 监听临时节点
路径监听
ZK
分布式锁
Redis
数据保存在内存中
Leader 挂掉、可快速选举、快速修复
集群 主从复制、分片处理增、删、改 只能在主节点、查询能在其他节点
并且是数据二进制安全的
节点存数据很少 1M
客户端链接维护了一个session 通过session可以判断持续时间
数据模型、目录树
顺序一致性、客户端链接是顺序的
原子性操作
最终一致性
基础概念
后面数据只能1M 大小 并且是二进制安全的 不会乱码
-S
-E 临时节点
create /xxoo “”
cZxid 创建事务ID
ctime 创建时间
mzxid 修改事务ID
mtime 修改时间
pzxid 子节点最后修改的事务id
cversion 子节点版本号
dataVersion 数据版本号
aclVersion 权限版本号
ephemeralOwner 创建临时节点的回话sessionID
dataLength 节点数据长度
子节点数量
Children
ls -s
ls /
基本命令
主节点,不参与计算,发号命令
Leader
选举
Follow
增加查询能力
Observer
多节点配置
zoo.cfg
角色
扩展性
快速恢复:攘外必先安内
对外: 一致性、可靠性
内部 Paxos 协议选举
可靠性
特征
向集群发出议案,设置自己为leader 提议内容格式编号n内容value)
Proposer
对议案进行投票,达到多数派提议认可时提议才会被接受
Acceptor
对提议记录,对一致性没有任何影响
Learner
1:prepare(N)请求
2:promise(N-Value)返回
prepare阶段
1:accept(N-value)请求
2:accepted 返回
accept阶段
阶段
先进行选举,产生最新leader,后续选举互动返回Leader
多个节点进行选举,未产生leader时,选则最大的N,直到过半accepted返回成功,在进行Leader 同步
图解
一次选举被拒绝会产生更大的N,如果两个Proposer发现自己的N小会进行更高N的选举,这样就会导致死循环,产生活锁
设置最大请求次数,超过请求次数便不再请求,请求时间依次递减直至不请求
二进制指数退避算法
解决方案
活锁
每次选举请求经过两轮请求返回
效率低
实现困难
优化缺点
视频详解
集群所有消息均可靠,内部通信没有叛徒
前提条件
Paxos算法
Paxos 协议精简版-- 原子广播协议
1:客户端创建节点2:Follow 转 Leader3:Leader 创建zxid -- 内存中维护数据,并且维护发送队列4:Leader 写入Follow 日志中,磁盘写日志 5:Follow 回复写成功6:过半Follow 回复OK 触发自身写操作 -- Follow 也写内存
zab
事件:Create\\delete\\change\\children
监听后执行callback
事件监听\\观察
new zk 时候创建的时间,和session、path 没关系
两类:
API
callback
Zookeeper
Kafka是一个分布式的基于发布、订阅的消息系统,有着强大的消息处理能力,相比与其他消息系统,具有以下特性:快速数据持久化,实现了O(1)时间复杂度的数据持久化能力。高吞吐,能在普通的服务器上达到10W每秒的吞吐速率。高可靠,消息持久化以及副本系统的机制保证了消息的可靠性,消息可以多次消费。高扩展,与其他分布式系统一样,所有组件均支持分布式、自动实现负载均衡,可以快速便捷的扩容系统。离线与实时处理能力并存,提供了在线与离线的消息处理能力
优点简介
kafka 分布式消息系统,将消息直接存入磁盘,默认保存一周
broker kafka节点、没有主从挂你,依赖ZK进行协调。broker负责消息读写存储,一个broker可以管理多个partition
topic 一类消息总称,一个消息队列,topic是有partition组成的,指定创建partition数量
partition 组成topic的单元,每个partition有副本,由broker来进行管理
Producer 消息的生产者,自己决定向哪一个partatition中取生产消息,两种机制:hash、轮询
consumer 消息消费者,consumer 通过Zookeeper去维护消费者偏移量,consumer有自己的消费组,不同的组之间消费同一个topic的数据互不干扰,同一个组内的topic消费只产生一次
组件
依赖 ZK 进行分布式协调 , 环境搭建完成后会通过zc 来进行broker管理
每个Topic分为多个partition,每个分区存储不同的消息,消息进入partation时候回从0开始维护一个offset,并保证分区上唯一,消息在分区上的顺序由offset保证,消息在一个分区内是有序的
Topic
分区在逻辑上对应一个日志(Log),物理上对应的是一个文件夹。到kafka log文件夹去看,效果如下
消息写入分区时会进行分片,默认没片大小为1G ,实际存储为三个文件 .index .timeindex .log
日志索引
log
主体与日志
副本所在节点需要与ZooKeeper维持心跳。从副本的最后一条消息的offset需要与主副本的最后一条消息offset差值不超过设定阈值(replica.lag.max.messages)或者副本的LEO落后于主副本的LEO时长不大于设定阈值(replica.lag.time.max.ms),官方推荐使用后者判断,并在新版本kafka0.10.0移除了replica.lag.max.messages参数
ISR集合 -- 连通性&活跃性 的节点
是一个比较特殊的offset标记,消费端消费时只能拉取到小于HW的消息而HW及之后的消息对于消费者来说是不可见的,该值由主副本管理,当ISR集合中的全部从副本都拉取到HW指定消息之后,主副本会将HW值+1,即指向下一个offset位移,这样可以保证HW之前消息的可靠性。
高水位 High Watermark
LEO(Log End Offset)
副本文件
1:默认为1,表示在ISR中的leader副本成功接收到数据并确认后再发送下一条消息,如果主节点宕机则可能出现数据丢失场景,详细分析可参考前面提到的副本章节。0:表示生产端不需要等待节点的确认就可以继续发送下一批数据,这种情况下数据传输效率最高,但是数据的可靠性最低。-1:表示生产端需要等待ISR中的所有副本节点都收到数据之后才算消息写入成功,可靠性最高,但是性能最低,如果服务端的min.insync.replicas值设置为1,那么在这种情况下允许ISR集合只有一个副本,因此也会存在数据丢失的情况。
ACK
唯一标识:判断某个请求是否重复,需要有一个唯一性标识,然后服务端就能根据这个唯一标识来判断是否为重复请求。
记录已经处理过的请求:服务端需要记录已经处理过的请求,然后根据唯一标识来判断是否是重复请求,如果已经处理过,则直接拒绝或者不做任何操作返回成功。
幂等
生产者
消费组订阅主题下的每个分区只会分配给消费组中的一个消费者。group.id标识消费组,相同则属于同一消费组。不同消费组之间相互隔离互不影响。
消费组
自动提交
基于一条记录
基于partition (推荐,因为kafka的offset是基于partition维护的)
基于一次拉取数据
手动提交
偏移量 offset
消费者
nohup ./kafka-server-start.sh ../config/server.properties >> kafkaServer.nohup &
启动kafka Server
./kafka-topics.sh --list --zookeeper 127.0.0.1:2181
topic 列表
常用命令
多Broker 节点
partition 多副本
高可用
1:消息是顺序读写
2:零拷贝技术, MMAP , 避免线程分片执行时候上下文切换
3:压缩算法
KAFKA为什么快
Product 设置ACK 为0 、 1 、 -1 三种
消费者提交offset
保证不会丢失
数据库有记录,会造成主键冲突
生产 --> kafka --> 消费者
消费者进行offset 增量维护
消费过程:
不会重复消费
alter partition
新增消费者
分片扩容
消费者发送到新consume
新建Topic partition 是原来的 10倍
消息积压如何处理
消费者加多线程处理
产生原因
在队列中维护类型,分类型开启线程
消息顺序读写
面试
kafka
有些业务不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
异步通信
在任何重要的系统中,都会有需要不同的处理时间的元素。消息队列通过一个缓冲层来帮助任务最高效率的执行,该缓冲有助于控制和优化数据流经过系统的速度。以调节系统响应时间。
缓冲
降低工程间的强依赖程度,针对异构系统进行适配。在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。通过消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口,当应用发生变化时,可以独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
解耦
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
冗余
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量无法提取预知;如果以为了能处理这类瞬间峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
加载保护
分布式系统产生的海量数据流,如:业务日志、监控数据、用户行为等,针对这些数据流进行实时或批量采集汇总,然后进行大数据分析是当前互联网的必备技术,通过消息队列完成此类数据收集是最好的选择。
数据流处理
异构平台、相互解耦
应用场景
Broker
Provider
Consumer
点对点
p2p
pub/sub
JMS中的角色
启动 ./activemq start
停止 ./activemq stop
securityLoginService 管理平台登录名 用户 密码配置(jetty-realm.properties)
${AMQ_HOME}/config/jetty.xml
新增消息用户密码需要配置plugin
${AMQ_HOME}/config/activemq.xml
系统配置
KahaDB存储
AMQ方式
activemq_msgs:queue和topic的消息都存在这个表中 activemq_acks:存储持久订阅的信息和最后一个持久订阅接收的消息ID activemq_lock:跟kahadb的lock文件类似,确保数据库在某一时刻只有一个broker在访问
JDBC
LevelDB
Memory
存储
session.commit();session.rollback();
签收代表接收端的session已收到消息的一次确认,反馈给broker
Session.AUTO_ACKNOWLEDGE当客户成功的从receive方法返回的时候,或者从MessageListener.onMessage方法成功返回的时候,会话自动确认客户收到的消息
Session.CLIENT_ACKNOWLEDGE。客户通过消息的acknowledge方法确认消息。需要注意的是,在这种模式中,确认是在会话层上进行:确认一个被消费的消息将自动确认所有已被会话消费的消息。例如,如果一个消息消费者消费了10个消息,然后确认第5个消息,那么所有10个消息都被确认。
Session.DUPS_ACKNOWLEDGE。该选择只是会话迟钝的确认消息的提交。如果JMS Provider失败,那么可能会导致一些重复的消息。如果是重复的消息,那么JMS Provider必须把消息头的JMSRedelivered字段设置为true
消息可靠性机制
可以使用消息优先级来指示JMS Provider首先提交紧急的消息。优先级分10个级别,从0(最低)到9(最高)。如果不指定优先级,默认级别是4。JMS Provider并不一定保证按照优先级的顺序提交消息。
优先级
具体配置: producer.setTimeToLive
超时时间 -> 死信队列 -> 拿出来 -> 重发
死信队列超时的消息会进入 ActiveMQ.DLQ`队列且不会自动清除,称为死信
消息超时机制
producer每发送一个消息,统计一下发送的字节数,当字节数达到ProducerWindowSize值时,需要等待broker的确认,才能继续发送。
消息堆积
基础概念
ActiveMQ
中间件架构
0 条评论
回复 删除
下一页