消息队列与数据库总结
形而上 Lv4

本文主要讲解消息队列与数据库相关的知识,重点讲解三部分知识点:

  1. Kafka 的架构与消息交互流程;

  2. 数据库事务的 4 大特性和分类;

  3. MySQL 相关的内容,比如索引、MySQL 调优等。

消息队列与数据库知识点

先来看看相关知识点汇总,如下图。首先为了防止歧义进行说明,本课时中提到的“队列“就是指“消息队列“。

消息队列

来看消息队列的应用场景,也就是队列能解决哪些问题。

  • 队列可以对应用进行解耦合,应用之间不用直接调用。

  • 可以通过队列来传递消息,完成通信。

  • 队列也可以用来执行异步任务,任务提交方无需等待结果。

  • 队列的另一个作用是削峰填谷,在突发流量时,可以通过队列做缓冲,不会对后端服务产生较大压力,当峰值过去时,可以逐渐消费堆积的数据,填平流量低谷。

  • 消息队列一般还提供了一写多读的能力,可以用来做消息的多播与广播。

关于队列还需要知道两个主要的消息协议。

  • JMS 是 Java 的消息服务,规定了 Java 使用消息服务的 API,在前面 Spring 的课时提到过,Spring 提供了支持 JMS 的组件。

  • AMQP 是高级消息队列协议,是应用层协议的一个开放标准,AMQP 不从 API 层进行限定,而是直接定义网络交换的数据格式,因此支持跨语言的能力,例如 RabbitMQ 就使用了 AMQP 实现。

再来对比几个常用的消息队列。

  • RabbitMQ

使用 Erlang 开发的开源消息队列,通过 Erlang 的 Actor 模型实现了数据的稳定可靠传输。支持 AMQP、XMPP、SMTP 等多种协议,因此也比较重量级。由于采用 Broker 代理架构,发送给客户端时先在中心队列排队,疑似 RabbitMQ的单机吞吐量在万级,不算很高。

  • ActiveMQ

可以部署于代理模式和 P2P 模式,支持多种协议,单机吞吐量在万级,但是 ActiveMQ 不够轻巧,对于队列较多的情况支持不是很好。并且有较低概率丢失消息。

  • RocketMQ

阿里开源的消息中间件,单机能够支持 10w 级的吞吐量,使用 Java 开发,具有高吞吐量、高可用性的特点、适合在大规模分布式系统中应用。

  • Kafka

由 Scala 开发的高性能跨语言分布式消息队列,单机吞吐量可以到达 10w 级,消息延迟在 ms 级。Kafka 是完全的分布式系统,Broker、Producer、Consumer 都原生自动支持分布式,依赖于 ZooKeeper 做分布式协调。Kafka 支持一写多读,消息可以被多个客户端消费,消息有可能会重复,但是不会丢失。本课时后面会对 Kafka 的架构进行详细介绍。

数据库中间件

数据库中间件一般提供了读写分离、数据库水平扩展的能力。下面主要介绍两个中间件。

一是 Sharding-Sphere,它是一个开源的分布式数据库中间件解决方案,由 Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar 这几个独立产品组成,适用不同使用场景。这几个产品都提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。 目前 Sharding-Sphere 已经进入 Apache 孵化,发展速度很快,可以重点关注。

二是 Mycat,它也提供了分库分表等能力,Mycat 基于 Proxy 代理模式,后端可以支持 MySQL、Oracle、DB2 等不同数据库实现,不过代理方式对性能会有一定影响

其他还有一些数据库中间件例如 Vitess 等,使用不算广泛,了解即可

数据库

对于数据库相关知识点,首先需要知道不同类型的数据库。

关系型数据库

常用的关系型数据库主要是 Oracle 和 MySQL。Oracle 功能强大,主要缺点就是贵。MySQL 是互联网行业中最流行的数据库,这不仅仅是因为 MySQL 免费,可以说关系数据库场景中你需要的功能,MySQL 都能很好得满足。后面的详解部分会详细介绍 MySQL 的一些知识点。

MariaDB 是 MySQL 的分支,由开源社区维护,MariaDB 虽然被看作 MySQL 的替代品,但与 MySQL 相比,它在扩展功能、存储引擎上都有非常好的改进,后续可以关注。

PostgreSQL也叫 PGSQL,PGSQL 类似于 Oracle 的多进程框架,可以支持高并发的应用场景。PG 几乎支持所有的 SQL 标准,支持类型相当丰富。PG 更加适合严格的企业应用场景,而 MySQL 更适合业务逻辑相对简单、数据可靠性要求较低的互联网场景。

NoSQL

NoSQL,就是 Not only SQL,一般指非关系型数据库。

Redis 就是非关系型数据库,它提供了持久化能力,支持多种数据类型。Redis 适用于数据变化快且数据大小可预测的场景。

MongoDB 是一个基于分布式文件存储的数据库,将数据存储为一个文档,数据结构由键值对组成。MongoDB 比较适合表结构不明确,且数据结构可能不断变化的场景,不适合有事务和复杂查询的场景。

HBase 是建立在 HDFS,也就是 Hadoop 文件系统之上的分布式面向列的数据库,类似于谷歌的大表设计,HBase 可以快速随机访问海量结构化数据。在表中它由行排序,一个表有多个列族以及每一个列族可以有任意数量的列。 HBase 依赖 HDFS 可以实现海量数据的可靠存储,适用于数据量大,写多读少,不需要复杂查询的场景。

Cassandra 是一个高可靠的大规模分布式存储系统。支持分布式的结构化 key-value 存储,以高可用性为主要目标。适合写多的场景,适合做一些简单查询,不适合用来做数据分析统计。

Pika 是一个可持久化的大容量类 Redis 存储服务, 兼容五种主要数据结构的大部分命令。Pika 使用磁盘存储,主要解决 Redis 大容量存储的成本问题。

NewSQL

NewSQL 数据库也越来越被大家关注,NewSQL 是指新一代关系型数据库。比较典型的有TiDB。

TiDB 是开源的分布式关系数据库,几乎完全兼容 MySQL,能够支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性。既适合在线事务处理,也适合在线分析处理。

另外一个比较著名的 NewSQL 是蚂蚁金服的 OceanBase。OB 是可以满足金融级的可靠性和数据一致性要求的数据库系统。需要使用事务,并且数据量比较大的时候,就比较适合使用 OB。不过目前 OB 已经商业化,不再开源。

最后来看数据库的范式。目前关系数据库有六种范式:第一范式、第二范式、第三范式、巴斯-科德范式(BCNF)、第四范式和第五范式。范式级别越高对数据表的要求越严格。

  • 要求最低的第一范式只要求表中字段不可用在拆分。

  • 第二范式在第一范式的基础上要求每条记录由主键唯一区分,记录中所有属性都依赖于主键。

  • 第三范式在第二范式的基础上,要求所有属性必须直接依赖主键,不允许间接依赖。

一般说来,数据库只需满足第三范式就可以了。

详解 Kafka

架构

下面来学习 Kafka 的架构。先结合如下的架构图来了解 Kafka 中的几个概念。

首先 Kafka 消息队列由三个角色组成,左面的是消息的生产方 Producer;中间是 Kafka 集群, Kafka 集群由多台 Kafka server 组成,每个 Server 称为一个 Broker,也就是消息代理;右面的是消息的消费方 Consumer。

Kafka 中消息是按照 Topic 进行划分的,一个 Topic 就是一个 Queue。在实际应用中,不同业务数据就可以设置为不同的 Topic。一个 Topic 可以有多个消费方,当生产方在某个 Topic 发出一条消息后,所有订阅了这个 Topic 的消费方都可以收到这条消息。

为了提高并行能力,Kafka 为每个 Topic 维护了多个 Partition 分区,每个分区可以看作一份追加类型的日志。 每个分区中的消息保证 ID 唯一且有序,新消息不断追加到尾部。Partition 实际存储数据时,会对按大小进行分段(Segment),来保证总是对较小的文件进行写操作,提高性能,方便管理。

如图中间部分,Partition 分布于多个 Broker 上。图中绿色的模块表示 Topic1 被分为了 3 个 Partition。每个 Partition 会被复制多份存在于不同的 Broker 上,如图中红色的模块,这样可以保证主分区出现问题时进行容灾。每个 Broker 可以保存多个 Topic 的多个 Partition。

Kafka 只保证一个分区内的消息有序,不能保证一个 Topic 的不同分区之间的消息有序。为了保证较高的处理效率,所有的消息读写都是在主 Partition 中进行,其他副本分区只会从主分区复制数据。Kafka 会在 ZooKeeper 上针对每个 Topic 维护一个称为 ISR(in-sync replica),就是已同步的副本集。如果某个主分区不可用了,Kafka 就会从 ISR 集合中选择一个副本作为新的主分区。

消息发布/消费流程

Kafka 通过对消费方进行分组管理来支持消息一写多读,流程如下图所示。

来看图中的例子,这个 Topic 分为 4 个 Partition,就是图中绿色的 P1到 P4,上部的生产方根据规则选择一个 Partition 进行写入,默认规则是轮询策略。也可以由生产方指定 Partition 或者指定 key 来根据 Hash 值选择 Partition。

消息的发送有三种方式:同步、异步以及 oneway。

  • 同步模式下后台线程中发送消息时同步获取结果,这也是默认模式。

  • 异步的模式允许生产者批量发送数据,可以极大的提高性能,但是会增加丢失数据的风险。

  • oneway 模式只发送消息不需要返回发送结果,消息可靠性最低,但是低延迟、高吞吐,适用于对可靠性要求不高的场景。

来看消息的消费,Consumer 按照 Group 来消费消息,Topic 中的每一条消息可以被多个 Consumer Group 消费,如上图中的 GroupA 和 GroupB。Kafka 确保每个 Partition 在一个 Group 中只能由一个 Consumer 消费。Kafka 通过 Group Coordinator 来管理 Consumer 实际负责消费哪个 Partition,默认支持 Range 和轮询分配。

Kafka 在 ZK 中保存了每个 Topic 中每个 Partition 在不同 Group 的消费偏移量 offset,通过更新偏移量保证每条消息都被消费

注意:用多线程来读取消息时,一个线程相当于一个 Consumer 实例。当 Consumer 的数量大于分区的数量的时候,有的 Consumer 线程会读取不到数据。

详解数据库事务

特性

数据库的特性是面试时考察频率非常高的题目,来看看数据库的 ACID 四大特性,如下图

第一个原子性,指事务由原子的操作序列组成,所有操作要么全部成功,要么全部失败回滚。

第二个事务的一致性,指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。比如在做多表操作时,多个表要么都是事务后新的值,要么都是事务前的旧值

第三个事务的隔离性,指多个用户并发访问数据库时,数据库为每个用户执行的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。事务的隔离级别在后文中介绍。

第四个事务的持久性,指一个事务一旦提交并执行成功,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

并发问题

在介绍数据的隔离级别之前,先看看没有隔离性的情况下数据库会出现哪些并发问题,如下图左侧部分所示。

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据,例如,账户 A 转帐给 B 500元,B 余额增加后但事务还没有提交完成,此时如果另外的请求中获取的是 B 增加后的余额,这就发生了脏读,因为事务如果失败回滚时,B 的余额就不应该增加。

不可重复读是指对于数据库中某个数据,一个事务范围内多次查询返回了不同的数据值,这是由于在多次查询之间,有其他事务修改了数据并进行了提交。

幻读是指一个事务中执行两次完全相同的查询时,第二次查询所返回的结果集跟第一个查询不相同。与不可重复读的区别在于,不可重复读是对同一条记录,两次读取的值不同。而幻读是记录的增加或删除,导致两次相同条件获取的结果记录数不同。

隔离级别

事务的四种隔离级别可以解决上述几种并发问题。如上图右侧内容所示,由上到下,四种隔离级别由低到高。

第一个隔离级别是读未提交,也就是可以读取到其他事务未提交的内容,这是最低的隔离级别,这个隔离级别下,前面提到的三种并发问题都有可能发生。

第二个隔离级别是读已提交,就是只能读取到其他事务已经提交的数据。这个隔离级别可以解决脏读问题。

第三个隔离级别是可重复读,可以保证整个事务过程中,对同数据的多次读取结果是相同的。这个级别可以解决脏读和不可重复读的问题。MySQL 默认的隔离级别就是可重复读。

最后一个隔离级别是串行化,这是最高的隔离级别,所有事务操作都依次顺序执行。这个级别会导致并发度下降,性能最差。不过这个级别可以解决前面提到的所有并发问题

事务分类

接下来看事务的分类,如下图。

第一个是扁平化事务,在扁平事务中,所有的操作都在同一层次,这也是我们平时使用最多的一种事务。它的主要限制是不能提交或者回滚事务的某一部分,要么都成功,要么都回滚。

为了解决第一种事务的弊端,就有了第二种带保存点的扁平事务。它允许事务在执行过程中回滚到较早的状态,而不是全部回滚。通过在事务中插入保存点,当操作失败后,可以选择回滚到最近的保存点处。

第三种事务是链事务,可以看做是第二种事务的变种。它在事务提交时,会将必要的上下文隐式传递给下一个事务,当事务失败时就可以回滚到最近的事务。不过,链事务只能回滚到最近的保存点,而带保存点的扁平化事务是可以回滚到任意的保存点。

第四种事务是嵌套事务,由顶层事务和子事务构成,类似于树的结构。一般顶层事务负责逻辑管理,子事务负责具体的工作,子事务可以提交,但真正提交要等到父事务提交,如果上层事务回滚,那么所有的子事务都会回滚。

最后一种类型是分布式事务。是指分布式环境中的扁平化事务。

常用的分布式事务解决方案如上图右侧所示,下面进行简要介绍。

第一个分布式事务解决方案是 XA 协议,是保证强一致性的刚性事务。实现方式有两段式提交和三段式提交。两段式提交需要有一个事务协调者来保证所有的事务参与者都完成了第一阶段的准备工作。如果协调者收到所有参与者都准备好的消息,就会通知所有的事务执行第二阶段提交。一般场景下两段式提交已经能够很好得解决分布式事务了,然而两阶段在即使只有一个进程发生故障时,也会导致整个系统存在较长时间的阻塞。三段式提交通过增加 pre-commit 阶段来减少前面提到的系统阻塞的时间。三段式提交很少在实际中使用,简单了解就可以了。

第二个分布式解决方案是 TCC,是满足最终一致性的柔性事务方案。TCC 采用补偿机制,核心思想是对每个操作,都要注册对应的确认和补偿操作。它分为三个阶段:Try 阶段主要对业务系统进行检测及资源预留;Confirm 阶段对业务系统做确认提交;Cancel 阶段是在业务执行错误,执行回滚,释放预留的资源。

第三种方案是消息一致性方案。基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么都成功要么都失败。下游应用订阅消息,收到消息后执行对应操作。

第四种方案可以了解一下阿里云中的全局事务服务 GTS,对应的开源版本是 Fescar。Fescar 基于两段式提交进行改良,剥离了分布式事务方案对数据库在协议支持上的要求。使用 Fescar 的前提是分支事务中涉及的资源,必须是支持 ACID 事务的关系型数据库。分支的提交和回滚机制,都依赖于本地事务来保障。 Fescar 的实现目前还存在一些局限,比如事务隔离级别最高支持到读已提交级别。

详解 MySQL

下面来学习互联网行业使用最为广泛的关系型数据库 MySQL,它的知识点结构图如下所示。

常用 SQL 语句

对于手写常用 SQL 语句,没有什么特殊的技巧,根据所列的语句类型多做一些练习就好。

数据类型

要知道 MySQL 都提供哪些基本的数据类型,不同数据类型占用的空间大小。可以按给出的分类进行记忆,不一一罗列。

引擎

介绍 MySQL 中主要的存储引擎。

  • MyISAM 是 MySQL 官方提供的存储引擎,其特点是支持全文索引,查询效率比较高,缺点是不支持事务、使用表级锁。
  • InnoDB 在 5.5 版本后成为了 MySQL 的默认存储引擎,特点是支持 ACID 事务、支持外键、支持行级锁提高了并发效率。
  • TokuDB 是第三方开发的开源存储引擎,有非常快的写速度,支持数据的压缩存储、可以在线添加索引而不影响读写操作。但是因为压缩的原因,TokuDB 非常适合访问频率不高的数据或历史数据归档,不适合大量读取的场景。

MySQL 中的锁,上面也提到了,MyIASAM 使用表级锁,InnoDB 使用行级锁。

  • 表锁开销小,加锁快,不会出现死锁;但是锁的粒度大,发生锁冲突的概率高,并发访问效率比较低。
  • 行级锁开销大,加锁慢,有可能会出现死锁,不过因为锁定粒度最小,发生锁冲突的概率低,并发访问效率比较高。
  • 共享锁也就是读锁,其他事务可以读,但不能写。MySQL 可以通过 lock in share mode 语句显示使用共享锁。
  • 排他锁就是写锁,其他事务不能读取,也不能写。对于 UPDATE、DELETE 和 INSERT 语句,InnoDB 会自动给涉及的数据集加排他锁,或者使用 select for update 显示使用排他锁。

存储过程与函数

MySQL 的存储过程与函数都可以避免开发人员重复编写相同的 SQL 语句,并且存储过程和函数都是在 MySQL 服务器中执行的,可以减少客户端和服务器端的数据传输

存储过程能够实现更复杂的功能,而函数一般用来实现针对性比较强的功能,例如特殊策略求和等。存储过程可以执行包括修改表等一系列数据库操作,而用户定义函数不能用于执行修改全局数据库状态的操作。

存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用。SQL 语句中不能使用存储过程,但可以使用函数。存储过程一般与数据库实现绑定,使用存储过程会降低程序的可移植性,应谨慎使用。

新特性

此外,可以去了解 MySQL8.0 的一些新特性,例如:

  • 默认字符集格式改为了 UTF-8;
  • 增加了隐藏索引的功能,隐藏后的索引不会被查询优化器使用,可以使用这个特性用于性能调试;
  • 支持了通用表表达式,使复杂查询中的嵌入表语句更加清晰;
  • 新增了窗口函数的概念,可以用来实现新的查询方式。

其中,窗口函数与 SUM、COUNT 等集合函数类似,但不会将多行查询结果合并,而是将结果放在多行中,即窗口函数不需要 GROUP BY。

索引

来看 MySQL 的索引,索引可以大幅增加数据库的查询的性能,在实际业务场景中,或多或少都会使用到。但是索引也是有代价的,首先需要额外的磁盘空间来保存索引;其次,对于插入、更新、删除等操作由于更新索引会增加额外的开销,因此索引比较适合用在读多写少的场景

首先学习 MySQL 索引类型。

  • 唯一索引,就是索引列中的值必须是唯一的,但是允许出现空值。这种索引一般用来保证数据的唯一性,比如保存账户信息的表,每个账户的 ID 必须保证唯一,如果重复插入相同的账户 ID 时 MySQL 返回异常。
  • 主键索引是一种特殊的唯一索引,但是它不允许出现空值。
  • 普通索引,与唯一索引不同,它允许索引列中存在相同的值。例如学生的成绩表,各个学科的分数是允许重复的,就可以使用普通索引。
  • 联合索引,就是由多个列共同组成的索引。一个表中含有多个单列的索引并不是联合索引,联合索引是对多个列字段按顺序共同组成一个索引。应用联合索引时需要注意最左原则,就是 where 查询条件中的字段必须与索引字段从左到右进行匹配。比如,一个用户信息表,用姓名和年龄组成了联合索引,如果查询条件是“姓名等于张三“,那么满足最左原则;如果查询条件是“年龄大于 20“,由于索引中最左的字段是姓名不是年龄,所以不能使用这个索引。
  • 全文索引,前面提到了,MyISAM 引擎中实现了这个索引,在 5.6 版本后 InnoDB 引擎也支持了全文索引,并且在 5.7.6 版本后支持了中文索引。全文索引只能在 CHAR、VARCHAR、TEXT 类型字段上使用,底层使用倒排索引实现。要注意对于大数据量的表,生成全文索引会非常消耗时间也非常消耗磁盘空间。

然后来看索引的实现。

B+ 树实现,B+ 树比较适合用作 > 或 < 这样的范围查询,是 MySQL 中最常使用的一种索引实现。

R-Tree 是一种用于处理多维数据的数据结构,可以对地理数据进行空间索引。不过实际业务场景中使用的比较少。

Hash 是使用散列表来对数据进行索引,Hash 方式不像 B-Tree 那样需要多次查询才能定位到记录,因此 Hash 索引的效率高于 B-Tree,但是不支持范围查找和排序等功能。实际使用的也比较少。

FullText 就是前面提到的全文索引,是一种记录关键字与对应文档关系的倒排索引

调优

MySQL 的调优也是研发人员需要掌握的一项技能,一般 MySQL 调优有如下图所示的四个纬度。

  • 第一个纬度是针对数据库设计、表结构设计以及索引设置纬度进行的优化;
  • 第二个纬度是对我们业务中使用的 SQL 语句进行优化,例如调整 where 查询条件;
  • 第三个纬度是对 MySQL 服务的配置进行优化,例如对链接数的管理,对索引缓存、查询缓存、排序缓存等各种缓存大小进行优化;
  • 第四个纬度是对硬件设备和操作系统设置进行优化,例如调整操作系统参数、禁用 swap、增加内存、升级固态硬盘等等。

这四个纬度从优化的成本角度来讲,从左到右优化成本逐渐升高;从优化效果角度来看,从右到左优化的效果更高。

对于研发人员来说,前两个纬度与业务息息相关,因此需要重点掌握,后两个纬度更适合 DBA 进行深入学习,简单了解就好。

那么,重点来看前两个纬度,要点如下图所示。

先看到图中左边的模块,关于表结构和索引的优化,应该掌握如下原则。

  1. 要在设计表结构时,考虑数据库的水平与垂直扩展能力,提前规划好未来1年的数据量、读写量的增长,规划好分库分表方案。比如设计用户信息表,预计1年后用户数据10亿条,写QPS约5000,读QPS30000,可以设计按UID纬度进行散列,分为4个库每个库32张表,单表数据量控制在KW级别。
  2. 要为字段选择合适的数据类型,在保留扩展能力的前提下,优先选用较小的数据结构。例如保存年龄的字段,要使用TINYINT而不要使用INT。
  3. 可以将字段多的表分解成多个表,必要时增加中间表进行关联。假如一张表有40~50个字段显然不是一个好的设计。
  4. 一般来说,设计关系数据库时需要满足第三范式,但为了满足第三范式,我们可能会拆分出多张表。而在进行查询时需要对多张表进行关联查询,有时为了提高查询效率,会降低范式的要求,在表中保存一定的冗余信息,也叫做反范式。但要注意反范式一定要适度。
  5. 要擅用索引,比如为经常作为查询条件的字段创建索引、创建联合索引时要根据最左原则考虑索引的复用能力,不要重复创建索引;要为保证数据不能重复的字段创建唯一索引等等。不过要注意索引对插入、更新等写操作是有代价的,不要滥用索引,比如像性别这样唯一很差的字段就不适合建立索引。
  6. 列字段尽量设置为not null。MySQL难以对使用null的列进行查询优化,允许null会使索引、索引统计和值更加复杂,允许null值的列需要更多的存储空间,还需要MySQL内部进行特殊处理。
  7. 再看到如图右边所示的模块,对SQL语句进行优化的原则
  8. 要找到最需要优化的SQL语句。要么是使用最频繁的语句,要么是优化后提高最明显的语句,可以通过查询 MySQL的慢查询日志来发现需要进行优化的SQL语句;
  9. 要学会利用 MySQL 提供的分析工具。例如使用 Explain 来分析语句的执行计划,看看是否使用了索引,使用了哪个索引,扫描了多少记录,是否使用文件排序等等。或者利用 Profile 命令来分析某个语句执行过程中各个分步的耗时。
  10. 要注意使用查询语句是要避免使用 SELECT *,而是应该指定具体需要获取的字段。原因一是可以避免查询出不需要使用的字段,二是可以避免查询列字段的元信息。
  11. 是尽量使用 prepared statements,一个是它性能更好,另一个是可以防止 SQL 注入。
  12. 要尽量使用索引扫描来进行排序,也就是尽量在有索引的字段上进行排序操作。

考察点

  1. 必须了解消息队列、数据库的基本原理、使用场景以及常用队列、数据库的特点。比如消息队列适用于异步处理和削峰填谷的场景;Kafka 在提供高可用性的前提下实现了 0 消息丢失的高性能分布式队列服务;MySQL 提供了多种引擎可以支持事务型与非事务型的关系对象库服务等等。
  2. 要了解 Kafka 的架构和消息处理流程,明白 Kafka 是如何通过 Partition 来保证并发能力与冗余灾备的;了解消费组是如何保证每个 Consumer 实例不会获取到重复消息的
  3. 要深刻理解数据库事务的 ACID 特性,了解并发事务可能导致的并发问题和不同的数据库隔离级别如何解决这些并发问题。
  4. 要牢牢掌握常用的 MySQL 语句,比如 WHERE 条件查询语句、JOIN 关联语句、ORDER BY 排序语句等等。还要熟悉常用的自带函数,例如 SUM、COUNT 等等。
  5. 了解 MySQL 数据库不同引擎的特点及不同类型的索引实现。比如知道最常使用的 InnoDB 非常擅长事务处理,MyISAM 比较适合非事务的简单查询场景。比如知道 MySQL 的唯一索引、联合索引、全文索引等不同索引类型,以及最常使用等 B+ 树索引实现等等。

加分项

如果想要在面试中获得更好的表现,还应该了解下面这些加分项。

  1. 要了解新特性,不论是 Kafka 还是 MySQL,都要了解一下新版本特性。例如 MySQL8.0 中提供了窗口函数来支持新的查询方式;支持通用表表达式,使复杂查询中的嵌入表语句更加清晰等等。
  2. 要知道数据库表设计原则,如果有过线上业务数据库的设计经验就更好了,就能够知道如何对容量进行评估,也知道适当分库分表来保证未来服务的可扩展性,这会对面试起到积极的影响。
  3. 最好有过数据库调优经验,例如明明建立了索引的语句,但是查询效率还是很慢,通过 Explain 分析发现表中有多个索引,MySQL 的优化器选用了错误的索引,导致查询效率偏低,然后通过在 SQL 语句中使用 use index 来指定索引解决。
  4. 有过 Kafka 等主流消息队列使用经验,并且知道应该如何在业务场景下进行调优。例如日志推送的场景,对小概率消息丢失可以容忍,可以设置异步发送消息。而对应金融类业务,需要设置同步发送消息,并设置最高的消息可靠性,把 request.required.acks 参数设置为 -1。

真题汇总

  • 第 2 题,可以从消息的发送者保证投递到消息队列、消息对象自身的高可用、消费方处理完成后修改 offset 这三个方面来保证消息的可靠性。这个题目可以结合 Kafka 的消息发送同步、异步,消息可靠性配置来回答。
  • 第 3 题可以从两个方面解决消息重复:一个是通过对消息处理实现幂等,消除消息重复的影响;另一个是使用 Redis 来进行消息去重,避免重复消息的处理。
  • 第 4 题可以从创建索引、减少关联查询、优化 SQL 查询条件等方面展开。
  • 第 6 题可以从 MySQL 调优部分讲解的相关原则这个角度来回答。
  • 本文标题:消息队列与数据库总结
  • 本文作者:形而上
  • 创建时间:2021-10-23 12:12:00
  • 本文链接:https://deepter.gitee.io/2021_10_23_msg_mysql/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!