【后端开发】服务开发场景之高性能(CDN与负载均衡,数据库优化,消息队列)

【后端开发】服务开发场景之高性能(CDN与负载均衡,数据库优化,消息队列)

文章目录

按照面试 & 笔试题的方式整理的八股知识哈,长期学习计划

1、内容分发网络(CDN ) & 负载均衡算法

CDN是什么?(静态资源加速)

内容分发网络(Content Delivery Network,CDN)是什么?

  • 内容
    指的是静态资源比如图片、视频、文档、JS、CSS、HTML
  • 分发网络
    指的是将这些静态资源分发到位于多个不同的地理位置机房中的服务器上 ,这样,就可以实现静态资源的就近访问比如北京的用户直接访问北京机房的数据。
  • 所以,简单来说:
    CDN 就是将静态资源分发到多个不同的地方以实现就近访问,进而加快静态资源的访问速度,减轻服务器以及带宽的负担。
  • 类似于京东建立的庞大的仓储运输体系。
    京东物流在全国拥有非常多的仓库,仓储网络几乎覆盖全国所有区县。这样的话,用户下单的第一时间,商品就从距离用户最近的仓库,直接发往对应的配送站。

CDN的应用场景?(对比全站加速,分布式)

  • 全站加速(不同云服务商叫法不同,腾讯云叫 ECDN、阿里云叫 DCDN)既可以加速静态资源又可以加速动态资源 ,内容分发网络(CDN)主要针对的是 静态资源

  • 既然是就近访问,为什么不直接将服务部署在多个不同的地方呢

    成本太高,需要部署多份相同的服务
    静态资源通常占用空间比较大且经常会被访问到 ,如果直接使用服务器或者缓存来处理静态资源请求的话,对系统资源消耗非常大,可能会影响到系统其他服务的正常运行。

  • 同一个服务在在多个不同的地方部署多份 (比如同城灾备、异地灾备、同城多活、异地多活)是为了实现系统的高可用而不是就近访问

CDN的原理?(缓存预热,GSLB负载均衡,防盗链)

搞懂下面 3 个问题也就搞懂了 CDN 的工作原理:

  1. 静态资源是如何被缓存到 CDN 节点中的?
  2. 如何找到最合适的 CDN 节点?
  3. 如何防止静态资源被盗用?

静态资源是如何被缓存到 CDN 节点中的?

  • 通过 预热 的方式将源站的资源同步到 CDN 的节点中。这样的话,用户首次请求资源可以直接从 CDN 节点中取,无需回源。
  • 如果不预热的话,你访问的资源可能不在 CDN 节点中,这个时候 CDN 节点将请求源站获取资源,这个过程是大家经常说的 回源
  • 如果资源有更新的话,你也可以对其 刷新 ,删除 CDN 节点上缓存的旧资源,并强制 CDN 节点回源站获取最新资源。
  • 几乎所有云厂商提供的 CDN 服务都具备缓存的刷新和预热功能(根据URL,目录,正则判断资源是否有更新)
  • 命中率 和 回源率 是衡量 CDN 服务质量两个重要指标。命中率越高越好,回源率越低越好

如何找到最合适的 CDN 节点?

  • GSLB (Global Server Load Balance,全局负载均衡)是 CDN 的大脑,负责多个 CDN 节点之间相互协作,最常用的是基于 DNS 的 GSLB。
  • CDN 会通过 GSLB 找到最合适的 CDN 节点
    1、浏览器向 DNS 服务器发送域名请求;
    2、DNS 服务器向根据 CNAME( Canonical Name ) 别名记录向 GSLB 发送请求;
    3、GSLB 返回性能最好(通常距离请求地址最近)的 CDN 节点(边缘服务器,真正缓存内容的地方)的地址给浏览器;
    4、浏览器直接访问指定的 CDN 节点。
  • GSLB 内部可以看作是 CDN 专用 DNS 服务器和负载均衡系统组合。GSLB 会根据请求的 IP 地址、CDN 节点状态(比如负载情况、性能、响应时间、带宽)等指标来综合判断具体返回哪一个 CDN 节点的地址。

如何防止资源被盗刷?

  • 解决这个问题最常用最简单的办法设置 Referer 防盗链,具体来说就是根据 HTTP 请求的头信息里面的 Referer 字段对请求进行限制 。我们可以通过 Referer 字段获取到当前请求页面的来源页面的网站地址,这样我们就能确定请求是否来自合法的网站。
  • CDN 服务提供商几乎都提供了这种比较基础的防盗链机制。(开启防盗链配置,黑名单,白名单)
  • 通常情况下,我们会配合其他机制来确保静态资源不被盗用,一种常用的机制是 **时间戳防盗链 。**相比之下,时间戳防盗链 的安全性更强一些。时间戳防盗链加密的 URL 具有时效性,过期之后就无法再被允许访问。
  • 时间戳防盗链的 URL 通常会有两个参数 一个是签名字符串,一个是过期时间。签名字符串一般是通过对用户设定的加密字符串、请求路径、过期时间通过 MD5 哈希算法取哈希的方式获得

什么是负载均衡?(服务端/客户端,传输层/应用层)

负载均衡是什么

  • 将用户请求分摊到不同的服务器上处理,以提高系统整体的并发处理能力以及可靠性。负载均衡服务可以有由专门的软件或者硬件来完成,一般情况下,硬件的性能更好,软件的价格更便宜。
  • 负载均衡是一种比较常用且实施起来较为简单的提高系统并发能力和可靠性的手段,不论是单体架构的系统还是微服务架构的系统几乎都会用到。

负载均衡分为哪几种?

  • 负载均衡可以简单分为 服务端负载均衡 和 客户端负载均衡 这两种。服务端负载均衡涉及到的知识点更多,工作中遇到的也比较多。

  • 服务端负载均衡

    服务端负载均衡 主要应用在 系统外部请求 和 网关层 之间,可以使用 软件 或者 硬件 实现。
    硬件负载均衡 通过专门的硬件设备(比如 F5、A10、Array )实现负载均衡功能,缺点就是实在是太贵了,基础款的 F5 最低也要 20 多万。
    软件负载均衡通过软件(比如 LVS、Nginx、HAproxy )实现负载均衡功能,基础款就几千。

  • 根据 OSI 模型,服务端负载均衡还可以分为:

    二层负载均衡

    三层负载均衡

    四层负载均衡

    七层负载均衡
    最常见的是四层和七层负载均衡。 四层负载均衡性能很强,七层负载均衡功能更强!不过性能差异一般不明显。

  • 四层负载均衡 工作在 OSI 模型第四层,也就是传输层,这一层的主要协议是 TCP/UDP,负载均衡器在这一层能够看到数据包里的源端口地址以及目的端口地址,会基于这些信息通过一定的负载均衡算法将数据包转发到后端真实服务器 。也就是说,四层负载均衡的核心就是 IP+端口 层面的负载均衡,不涉及具体的报文内容

  • 七层负载均衡 工作在 OSI 模型第七层,也就是应用层,这一层的主要协议是 HTTP 。这一层的负载均衡比四层负载均衡路由网络请求的方式更加复杂,它会读取报文的数据部分 (比如说我们的 HTTP 部分的报文),然后根据读取到的数据内容(如 URL、Cookie)做出负载均衡决策 。也就是说,七层负载均衡器的核心是报文内容(如 URL、Cookie)层面的负载均衡,执行第七层负载均衡的设备通常被称为 反向代理服务器

  • 我们通常会使用 Nginx 来做七层负载均衡 ,LVS(Linux Virtual Server 虚拟服务器, Linux 内核的 4 层负载均衡)来做四层负载均衡。不过,LVS 这个绝大部分公司真用不上

  • 客户端负载均衡

    客户端负载均衡 主要应用于系统内部的不同的服务之间,可以使用现成的负载均衡组件来实现

    客户端会自己维护一份服务器的地址列表,发送请求之前,客户端会根据对应的负载均衡算法来选择具体某一台服务器处理请求

负载均衡的原理,算法实现?

  • 随机法

    最简单粗暴 的负载均衡算法。

    如果没有配置权重的话,所有的服务器被访问到的概率都是相同的。如果配置权重的话,权重越高的服务器被访问的概率就越大。

    不过,随机算法有一个比较明显的缺陷:部分机器在一段时间之内无法被随机到,毕竟是概率算法,就算是大家权重一样, 也可能会出现这种情况。于是有了轮询法。

  • 轮询法

    轮询法是挨个轮询服务器处理,也可以设置权重。

    如果没有配置权重的话,每个请求按时间顺序逐一分配到不同的服务器处理。如果配置权重的话,权重越高的服务器被访问的次数就越多。

  • 两次随机法

    两次随机法的好处是可以动态地调节后端节点的负载,使其更加均衡。如果只使用一次随机法,可能会导致某些服务器过载,而某些服务器空闲。

  • 哈希法

    在服务器数量不变的情况下,相同参数的请求总是发到同一台服务器处理,比如同个 IP 的请求、同一个用户的请求。

  • 一致性 Hash 法

    常规哈希法在服务器数量变化时,哈希值会重新落在不同的服务器上,这明显违背了使用哈希法的本意。而一致性哈希法的核心思想是将数据和节点都映射到一个哈希环上,然后根据哈希值的顺序来确定数据属于哪个节点。当服务器增加或删除时,只影响该服务器的哈希,而不会导致整个服务集群的哈希键值重新分布。

  • 最小连接法

    最少连接数基于一个服务器连接数越多,负载就越高这一理想假设。然而, 实际情况是连接数并不能代表服务器的实际负载,有些连接耗费系统资源更多,有些连接不怎么耗费系统资源。

  • 最少活跃法

    活动连接数可以理解为当前正在处理的请求数。活跃数越低,说明处理能力越强。

  • 最快响应时间法

    最快响应时间法以响应时间为标准来选择具体是哪一台服务器处理。客户端会维持每个服务器的响应时间,每次请求挑选响应时间最短的。这种算法可以使得请求被更快处理,但可能会造成流量过于集中于高性能服务器的问题。

应用层负载均衡怎么做?

  • 1、DNS 解析

    在 DNS 服务器中为同一个主机记录配置多个 IP 地址,这些 IP 地址对应不同的服务器。当用户请求域名的时候,DNS 服务器采用轮询算法返回 IP 地址,这样就实现了轮询版负载均衡。

  • 2、反向代理

    客户端将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器,获取数据后再返回给客户端。对外暴露的是反向代理服务器地址,隐藏了真实服务器 IP 地址
    Nginx 就是最常用的反向代理服务器,它可以将接收到的客户端请求以一定的规则(负载均衡策略)均匀地分配到这个服务器集群中所有的服务器上。

  • 3、HTTP 重定向

    HTTP重定向服务器是一台普通的应用服务器,其唯一个功能就是根据用户的HTTP请求计算出一台真实的服务器地址,并将该服务器地址写入HTTP重定向响应中。引用

2、数据库优化

读写分离怎么做?(读并发大)

读写分离是什么,怎么实现?

  • 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话,就能够小幅提升写性能,大幅提升读性能。
  • 想要实现读写分离一般包含如下几步:
    部署多台数据库,选择其中的一台作为主数据库,其他的一台或者多台作为从数据库。保证主数据库和从数据库之间的数据是实时同步的,这个过程也就是我们常说的主从复制。系统将写请求交给主数据库处理,读请求交给从数据库处理。
  • 一般情况下,我们都会选择一主多从,也就是一台主数据库负责写,其他的从数据库负责读。主库和从库之间会进行数据同步,以保证从库中数据的准确性。
  • 我们可以在应用和数据中间加了一个代理层 。应用程序所有的数据请求都交给代理层处理,代理层负责分离读写请求,将它们路由到对应的数据库 中。提供类似功能的中间件有 MySQL Router(官方, MySQL Proxy 的替代方案)、Atlas(基于 MySQL Proxy)、MaxScale、MyCat。
  • 也可以通过引入第三方组件来帮助我们读写请求,目前在各种互联网公司中用的最多的。sharding-jdbc ,直接引入 jar 包即可使用,节省了很多运维的成本。

主从复制原理是什么?

  • MySQL binlog(二进制日志文件) 主要记录了 MySQL 数据库中数据的所有变化(数据库执行的所有 DDL 和 DML 语句)。因此,我们根据主库的 MySQL binlog 日志就能够将主库的数据同步到从库中。
  • 流程
    1、主库将数据库中数据的变化写入到 binlog
    2、从库连接主库
    3、从库会创建一个 I/O 线程向主库请求更新的 binlog
    4、主库会创建一个 binlog dump 线程来发送 binlog从库中的 I/O 线程负责接收
    5、从库的 I/O 线程将接收的 binlog 写入到 relay log 中。
    6、从库的 SQL 线程读取 relay log 同步数据到本地(也就是再执行一遍 SQL )。

如何避免主从延迟?

  • 读写分离对于提升数据库的并发非常有效,但是,同时也会引来一个问题:主库和从库的数据存在延迟。这个时间差就导致了主库和从库的数据不一致性问题 。这也就是我们经常说的 主从同步延迟

  • 强制将读请求路由到主库处理

    这种方案虽然会增加主库的压力,但可以将那些必须获取最新数据的读请求都交给主库处理。

  • 什么情况下会出现主从延迟?

    从库 I/O 线程接收 binlog 的速度跟不上主库写入 binlog 的速度,导致从库 relay log 的数据滞后于主库 binlog 的数据;

    从库 SQL 线程执行 relay log 的速度跟不上从库 I/O 线程接收 binlog 的速度,导致从库的数据滞后于从库 relay log 的数据。

  • 从库机器性能比主库差:从库接收 binlog 并写入 relay log 以及执行 SQL 语句的速度会比较慢(也就是 T2-T1 和 T3-T2 的值会较大),进而导致延迟。解决方法是选择与主库一样规格或更高规格的机器作为从库,或者对从库进行性能优化,比如调整参数、增加缓存、使用 SSD 等

  • 从库处理的读请求过多:从库需要执行主库的所有写操作,同时还要响应读请求,如果读请求过多,会占用从库的 CPU、内存、网络等资源,影响从库的复制效率(也就是 T2-T1 和 T3-T2 的值会较大,和前一种情况类似)。解决方法是引入缓存(推荐)、使用一主多从的架构,将读请求分散到不同的从库,或者使用其他系统来提供查询的能力,比如将 binlog 接入到 Hadoop、Elasticsearch 等系统中。

  • 大事务:运行时间比较长,长时间未提交的事务就可以称为大事务。由于大事务执行时间长,并且从库上的大事务会比主库上的大事务花费更多的时间和资源,因此非常容易造成主从延迟。解决办法是避免大批量修改数据,尽量分批进行。类似的情况还有执行时间较长的慢 SQL ,实际项目遇到慢 SQL 应该进行优化。

分库分表怎么做?(数据量大)

读写分离主要应对的是数据库读并发,没有解决数据库存储问题。试想一下:如果 MySQL 一张表的数据量过大怎么办?

换言之,我们该如何解决 MySQL 的存储压力呢?

分库分表是什么?

  • 分库 就是将数据库中的数据分散到不同的数据库上,可以垂直分库,也可以水平分库。
  • 垂直分库 就是把单一数据库按照业务进行划分,不同的业务使用不同的数据库 ,进而将一个数据库的压力分担到多个数据库。
  • 水平分库 是把同一个表按一定规则拆分到不同的数据库中,每个库可以位于不同的服务器上,这样就实现了水平扩展,解决了单表的存储和性能瓶颈的问题。
  • 分表 就是对单表的数据进行拆分,可以是垂直拆分,也可以是水平拆分。
  • 垂直分表 是对数据表列的拆分,把一张列比较多的表拆分为多张表。我们可以将用户信息表中的一些列单独抽出来作为一个表。
  • 水平分表 是对数据表行的拆分,把一张行比较多的表拆分为多张表 ,可以解决单一表数据量过大的问题。
  • 水平拆分只能解决单表数据量大的问题,为了提升性能,我们通常会选择将拆分后的多张表放在不同的数据库中。也就是说,水平分表通常和水平分库同时出现

什么情况下需要分库分表?

  • 单表的数据达到千万级别以上,数据库读写速度比较缓慢。
  • 数据库中的数据占用的空间越来越大,备份时间越来越长
  • 应用的并发量太大(应该优先考虑其他性能优化方法,而非分库分表)。

常见的分片算法有哪些?

  • 分片算法主要解决了数据被水平分片之后,数据究竟该存放在哪个表的问题

  • 哈希分片:求指定分片键的哈希,然后根据哈希值确定数据应被放置在哪个表中。哈希分片比较适合随机读写的场景,不太适合经常需要范围查询的场景。

  • 范围分片 :按照特定的范围区间(比如时间区间、ID 区间)来分配数据,比如 将 id1~299999 的记录分到第一个表, 300000~599999 的分到第二个表。范围分片适合需要经常进行范围查找且数据分布均匀的场景,不太适合随机读写的场景(数据未被分散,容易出现热点数据的问题)。

  • 映射表分片 :使用一个单独的表(称为映射表)来存储分片键和分片位置的对应关系。映射表分片策略可以支持任何类型的分片算法,如哈希分片、范围分片等。映射表分片策略是可以灵活地调整分片规则,不需要修改应用程序代码或重新分布数据。不过,这种方式需要维护额外的表,还增加了查询的开销和复杂度

  • 地理位置分片 :很多 NewSQL 数据库都支持地理位置分片算法,也就是根据地理位置(如城市、地域)来分配数据。

  • 融合算法分片:灵活组合多种分片算法,比如将哈希分片和范围分片组合。

分片键如何选择?

  • 分片键(Sharding Key)是数据分片的关键字段 。分片键的选择非常重要,它关系着数据的分布和查询效率
  • 一般来说,分片键应该具备以下特点:
    具有共性,即能够覆盖绝大多数的查询场景,尽量减少单次查询所涉及的分片数量 ,降低数据库压力;
    具有离散性,即能够将数据均匀地分散到各个分片上,避免数据倾斜和热点问题
    具有稳定性,即分片键的值不会发生变化 ,避免数据迁移和一致性问题;
    具有扩展性,即能够支持分片的动态增加和减少,避免数据重新分片的开销。
  • 实际项目中,分片键很难满足上面提到的所有特点,需要权衡一下。并且,分片键可以是表中多个字段的组合,例如取用户 ID 后四位作为订单 ID 后缀。

分库分表会带来什么问题呢?

  • join 操作:同一个数据库中的表分布在了不同的数据库中,导致无法使用 join 操作。这样就导致我们需要手动进行数据的封装.
  • 事务问题:同一个数据库中的表分布在了不同的数据库中,如果单个操作涉及到多个数据库,那么数据库自带的事务就无法满足我们的要求。这个时候,需要引入分布式事务
  • 分布式 ID:分库之后, 数据遍布在不同服务器上的数据库,数据库的自增主键已经没办法满足生成的主键唯一了。需要为我们的系统引入分布式 ID
  • 跨库聚合查询问题:分库分表会导致常规聚合查询操作,如 group by,order by 等变得异常复杂。这是因为这些操作需要在多个分片上进行数据汇总和排序,而不是在单个数据库上进行。为了实现这些操作,需要编写复杂的业务代码,或者使用中间件来协调分片间的通信和数据传输。这样会增加开发和维护的成本,以及影响查询的性能和可扩展性。

分库分表有没有什么比较推荐的方案?

  • ShardingSphere 项目(包括 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar)是当当捐入 Apache 的,目前主要由京东数科的一些巨佬维护。

分库分表后,数据怎么迁移呢?

  • 比较简单同时也是非常常用的方案就是停机迁移,写个脚本老库的数据写到新库中。
  • 考虑双写方案。对老库的更新操作(增删改),同时也要写入新库(双写)。如果操作的数据不存在于新库的话,需要插入到新库中。 这样就能保证,咱们新库里的数据是最新的。
  • 迁移过程,双写只会让被更新操作过的老库中的数据同步到新库,我们还需要自己写脚本将老库中的数据和新库的数据做比对。如果新库中没有,那咱们就把数据插入到新库。如果新库有,旧库没有,就把新库对应的数据删除(冗余数据清理)

数据冷热分离怎么做?(高频数据)

数据冷热分离是指根据数据的访问频率和业务重要性,将数据分为冷数据和热数据,冷数据一般存储在存储在低成本、低性能的介质中,热数据高性能存储介质中。

冷热数据到底如何区分呢?

  • 时间维度区分:按照数据的创建时间、更新时间、过期时间等,将一定时间段内的数据视为热数据,超过该时间段的数据视为冷数据。订单系统可以将 1 年前的订单数据作为冷数据。几年前的数据并不一定都是热数据,例如一些优质文章发表几年后依然有很多人访问
  • 访问频率区分:将高频访问的数据视为热数据,低频访问的数据视为冷数据。例如,内容系统可以将浏览量非常低的文章作为冷数据,浏览量较高的文章作为热数据。

冷热分离的思想在生活中有哪些应用?

  • 邮件系统中,可以将近期的比较重要的邮件放在收件箱,将比较久远的不太重要的邮件存入归档。
  • 日常生活中,可以将常用的物品放在显眼的位置,不常用的物品放入储藏室或者阁楼。
  • 图书馆中,可以将最受欢迎和最常借阅的图书单独放在一个显眼的区域,将较少借阅的书籍放在不起眼的位置。

冷数据如何迁移?

  • 业务层代码实现:当有对数据进行写操作时,触发冷热分离的逻辑,**判断数据是冷数据还是热数据,冷数据就入冷库,热数据就入热库。**这种方案会影响性能且冷热数据的判断逻辑不太好确定,还需要修改业务层代码,因此一般不会使用。
  • 任务调度:可以利用 xxl-job 或者其他分布式任务调度平台定时去扫描数据库 ,找出满足冷数据条件的数据,然后批量地将其复制到冷库中,并从热库中删除 。这种方法修改的代码非常少,非常适合按照时间区分冷热数据的场景

冷数据如何存储?

  • 冷数据的存储要求主要是容量大,成本低,可靠性高,访问速度可以适当牺牲。
  • 中小厂:直接使用 MySQL/PostgreSQL 即可(不改变数据库选型和项目当前使用的数据库保持一致)
  • 大厂:Hbase(常用)、RocksDB、Doris、Cassandra

SQL优化手段有哪些?

可以参考【八股】2023秋招八股复习笔记4(MySQL & Redis等)中的索引优化

深度分页如何进行优化?

查询偏移量过大的场景我们称为深度分页,这会导致查询性能较低,例如:

sql 复制代码
# MySQL 在无法利用索引的情况下跳过1000000条记录后,再获取10条记录
SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10

怎么优化?

1、范围查询:当可以保证 ID 的连续性时,根据 ID 范围进行分页

sql 复制代码
# 查询指定 ID 范围的数据
SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id
# 也可以通过记录上次查询结果的最后一条记录的ID进行下一页的查询:
SELECT * FROM t_order WHERE id > 100000 LIMIT 10

2、子查询:先查询出 limit 第一个参数对应的主键值,再根据这个主键值再去过滤并 limit

sql 复制代码
# 通过子查询来获取 id 的起始值,把 limit 1000000 的条件转移到子查询
SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order limit 1000000, 1) LIMIT 10;

3、延迟关联:跟子查询的优化思路一样,都是把条件转移到主键索引树,减少回表的次数。不同点是,延迟关联使用了 INNER JOIN(内连接) 包含子查询。

sql 复制代码
SELECT t1.* FROM t_order t1
INNER JOIN (SELECT id FROM t_order limit 1000000, 10) t2
ON t1.id = t2.id;

3、消息队列

消息队列是什么,什么时候用?

消息队列是什么?

  • 消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。参与消息传递的双方称为 生产者 和 消费者 ,生产者负责发送消息,消费者负责处理消息。
  • 我们知道操作系统中的进程通信的一种很重要的方式就是消息队列。我们这里提到的消息队列稍微有点区别,更多指的是各个服务以及系统内部各个组件/模块之前的通信,属于一种 中间件 。
  • 中间件就是一类为应用软件服务的软件 ,应用软件是为用户服务的,用户不会接触或者使用到中间件
    除了消息队列之外,常见的中间件还有 RPC 框架、分布式组件、HTTP 服务器、任务调度框架、配置中心、数据库层的分库分表工具和数据迁移工具等等。

消息队列有什么用?

  • 通常来说,使用消息队列主要能为我们的系统带来下面三点好处:
    通过异步处理提高系统性能(减少响应所需时间)
    削峰/限流
    降低系统耦合性
  • 其他的一些应用场景,例如实现分布式事务、顺序保证和数据流处理

消息队列的应用例子

  • 异步提高性能:
    比如用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功,以免交易纠纷。这就类似我们平时手机订火车票和电影票。
  • 削峰/限流
    在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。
  • 解耦
    商城系统分为用户、订单、财务、仓储、消息通知、物流、风控等多个服务。用户在完成下单后,需要调用财务(扣款)、仓储(库存管理)、物流(发货)、消息通知(通知用户发货)、风控(风险评估)等服务。使用消息队列后,下单操作和后续的扣款、发货、通知等操作就解耦了,下单完成发送一个消息到消息队列,需要用到的地方去订阅这个消息进行消息即可。
  • 实现分布式事务
    分布式事务的解决方案之一就是 MQ 事务,事务允许事件流应用将消费,处理,生产消息整个过程定义为一个原子操作。
  • 顺序保证:处理数据的顺序有严格要求的。
  • 数据流处理:分布式系统产生的海量数据流,如业务日志、监控数据、用户行为等

使用消息队列会带来哪些问题?

  • 系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入 MQ 之前,你不用考虑消息丢失或者说 MQ 挂掉等等的情况。
  • 系统复杂性提高: 加入 MQ 之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
  • 一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!

有哪些可以用的消息队列,如何选型?

**JMS **

  • JMS(JAVA Message Service,java 消息服务)是 Java 的消息服务,JMS 的客户端之间可以通过 JMS 服务进行异步的消息传输。
  • 两种消息模型:
    点到点(P2P)模型
    发布/订阅(Pub/Sub)模型

RPC 和消息队列的区别

  • 通信方式:RPC 是双向直接网络通讯,消息队列是单向引入中间载体的网络通讯。
  • 架构:消息队列需要把消息存储起来,RPC 则没有这个要求。
  • 请求处理的时效性:通过 RPC 发出的调用一般会立即被处理,存放在消息队列中的消息并不一定会立即被处理。
  • RPC 和消息队列本质上是网络通讯的两种不同的实现机制,两者的用途不同。

消息队列如何选型?

对比方向 概要
吞吐量 万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。
可用性 都可以实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。 Kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
时效性 RabbitMQ 基于 Erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级,其他几个都是 ms 级。
功能支持 Pulsar 的功能更全面,支持多租户、多种消费模式和持久性模式等功能,是下一代云原生分布式消息流平台。
消息丢失 ActiveMQ 和 RabbitMQ 丢失的可能性非常低, Kafka、RocketMQ 和 Pulsar 理论上可以做到 0 丢失。
  • ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用,已经被淘汰了
  • RabbitMQ 在吞吐量方面虽然稍逊于 Kafka、RocketMQ 和 Pulsar,但是由于它基于 Erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为 RabbitMQ 基于 Erlang 开发,所以国内很少有公司有实力做 Erlang 源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这几种消息队列中,RabbitMQ 或许是你的首选。
  • RocketMQ 和 Pulsar 支持强一致性,对消息一致性要求比较高的场景可以使用 。RocketMQ 阿里出品,Java 系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的 MQ,并且 RocketMQ 有阿里巴巴的实际业务场景的实战考验。
  • Kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性 ,而且分布式可以任意扩展。同时 Kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。Kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

参考资料:12

相关推荐
wqq_99225027714 分钟前
springboot基于微信小程序的食堂预约点餐系统
数据库·微信小程序·小程序
爱上口袋的天空16 分钟前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse
朝九晚五ฺ40 分钟前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
Kkooe2 小时前
GitLab|数据迁移
运维·服务器·git
聂 可 以2 小时前
Windows环境安装MongoDB
数据库·mongodb
web前端神器2 小时前
mongodb多表查询,五个表查询
数据库·mongodb
门牙咬脆骨2 小时前
【Redis】redis缓存击穿,缓存雪崩,缓存穿透
数据库·redis·缓存
门牙咬脆骨2 小时前
【Redis】GEO数据结构
数据库·redis·缓存
wusong9992 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
代码小鑫2 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计