消息队列
用于进程中相互通信的队列
放入消息的是生产者,取出消息的是消费者
应用场景
异步处理,削峰/限流,解耦
用Java模拟消息队列
用一个线程当生产者,当消息队列中消息数小于最大队列容量时向队列中加入消息,满了则阻塞
另一个线程当消费者,当消息队列非空时取出消息,空了则阻塞
队列由空到放入消息时唤醒消费者,队列从满到取出消息时唤醒生产者
JMS和AMQP
RPC
Kafka
分布式流式处理平台,削峰填谷
三个关键功能:消息队列,容错的持久方式存储记录消息流(持久化到磁盘。避免消息丢失),流式处理平台
用于秒杀活动,大数据和日志异构同步
分布式系统,由通过高性能TCP网络协议通信的服务器和客户端组成
主要用于消息队列和流数据处理
二进制数据传输
特性
消息持久化
高吞吐量
扩展性强(动态扩展)
多语言支持
流处理
安全机制
数据备份
轻量级
消息压缩
高性能
可以有多个生产者和消费者,也可以将不同的消息进行分类,分成不同的topic放入不同队列,生产者分类投递,消费者按需订阅
单个topic过长还可以分成多个partition分区,每个消费者负责一个分区
高扩展性
将partition分散部署在多台机器上,每台机器代表一个broker,通过增加机器缓解机器CPU过高带来的性能问题
高可用
给partition增加副本replicas,分为leader和follower,leader负责应对生产者和消费者的读写请求,follower只负责同步leader的消息,将leader和follower分散到不同broker上,leader挂了就选举出一个新的partition顶上
持久化和过期策略
将消息放入磁盘中,设置retention policy过期策略,磁盘满了或者过期了就清理掉
消费者组
不同消费者组维护自己的消费进度,互相隔离
ZooKeeper
ZooKeeper组件定期和broker通信,获取整个kafka集群的状态
一个新的broker加入后,其他broker马上就能感知到
分布式协调服务:在分布式环境下让多个实例同时获取到同一份信息的服务
zookeeper是通用的分布式协调服务,可以用于服务注册和发现,还可以用于分布式锁配置管理等场景
但是ZooKeeper过重,在2.8.0版本支持移除Zookeeper,通过broker之间加入一致性算法Raft实现同样效果,这就是Kraft或Quorum模式
如何保证消息顺序消费
生产者通过对消息的key对partition取模,决定把消息放在哪个partition中,消息按照先后有序存储在partition中
消息被路由在不同partition分区,消费者通过balance机制分别指派了对应的消费分区,因为消费者是完全独立的网络节点,所以可能导致消息的消费顺序不是按照发送顺序实现的,导致消费乱序问题
解决方案:自定义消息分区的路由算法,把指定的key发送到一个partition中,指定一个消费者专门消费某个分区的数据
在有些设计方案中,在消费端采用异步线程方式消费数据,提高消息处理效率。每个消费者消费消息速率不同,即便是分区消费也可能出现无序访问的问题
解决方案:在消费端采用一个阻塞队列,把获取到的消息保存到阻塞队列里,采用异步线程从阻塞队列中获取消息进行消费
RocketMQ
和kafka区别
架构减法,功能加法
简化协调节点
将zookeeper去掉,换成了NameServer,轻量级方式管理消息队列的集群信息
简化分区
分区从partition换成Queue
kafka中partition会存储完整的消息体,rocketMQ中Queue只存储简要信息,比如消息偏移offset
消息完整数据放在CommitLog文件上,通过offset定位到CommitLog上的某条消息
kafka只需要从partition中读一次即可,rocketMQ需要读两次
底层存储
kafka底层存储partition分为多段segment,生产者写入数据到partition本质是写入到某个segment文件下,对每个文件都是顺序写,当topic变多时,partition也变多,segment也变多,同时写多个文件时,虽然每个文件内部都是顺序写,但是多个文件存放在磁盘不同地方,顺序写磁盘劣化为随机写,写性能降低
rockerMQ底层存储将单个broker下的多个topic数据全部写到一个逻辑文件CommitLog上,将所有写操作变为顺序写
简化备份模型
kafka同步本质是同步partition下的segment文件数据
RocketMQ直接同步CommitLog文件,通过broker为单位区分主从,保持高可用同时简化备份模型
消息过滤
RocketMQ支持在消息上打标记tag,可以区分同一topic上的消息类型
支持事务
kafka支持事务是发送消息要么同时成功要么同时失败
RocketMQ支持事务是执行自定义逻辑和生产者发消息这两件事同时成功或失败
加入延时队列
加入死信队列
多次重试都发送失败,RocketMQ会把消息放在一个专门的队列,方便后续单独处理
kafka需要手动ack重置偏移量
消息回溯
kafka可以调整offset控制消费者从某个地方开始消费
RocketMQ可以调整offset和时间
缺点
性能(吞吐量)不如kafka
为什么不如kafka
零拷贝技术不同,批处理,数据压缩
数据从磁盘发送到网络过程
首先程序发起系统调用read(),将磁盘数据拷贝到内核空间的缓冲区,再从内核空间缓冲区拷贝到用户空间
程序再发起系统调用write(),将数据从用户空间拷贝到socket发送缓冲区
再从发送缓冲区拷贝到网卡,通过网络到达消费者
总共两次系统调用,对应四次用户态和内核态切换和四次数据拷贝
零拷贝
mmap:操作系统内核提供的一个方法,可以将内核空间缓冲区映射到用户空间,将read()调用改为mmap()方法,不需要从内核缓冲区拷贝到用户空间,但还需要拷贝到socket缓冲区然后拷贝到网卡
sendfile:也是内核提供的方法,发起系统调用sendfile()后,内核将磁盘数据拷贝到内核空间缓冲区,然后直接拷贝到网卡,只需要两次数据拷贝,不需要CPU参与数据拷贝
RocketMQ使用mmap技术,kafka使用sendfile技术
为什么RocketMQ不用sendfile
mmap返回的是数据具体内容,应用层能获取到消息内容,并进行逻辑处理
sendfile返回的是成功发送字节数,应用层不知道消息内容,RocketMQ需要了解具体的消息内容,方便二次投递(死信队列)
选哪个?
大数据场景(Spark,Flink)用kafka
其他场景尽量用RocketMQ
RabbitMQ
K8S
本质上是应用服务和服务器之间的中间层,通过暴露一系列API能力简化服务的运维部署流程,可以通过这些API能力搭建自己的服务管理平台
可以通过策略协调和管理多个应用服务,只需要一个yaml文件配置,定义应用的部署顺序等信息,就能自动部署应用到各个服务器上,能让他们自动扩缩容,在一个服务器挂了后可以自动在其他服务器上自动部署应用
架构设计
服务器分为控制平面control plane和工作节点Node,控制平面控制和管理各个Node,Node实际运行各个应用服务
控制平面
通过调用API,由Scheduler调度器查看服务器内存和CPU资源部署应用
由Controller Mgr控制器管理器负责创建和关闭服务
将数据保存到存储层ETCD
工作节点
可以是裸机服务器或虚拟机
多个应用服务共享一台Node上的内存和CPU等计算资源
只需要将服务代码打包成Container Image容器镜像,就能一行命令直接部署(容器镜像可以理解为将应用代码和系统环境打包成压缩包,在任意服务器上解压即可正常运行服务)
为了下载和部署镜像,Node中会有container runtime容器运行时组件,每个应用服务可以认为是一个container,大多数时候还会为应用服务搭配一个日志收集器container或监控采集器container,多个container组成一个pod,运行在Node上
K8S可以将pod从某个Node,调度到另一个Node,还能以pod为单位做重启和动态扩缩容的操作
Node组件Kubelet用于接收控制平面的命令,负责管理和监控pod
Node中还有个kube proxy,负责Node的网络通信功能,可以将外部请求转发到pod中
Cluster
控制平面和工作节点共同构成了一个Cluster集群,一般会构建多个Cluster集群,比如生产环境和测试环境
为了将集群内部服务暴露给外部用户使用,还会部署一个入口控制器Ingress控制器,让外部用户访问集群内部服务
Kubectl
命令行工具Kubectl,只需要执行命令,内部就会调用K8S的API
使用方式
编写yaml文件,定义pod用到了哪些镜像,占用内存和CPU等信息
然后使用Kubectl命令行工具执行kubectl apply -f xx.yaml文件
Kubectl将解析后的对象通过API请求发送给K8S
API Server驱使Scheduler通过ETCD提供的数据寻找合适的Node
再驱使Controller Mgr控制Node创建服务
Node内部的Kubelet开始基于container runtime组件拉取镜像创建容器
最终完成pod创建
调用过程
之前直接发送HTTP请求,发送到Nginx服务器,转发到部署的服务内
现在外部请求先到达K8S集群的Ingress控制器,然后转发到K8S内某个Node的kube proxy上,找到对应的pod后转发到容器内部服务中,处理结果原路返回
版权归原作者 锦鲤5214 所有, 如有侵权,请联系我们删除。