自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(88)
  • 收藏
  • 关注

原创 RocketMq comsumer源码

PullMessageService负责对消息队列进行消息拉取,从远端服务器拉取消息后将消息存储ProcessQueue消息队列处理队列中,然后调用ConsumeMessageService#submitConsumeRequest方法进行消息消费,使用线程池来消费消息,确保了消息拉取与消息消费的解耦。集群模式:各个消费者通过负载均衡的方式消费消息。广播模式:每一个消费者消费所有消息。

2024-06-05 17:42:50 176

原创 RocketMq producer源码

整个JVM中只存在一个MQClientManager实例,维护一个MQClientInstance缓存表同一个clientId只会创建一个MQClientInstance。MQClientInstance封装了RocketMQ网络处理API,是消息生产者和消息消费者与NameServer、Broker打交道的网络通道每一个客户端就是一个MQClientInstance,每一个ClientConfig对应一个实例。

2024-06-03 17:08:41 238

原创 RocketMq broker源码解析

broker 集群工作流程NameSrv启动成功后,等待broker、Consumer和producer启动后也与NameSrv保持长连接,NameSrv相当于是路由控制中心。启动broker, broker与所有的NameSrv建立长连接, broker,通过定时线程定时向NameSrv发送心跳,broker信息注册到所有的NameSrv上, 包含brokerName、brokerAddr、clusterName等由nameSrv去保存。producer启动时,先随机选择Namesrv集群中的某

2024-05-31 14:06:13 183

原创 NameServer 核心源码解析

Broker会自动向NameServer注册消息,生产者在发送消息时,会在NameServer的地址列表里通过负载均衡选择一个Broker进行消息发送,使用Netty与Broker保持长连接。brokerAddrTable:Broker基础信息,包括brokerName、所属集群名称、主备Broker地址。brokerLiveTable:Broker状态信息,NameServer每次收到心跳包是会替换该信息。clusterAddrTable:Broker集群信息,存储集群中所有Broker名称。

2024-05-30 17:44:34 237

原创 push模式消费

【代码】push模式消费。

2024-05-30 14:53:38 133

原创 生产者延迟消息和重试机制

【代码】生产者延迟消息和重试机制。

2024-05-29 10:00:25 152

原创 负载均衡策略

2024-05-27 15:05:35 82

原创 生产者发送源码

具体流程Producer先从本地尝试获取路由信息本地无缓存的路由信息时,从注册中心中获取路由信息,并缓存到本地获取到的路由信息包含了Topic下的所有Queue,Producer就可以采取负载均衡策略把消息发送到某个队列里Producer发送消息到Broker成功之后,服务器就会返回消息发送成功对象SendResult

2024-05-27 14:24:28 204

原创 RocketMQ 架构原理

在保持长连接的情况下,Producer每30s获取一次配置中心的所有Topic的最新队列情况,如果某个Broker宕机,Producer最多需要30s可以从配置中心感知到(如果写入消息多次失败也可以感知到)注册中心没隔10s会扫描一次所有的broker,如果2min没有发送心跳过来,就人为挂了,断开连接。一个Producer与注册中心的一台服务器保持长连接,并且会定时查询MQ的Topic配置信息,如果当前注册中心的服务器宕机,Producer会自动与下一台服务器连接。同步刷盘:写入成功才算成功。

2024-05-24 15:24:39 396

原创 26 | MQTT协议:如何支持海量的在线IoT设备?

如果你接入 IoT 设备数量在十万以内,是可以选择开源产品的,如果说客户端的规模超过十万的量级,需要支撑这么大规模的客户端数量,服务端只有单个节点肯定是不够的,必须用一个集群来支持,并且这个集群是要能支持水平扩容的,这些都是最基本的要求。另外,IoT 设备一般都采用无线连接,很多设备都是经常移动的,这就导致,IoT 设备的网络连接不稳定,并且这种不稳定的网络是一个常态。网络结构上,也是 C/S 架构,IoT 设备是客户端,Broker 是服务端,客户端与 Broker 通信进行收发消息。

2024-05-16 10:57:36 51

原创 22 | Kafka和RocketMQ的消息复制实现的差异点在哪?

这时候,即使有一些消息没有来得及复制到从节点上,这些消息依然躺在主节点的磁盘上,除非是主节点的磁盘坏了,否则等主节点重新恢复服务的时候,这些消息依然可以继续复制到从节点上,也可以继续消费,不会丢消息,消息的顺序也是没有问题的。在需要保证消息严格顺序的场景下,由于在主题层面无法保证严格顺序,所以必须指定队列来发送消息,对于任何一个队列,它一定是落在一组特定的主从节点上,如果这个主节点宕机,其他的主节点是无法替代这个主节点的,否则就无法保证严格顺序。Kafka 在写入消息的时候,采用的也是异步复制的方式。

2024-05-15 16:26:19 32

原创 19 | 数据压缩:时间换空间的游戏

选择压缩算法的时候,主要需要考虑数据的压缩率和压缩耗时。一般来说,压缩率越高的算法,压缩耗时也越高。如果是对性能要求高的系统,可以选择压缩速度快的算法,比如 LZ4;在 Kafka 中,生产者生成一个批消息发给服务端,在服务端中是不会拆分批消息的。那按照批来压缩,意味着,在服务端也不用对这批消息进行解压,可以整批直接存储,然后整批发送给消费者。在开启压缩时,Kafka 选择一批消息一起压缩,每一个批消息就是一个压缩分段。如果要对流数据进行压缩,那必须把流数据划分成多个帧,一帧一帧的分段压缩。

2024-05-15 11:21:33 41

原创 16 | 缓存策略:如何使用缓存来减少磁盘IO?

使用内存作为缓存来加速应用程序的访问速度,是几乎所有高性能系统都会采用的方法。

2024-05-14 17:50:22 104

原创 15 | Kafka如何实现高性能IO?

它的存储设计非常简单,对于每个分区,它把从 Producer 收到的消息,顺序地写入对应的 log 文件中,一个文件写满了,就开启一个新的文件这样顺序写下去。一般来说,消息刚刚写入到服务端就会被消费,按照 LRU 的“优先清除最近最少使用的页”这种策略,读取的时候,对于这种刚刚写入的 PageCache,命中的几率会非常高。构建批消息和解开批消息分别在发送端和消费端的客户端完成,不仅减轻了 Broker 的压力,最重要的是减少了 Broker 处理请求的次数,提升了总体的处理能力。

2024-05-14 16:15:47 18

原创 11 | 如何实现高性能的异步网络传输?

这个 select 方法是一个阻塞方法,这个线程会一直卡在这儿,直到这些 Channel 中的任意一个有数据到来,就会结束等待返回数据。它的返回值是一个迭代器,你可以从这个迭代器里面获取所有 Channel 收到的数据,然后来执行你的数据接收的业务逻辑。因为,每个连接都需要阻塞一个线程来等待数据,大量的连接数就会需要相同数量的数据接收线程。对,会有大量的线程来抢占 CPU 时间,造成频繁的 CPU 上下文切换,导致 CPU 的负载升高,整个系统的性能就会比较慢。Selecor 通过一种类似于。

2024-05-14 14:55:29 23

原创 10 | 如何使用异步设计提升系统性能?

在调用异步方法获得返回值 CompletableFuture 对象后,既可以调用 CompletableFuture 的 get 方法,像调用同步方法那样等待调用的方法执行结束并获得返回值,也可以像异步回调的方式一样,调用 CompletableFuture 那些以 then 开头的一系列方法,为 CompletableFuture 定义异步方法结束之后的后续操作。在两次调用账户服务的 Add 方法时,如果某一次调用失败了,该如何处理才能保证账户数据是平的?

2024-05-14 14:12:47 22

原创 07 | 消息积压了该如何处理?

主流消息队列的单个节点,消息收发的性能可以达到每秒钟处理几万至几十万条消息的水平,还可以通过水平扩展 Broker 的实例数成倍地提升处理能力。特别需要注意的一点是,在扩容 Consumer 的实例数量的同时,必须同步扩容主题中的分区(也叫队列)数量,使用消息队列的时候,大部分的性能问题都出现在消费端,如果消费的速度跟不上发送端生产消息的速度,就会造成消息积压。如果说,你的代码发送消息的性能上不去,你需要优先检查一下,是不是发消息之前的业务逻辑耗时太多导致的。我们更关注的是,在消息的收发两端,

2024-05-13 17:48:57 22

原创 06 | 如何处理消费过程中的重复消息?

在消息传递过程中,如果出现传递失败的情况,发送方会执行重试,重试的过程中就有可能会产生重复的消息。对使用消息队列的业务系统来说,如果没有对重复消息进行处理,就有可能会导致系统的数据出现错误。

2024-05-13 16:30:35 18

原创 05 | 如何确保消息不会丢失?

如果你的系统中 Producer 是多实例的,由于并不好协调多个 Producer 之间的发送顺序,所以也需要每个 Producer 分别生成各自的消息序号,并且需要附加上 Producer 的标识,在 Consumer 端按照每个 Producer 分别来检测序号的连续性。首先,像 Kafka 和 RocketMQ 这样的消息队列,它是不保证在 Topic 上的严格顺序的,只能保证分区上的消息是有序的,所以我们在发消息的时候必须要指定分区,并且,在每个分区单独检测消息序号的连续性。

2024-05-13 15:57:27 21

原创 04 | 如何利用事务消息实现分布式事务?

分布式事务就是要在分布式系统中的实现事务。在分布式系统中,在保证可用性和不严重牺牲性能的前提下,光是要实现数据的一致性就已经非常困难了,所以出现了很多“残血版”的一致性,比如顺序一致性、最终一致性等等。

2024-05-13 15:17:24 18

原创 03 | 消息模型:主题和队列有什么区别?

Exchange 位于生产者和队列之间,生产者并不关心将消息发送给哪个队列,而是将消息发送给 Exchange,由 Exchange 上配置的策略来决定将消息投递到哪些队列中。每个主题包含多个队列,通过多个队列来实现多实例并行生产和消费。需要注意的是,RocketMQ 只在队列上保证消息的有序性,主题层面是无法保证消息的严格顺序的。订阅者的概念是通过**消费组(Consumer Group)**来体现的。每个消费组都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,

2024-05-13 14:30:36 25

原创 02 | 该如何选择消息队列?

它的同步收发消息的响应时延比较高,因为当客户端发送一条消息的时候,Kafka 并不会立即发送出去,而是要等一会儿攒一批再发送,在它的 Broker 中,很多地方都会使用这种“先攒一波再一起处理”的设计。当你的业务场景中,每秒钟消息数量没有那么多的时候,Kafka 的时延反而会比较高。RabbitMQ 一个比较有特色的功能是支持非常灵活的路由配置,和其他消息队列不同的是,它在生产者(Producer)和队列(Queue)之间增加了一个 Exchange 模块,你可以理解为交换机。响应时延低,消息处理快。

2024-05-13 13:52:10 65 1

原创 01 | 为什么需要消息队列?

无论增加、减少下游系统或是下游系统需求如何变化,订单服务都无需做任何更改,实现了订单服务与下游服务的解耦。使用消息队列隔离网关和后端服务,以达到流量控制和保护后端服务的目的。

2024-05-13 11:41:52 104

原创 39 | 自增主键为什么不是连续的?

从 auto_increment_offset 开始,以 auto_increment_increment 为步长,持续叠加,直到找到第一个大于 X 的值,作为新的自增值。根据要插入的值和当前自增值的大小关系,自增值的变更结果也会有所不同。假设,某次要插入的值是 X,当前的自增值是 Y。其实,这个输出结果容易引起这样的误解:自增值是保存在表结构定义里的。,表示下一次插入数据时,如果需要自动生成自增值,会生成 id=2。事务回滚也会产生类似的现象,这就是第二种原因。表定义里面出现了一个。

2024-05-11 15:49:51 10

原创 37 | 什么时候会使用内部临时表?

但是,如果碰上不适合创建索引的场景,我们还是要老老实实做排序的。Extra 字段,表示在对子查询的结果集做 union 的时候,使用了临时表 (Using temporary)。在 group by 语句中加入 SQL_BIG_RESULT 这个提示(hint),就可以告诉优化器:这个语句涉及的数据量很大,请直接用磁盘临时表。这个语句的逻辑是把表 t1 里的数据,按照 id%10 进行分组统计,并按照 m 的结果排序后输出。这样执行的时候,就依次执行子查询,得到的结果直接作为结果集的一部分,发给客户端。

2024-05-11 15:10:16 37

原创 34 | 到底可不可以使用join?

t2 里插入了 1000 行数据,在表 t1 里插入的是 100 行数据。

2024-05-10 17:13:54 27

原创 26 | 备库为什么会延迟好几个小时?

在官方的 5.6 版本之前,MySQL 只支持单线程复制,由此在主库并发高、TPS 高时就会出现严重的主备延迟问题。coordinator 就是原来的 sql_thread, 不过现在它不再直接更新数据了,只负责读取中转日志和分发事务。真正更新日志的,变成了 worker 线程。而 work 线程的个数,就是由参数slave_parallel_workers 决定的。根据我的经验,把这个值设置为 8~16 之间最好(32 核物理机的情况),毕竟备库还有可能要提供读查询,不能把 CPU 都吃光了。

2024-05-09 18:03:19 59

原创 25 | MySQL是怎么保证高可用的?

所谓主备延迟,就是同一个事务,在备库执行完成的时间和主库执行完成的时间之间的差值,也就是 T3-T1。

2024-05-09 16:30:44 133

原创 24 | MySQL是怎么保证主备一致的?

由于 statement 格式下,记录到 binlog 里的是语句原文,因此可能会出现这样一种情况:在主库执行这条 SQL 语句的时候,用的是索引 a;当 binlog_format 使用 row 格式的时候,binlog 里面记录了真实删除行的主键 id,这样 binlog 传到备库去的时候,就肯定会删除 id=4 的行,不会有主备删除不同行的问题。binlog 有两种格式,一种是 statement,一种是 row。时,binlog 里面记录的就是 SQL 语句的原文。双 Master 结构。

2024-05-09 16:07:21 104

原创 23 | MySQL是怎么保证数据不丢的?

系统给 binlog cache 分配了一片内存,每个线程一个,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。binlog 的写入逻辑比较简单:事务执行过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。,指的就是指把日志写入到文件系统的 page cache,并没有把数据持久化到磁盘,所以速度比较快。

2024-05-09 14:39:47 20

原创 22 | MySQL有哪些“饮鸩止渴”提高性能的方法?

创建索引都支持 Online DDL 了,对于那种高峰期数据库已经被这个语句打挂了的情况,最高效的做法就是直接执行 alter table 语句。让数据库跳过权限验证阶段,重启数据库,并使用–skip-grant-tables 参数启动。

2024-05-08 18:01:23 41 2

原创 21 | 为什么我只改一行的语句,锁这么多?

表结构。

2024-04-30 15:33:57 23

原创 20 | 幻读是什么,幻读有什么问题?

幻读是什么?在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。上面 session B 的修改结果,被 session A 之后的 select语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。

2024-04-30 10:35:03 40

原创 19 | 为什么我只查一行的语句,也执行这么慢?

带 lock in share mode 的 SQL 语句,是当前读,因此会直接读到 1000001 这个结果,所以速度很快;而 select * from t where id=1 这个语句,是一致性读,因此需要从 1000001 开始,依次执行 undo log,执行了 100 万次以后,才将 1 这个结果返回。由于字段 c 上没有索引,这个语句只能走 id 主键顺序扫描,因此需要扫描 5 万行。大概率是表 t 被锁住了。接下来分析原因的时候,一般都是首先执行一下。命令,看看当前语句处于什么状态。

2024-04-30 10:00:37 17

原创 18 | 为什么这些SQL语句逻辑相同,性能却差异巨大?

你可能也发现了,tradeid 的字段类型是 varchar(32),而输入的参数却是整型,所以需要做类型转换。在这个例子里,放弃了树搜索功能,优化器可以选择遍历主键索引,也可以选择遍历索引 t_modified,优化器对比索引大小后发现,索引 t_modified 更小,遍历这个索引比遍历主键索引来得更快。这个语句里 trade_detail 表成了驱动表,但是 explain 结果的第二行显示,这次的查询操作用上了被驱动表 tradelog 里的索引 (tradeid),扫描行数是 1。

2024-04-29 17:19:47 15

原创 17 | 如何正确地显示随机消息?

Extra 字段显示 Using temporary,表示的是需要使用临时表;Using filesort,表示的是需要执行排序操作。需要临时表,并且需要在临时表上排序。order by rand() 使用了内存临时表,内存临时表排序的时候使用了 rowid 排序方法。

2024-04-29 14:50:39 13

原创 16 | “order by”是怎么工作的?

但这个算法有一个问题,就是如果查询要返回的字段很多的话,那么 sort_buffer 里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能会很差。在这个索引里面,我们依然可以用树搜索的方式定位到第一个满足 city='杭州’的记录,并且额外确保了,接下来按顺序取“下一条记录”的遍历过程中,只要 city 的值是杭州,name 的值就一定是有序的。从上面分析的执行过程,我们可以看到,MySQL 之所以需要生成临时表,并且在临时表上做排序操作,其原因是原来的数据都是无序的。

2024-04-28 17:48:17 15

原创 15 | 答疑文章(一):日志和索引相关问题

如果在图中的地方,也就是写入 redo log 处于 prepare 阶段之后、写 binlog 之前,发生了崩溃(crash),由于此时 binlog 还没写,redo log 也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候,binlog 还没写,所以也不会传到备库。也就是 binlog 写完,redo log 还没 commit 前发生 crash,崩溃恢复时的判断规则。

2024-04-28 15:25:50 21

原创 14 | count(*)这么慢,我该怎么办?

server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值取出来再判断一下,不是 null 才累加。InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。server 层拿到 id 后,判断是不可能为空的,就按行累加。

2024-04-28 14:43:42 16

原创 13 | 为什么表数据删掉一半,表文件大小不变?

结果就是,所有的数据页都会被标记为可复用。delete 命令其实只是把记录的位置,或者数据页标记为了“可复用”,但磁盘文件的大小是不会变的。这些可以复用,而没有被使用的空间,看起来就像是“空洞”。我们要删掉 R4 这个记录,InnoDB 引擎只会把 R4 这个记录标记为删除。如果之后要再插入一个 ID 在 300 和 600 之间的记录时,可能会复用这个位置。现在,你已经知道了 InnoDB 的数据是按页存储的,那么如果我们删掉了一个数据页上的所有记录,会怎么样?答案是,整个数据页就可以被复用了。

2024-04-28 11:44:22 28

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除