关于 RocketMQ ClientID 相同引发的消息堆积的问题

首先,造成这个问题的 BUG RocketMQ 官方已经在 3月16号这个提交中修复了,这里只是探讨一下在修复之前造成问题的具体细节,更多的上下文可以参考我之前写的 《RocketMQ Consumer 启动时都干了些啥?》 ,这篇文章讲解了 RocketMQ 的 Consumer 启动之后都做了哪些操作,对理解本次要讲解的 BUG 有一定的帮助。

其中讲到了:

消息堆积

重复消费自不必说,你 ClientID 都相同了。本篇着重聊聊为什么会消息堆积

继续阅读关于 RocketMQ ClientID 相同引发的消息堆积的问题

RocketMQ Consumer 启动时都干了些啥?

可能我们对 RocketMQ 的消费者认知乍一想很简单,就是一个拿来消费消息的客户端而已,你只需要指定对应的 Topic 和 ConsumerGroup,剩下的就是只需要:

  • 接收消息
  • 处理消息

就完事了。

简略消费模型

当然,可能在实际业务场景下,确实是这样。但是如果我们不清楚 Consumer 启动之后到底会做些什么,底层的实现的一些细节,在面对复杂业务场景时,排查起来就会如同大海捞针般迷茫。

继续阅读RocketMQ Consumer 启动时都干了些啥?

请求数据包从发送到接收,都经历什么?

之前讲了「从输入 URL 再到浏览器成功看到界面」中的域名是如何变成 IP 地址的,了解了 DNS 相关的东西。这篇文章就聊聊发生在 DNS 解析之后的操作——建立连接。也就是我们常说的三次握手

看到三次握手你可能会说,这不是面试都被问烂了的题吗?

三次握手不就是:

  1. 服务器开始为 CLOSE 状态,然后监听某个端口,此时服务器会进入 LISTEN 状态
  2. 客户端最初也是 CLOSE 状态,客户端会向服务器发送一个带 SYN 标志位的数据包,主动发起连接。此时客户端会变成 SYN-SENT 状态
  3. 服务器接收到客户端的数据包之后,通过标志位判断出了客户端想要建立连接。然后返回一个 SYNACK ,此时服务器的状态变为了 SYN-RCVD
  4. 客户端收到了服务器的 ACK 之后,会回一个 ACK 给服务器,回完这个 ACK 之后,客户端的状态就变为了 ESTABLISH
  5. 服务器收到了客户端回复的 ACK 之后,服务器的状态也变成了 ESTABLISH
继续阅读请求数据包从发送到接收,都经历什么?

你的域名是如何变成 IP 地址的?

可能大家都知道或者被问过一个问题,那就是很经典的「从浏览器输入 URL 再到页面展示,都发生了什么」。这个问题虽然简单,但是真的能够从回答的各种细节上看出不同人之间的水平差距。

这篇文章主要是聊一聊输入 URL 之后的第一步——域名解析

域名就类似于 http://www.google.com,而通过 ping 命令,就可以查询到对应域名的 IP 地址了。

那为什么又要有域名,又要有 IP 呢?

继续阅读你的域名是如何变成 IP 地址的?

Base64 原理

Base64

Base64 是什么?是将字节流转换成可打印字符、将可打印字符转换为字节流的一种算法。Base64 使用 64 个可打印字符来表示转换后的数据。

准确的来说,Base64 不算是一种加、解密的算法,它是一种编码、解码的算法。这也是为什么我的用词是编码、解码,而不是加密、解密。

编码原理

这里的讨论的前提是使用 UTF-8 编码

Base64 算法的原理,是将输入流中的字节按每 3 个分为一组,然后每次取 6 个比特,将其转换成表格中对应的数据,一直重复到没有剩余的字符为止,转换表格如下:

IndexCharacterIndexCharacterIndexCharacterIndexCharacter
0A1B2C3D
4E5F6G7H
8I9J10K11L
12M13N14O15P
16Q17R18S19T
20U21V22W23X
24Y25Z26a27b
28c29d30e31f
32g33h34i35j
36k37l38m39n
40o41p42q43r
44s45t46u47v
48w49x50y51z
520531542553
564575586597
60861962+63/
继续阅读Base64 原理

MySQL 不完全入门指南

由于 MySQL 的整个体系太过于庞大,文章的篇幅有限,不能够完全的覆盖所有的方面。所以我会尽可能的从更加贴进我们日常使用的方式来进行解释。

小白眼中的 MySQL

首先,对于我们来说,MySQL 是个啥?我们从一个最简单的例子来回顾一下。

这可能就是最开始大家认知中的 MySQL。那 MySQL 中是怎么处理这个查询语句的呢?换句话说,它是如何感知到这串字符串是一个查询语句的?它是如何感知到该去哪张表中取数据?它是如何感知到该如何取数据?

到目前为止,都不知道。接下来我们一步一补来进行解析。

连接池

首先,要去 MySQL 执行命令,肯定是需要连接上 MySQL 服务器的,就像我们通过「用户名」和「密码」登陆网站一样。所以,我们首先要认识的就是连接池

这种池化技术的作用很明显,复用连接,避免频繁的销毁、创建线程所带来的开销。除此之外,在这一层还可以根据你的账号密码对用户的合法性、用户的权限进行校验。

每一个连接都对应一个线程,「服务器」 和 「MySQL」 都一样,服务器的一个线程从服务器的连接池中取出一个连接,发起查询语句。MySQL 服务器的线程从连接池中取出一个线程,继续后续的流程。

那么后面的流程是啥呢?当然是分析 SQL 语句了。

继续阅读MySQL 不完全入门指南

MySQL 中删除的数据都去哪儿了?

不知道大家有没有想过下面这件事?

我们平时调用 DELETE 在 MySQL 中删除的数据都去哪儿了?

这还用问吗?当然是被删除了啊

那么这里又有个新的问题了,如果在 InnoDB 下,多事务并发的情况下,如果事务A删除了 id=1 的数据,同时事务B又去读取 id=1 的数据,如果这条数据真的被删除了,那 MVCC 拿啥数据返回给用户呢?

没错,这就需要了解一下 MySQL 的多版本并发的原理相关的东西,感兴趣的可以去看我之前写的[这篇文章]()。

所以,实际情况中,调用了 DELETE 语句删除的数据并不会真正的被物理删除,这条数据其实还在那,只不过被打上了一个标记,标记已删除

继续阅读MySQL 中删除的数据都去哪儿了?

MySQL 到底是如何做到多版本并发的?

之前的文章简单的介绍了 MySQL 的事务隔离级别,它们分别是:读未提交、读已提交、可重复读、串行化。这篇文章我们就来探索一下 MySQL 事务隔离级别的底层原理。

本篇文章针对 InnoDB 存储引擎

多版本并发控制

我们知道,读未提交会造成脏读、幻读、不可重复读,读已提交会造成幻读、不可重复读,可重复读可能会有幻读,和串行化就不会有这些问题。

那 InnoDB 到底是怎么解决这些问题的呢?又或者,你有没有想过造成脏读、幻读、不可重复读的底层最根本的原因是什么呢?

这就是今天要聊的主角——MVCC(Multi-Version Concurrent Controll),也叫多版本并发控制。InnoDB 是一个支持多事务并发的存储引擎,它能让数据库中的读-写操作能够并发的进行,避免由于加锁而导致读阻塞。

正是由于有了 MVCC,在事务B更新 id=1 的数据时,事务A读取 id=1 的操作才不会被阻塞。而不阻塞的背后则是不加锁的一致性读。那什么是一致性读?

继续阅读MySQL 到底是如何做到多版本并发的?

啥是 MySQL 事务隔离级别?

之前发过一篇文章,简单了解 MySQL 中相关的锁,里面提到了,如果我们使用的 MySQL 存储引擎为 InnoDB ,并且其事务隔离级别是 RR 可重复读的话,是可以避免幻读的。

但是没想到,都 1202 年了都还有人杠,说 InnoDB 的 RR 隔离级别下会出现幻读,只能依靠 gap 和 next-key 这两个锁来防止幻读 ,最开始我还以为是他真的不知道这个点,就跟他聊,最后聊下来发现,发现是在钻牛角尖。

这个在下面讲到 可重复读 的隔离级别时会讲。

本来我觉得事务隔离级别这玩意儿太简单没啥可讲的,但是经过了上面这件事,我打算详细的把事务隔离给讲讲。接下来顺便就把 InnoDB 所有的事务隔离级别给搂一遍。

ACID

在聊事务隔离级别之前,我们需要知道 ACID 模型。

ACID 模型

分别代表:

继续阅读啥是 MySQL 事务隔离级别?

ArrayList 从源码角度剖析底层原理

对于 ArrayList 来说,我们平常用的最多的方法应该就是 addremove 了,本文就主要通过这两个基础的方法入手,通过源码来看看 ArrayList 的底层原理。

add

默认添加元素

这个应该是平常用的最多的方法了,其用法如下。

接下来我们就来看看 add 方法的底层源码。

ensureCapacityInternal 作用为:保证在不停的往 ArrayList 插入数据时,数组不会越界,并且实现自动扩容。

继续阅读ArrayList 从源码角度剖析底层原理