数据库高并发和高可用方案

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 数据库高并发和高可用方案

依旧主要参考沈剑大佬的多篇博文,以及数位网友的优秀分享,文末是完整参考。

1、高可用方案(HA,High Availability)

缓存是通过双写和双读主备、或者利用缓存的集群数据同步,故障自动转移来实现的

数据库的读是通过读写分离(MHA,Master High Availability),分库冗余多份来实现的;写是通过主从双备,keepalived+virtual IP 自动故障转移来实现的。

2、高并发方案

读多写少,读并发高就主从分离,写并发高就水平分库,如果读写请求并发都很大,那就先水平分库,然后对每个库进行按照主从集群部署。解决读并发高还有一个方案是用缓存。

2.1 读写分离,主从复制,分组架构

三个名词代指同个架构模型。

主从复制(也称 AB 复制)指的是将一个MySQL 主服务器的数据复制到一个或多个MySQL从服务器(从服务器)。也常被称为分组架构、读写分离架构。

主库提供数据库写服务,从库提供数据库读服务。一般是一主多从。

读写分离架构在解决高可用问题时一般被简称为 MHA(Master High Availability)。

2.1.1 读写分离架构的优势

  • 读写分离,使数据库能支持更大的读并发和吞吐量。由于写库单独拥有一个独立的库,所以也能一定程度上提高写性能
  • 读写数据库相互独立,通过消除读写锁冲突提升数据库写性能
  • 通过冗余从库实现数据的“读高可用”
  • 有利于架构的扩展,通过增加从库数量可以明显提高读性能。

2.1.2 mysql 主从复制过程(异步)

master 开启 binlog 功能,binlog 日志文件用于记录数据库的读写增删。 需要开启3个线程,master IO线程,slave开启 IO线程 SQL线程,

1、MySQL master 将数据变更写入二进制日志( binary log,就是我们常说的 binlog)

2、Slave 通过IO线程连接master,并且请求某个bin-log,position之后的内容。

3、MASTER服务器收到slave IO线程发来的日志请求信息,io线程去将bin-log内容,position返回给slave IO线程。

4、slave服务器收到bin-log日志内容,将bin-log日志内容写入relay-log中继日志,创建一个master.info的文件,该文件记录了master ip 用户名 密码 master bin-log名称,bin-log position。

5、slave端开启SQL线程,实时监控relay-log日志内容是否有更新,解析文件内容,生成SQL语句,在slave数据库中执行。1456655-20230211180116596-754237710.png

2.2 分库分表

2.2.1 水平切分(也被称为分片架构)

2.2.1.1 分片架构的优势
  • 线性提升数据库写性能,需要注意的是,分组架构是不能线性提升数据库写性能的
  • 降低单库数据容量

一句话总结,分片解决的是“数据库数据量大,写操作有瓶颈”问题,所实施的架构设计。

常见的水平拆分方式有范围法和哈希法两种。两种路由和拆分方式都非常简单。有各自的优势和缺点:

2.2.1.2 按照范围水平拆分

好处是

(1)能保持数据原有的顺序;

(2)能够准确控制每台服务器存储的数据量,从而使得存储空间的利用率最大。

(3)比较容易扩展,不需要移动现有数据,可以随时加一个uid[2kw,3kw]的数据服务;

不足是:

(1)请求的负载不一定均衡,一般来说,新注册的用户会比老用户更活跃,大range的服务请求压力会更大;

2.2.1.3 按照哈希水平拆分

好处:

(1)数据量分布均衡性较好;

(3)服务器请求负载均匀性较好;

不足:

不容易扩展,扩展一个数据服务,hash方法改变时候,可能需要进行数据迁移;但是可以通过一致性哈希来一定程度上缓解这个问题。分片数量成倍扩展,迁移成本也还行,不需要移动全部的数据。

一致性哈希参考:一致性哈希算法原理详解

2.2.1.4 哈希+范围混合分片

先做哈希,然后对哈希结果做范围分片(或者先范围分片再哈希分片),一种折中方案,数据和请求量都较为均衡。

2.2.2 垂直切分

分成垂直分表和垂直分库。

2.2.2.1 垂直分表:

将表中使用频率低或者字段长度较大的字段放到扩展表。这是因为,数据库会以行(row)为单位,将数load到内存(buffer)里,在内存容量有限的情况下,长度短且访问频度高的属性,内存能够load更多的数据,命中率会更高,磁盘IO会减少,数据库的性能会提升。

2.2.2.2 垂直分库:

直接按照业务将一个库拆成两个独立的库,可以降低单库的数据量。与业务结合比较紧密,并不是所有业务都能够进行垂直切分的。

2.3 读写分离 + 分库分表

读写分离和分库分表的结合体,性能更加强大,但是架构也更加复杂。

3、问题

问:读写分离跟水平分库的区别

  • 单个服务器的数据量不一样:主从分离每个服务器上存储的数据量相同,都是全集;水平分库后每个服务器上存储的数据量是总量的1/n,每个服务器的数据没有交集,所有服务器的数据的并集是全集。
  • 目标和作用不一样:读写分离是为了扩展读性能,主要是解决读并发高问题,因为写库单独拥有一个独立的库,所以也能一定程度上提高写性能;水平分库主要扩展写性能,主要解决写并发问题,扩展之后读写性能都能提高。
  • 应用场景不一样:读多写少,读并发高就主从分离,写并发高就水平分库,如果读写请求并发都很大,那就先分库,然后对每个库进行按照主从集群部署。解决读并发高还有一个方案是用缓存。

问:主从分离有什么问题吗?

写仍然是单点,所以要做主从双备,辅助 keepalived+virtual IP 自动故障转移来实现高可用。

问:数据库架构如何选型

  • 业务初期用单库
  • 读压力大,读高可用,用分组
  • 数据量大,写线性扩容,用分片
  • 属性短,访问频度高的属性,垂直拆分到一起

问:水平切分,到底是分库还是分表?

:强烈建议分库,而不是分表,因为:

  • 分表依然公用一个数据库文件,仍然有磁盘IO的竞争
  • 分库能够很容易的将数据迁移到不同数据库实例,甚至数据库机器上,扩展性更好

问:平常流量不高,但由于业务问题,会出现瞬时高并发怎么解决

通过 MQ 消息队列来削峰填谷降流。

问:水平分库后,业务接入代码需要改动吗?数据访问层需要改动吗

如果以前的单库和现在的分片库都是通过代理来访问的话,那只需要切换数据源代理即可,业务层不感知分片。

数据访问层可能需要增加一些分片路由的代码,以及一些多库遍历聚合数据的代码,可以考虑抽取出一个数据库中间件专门来干这个事,减少对数据访问层的代码改动。

问:水平分库后,非 patition key的查询怎么办?如何同时查询多个库的数据?怎么做join或者全表查询操作?怎么保证事务特性?
网络异常,图片无法展示
|

patition key 走 db 或者 cache,非 patition key 走搜索

问:高并发指的只并发处理还是并行处理

一般一直并行处理的能力,吞吐量。比如某服务能同时处理10个请求,但是每个请求执行 5s,那么每秒的吞吐量只有 2 个,所以我们一般称并发能力为 2,吞吐量为 2,QPS 为 2。

问:分库带来的分布式事务怎么做的?

解法一:分表而不是分库,这样就没有分布式事务的问题了,但是不建议分表。

问:水平分库后,根据用户名登录,此时不知道uid,只知道用户名,怎么知道查哪个分片库?非 partition key 属性的查询?

1、全库扫描法

缺点:需要扫描所有的分片库,聚合数据,效率低下(其实细想一下其实效率还行,如果用户名每个分片库都有索引的话,单库查询很快,而遍历所有的库的话可以多线程并发遍历来加快速度)

2、用户名跟主键建立映射关系(假设用户名具有唯一性):索引法

建立用户名映射到主键的映射表或者把映射关系存在缓存中,映射表需要存在同一个库里,如果量太大,单个缓存实例存不下,可以通过用户名对缓存进行水平分片。

缺点:需要多查一次数据库或者缓存

3、用户名跟 hash 规则产生关系,也称为基因法

设计函数通过用户名生成用来决定 hash 分片的位数的几个bit。比如hash分片是对 8 取模,那么根据用户名需要生成 3 个bit,将这三个比特位作为主键的最后三位,这样就能根据用户名计算出用户所在分片了。

缺点:① 需要提前容量规划,否则如果刚开始8个分片,用户名生成了3个bit,但是后来扩容到了16个分片,这时根据用户名又无法确定分片了,如果刚开始根据用户名生成6个比特位,那就算扩展到 64 个分片,也还是能通过用户名确定分片。② 设计用户名生成比特位时,需要设计均匀分布,否则会导致分库数据库不均衡。

注:如果用户名是唯一且不可修改的,那么可以同时用上面的三种方式,如果用户允许修改,那么只能用前 2 中方式。

4、直接根据用户名来生成整个主键

缺点:有uid生成冲突风险,且需要设计末尾几个 bit 均匀分布,否则会导致分库数据库不均衡。

参考:用uid分库,uname上的查询怎么办?

类似的业务场景还有订单ID的生成(使用用户ID基因),保证同一个用户的所有订单在同一个分表。

问:多个非 partition key 上的查询怎么办

选择其中一个不会发生修改的字段可以用基因法打入 partition key,其他的可以用映射索引法

问:patition key上的批量查询怎么做的

比如用户列表 uid 上的IN查询,通过 patition key 查询,但是每次返回多行记录,难点是 partition key 值有多个,不一定都在同一个分片库里。

法一:数据访问层访问所有库,把结果集进行合并

法二:数据访问层分析路由规则,按需访问

数据访问层对每个 uid 进行路由分析,只访问对应的分片库然后进行数据聚合。

问:水平分库后,跨库分页怎么做

业界难题-“跨库分页”的四种方案

问:水平分库后,需要用用户名进行模糊查询 、时间范围查询

根据用户名关键词或者时间范围等查 ES

问:通常多大的数据量需要分库?

没有复杂查询,5kw 到 1亿 条数据。复杂查询,1kw-2kw。

问:数据库分表,索引如何工作

分表不分表,对索引没有影响,哪个属性上有在线查询,哪个属性索引

问:分片后,怎么生成唯一主键

参考“分布式id生成器”

问:水平分库后,需要使用数据库中间件来实现分库的路由吗

可以用数据库中间件来屏蔽分库细节,也可以自己 hash 实现路由到指定的分库。

问:什么时候需要分布式事务

同时修改多个库的数据

问:主从分离中写库有多个,

建议遵循一主多从,一个写库,多个从库,如果单点写有瓶颈,可以水平扩展多个写库,但是每个分片写库都需要配置多个从库,这样从库可以随时取代主库,读始终高可用。

读操作需要路由到指定集群,然后路由到指定读库实例。写操作需要路由到指定集群的指定写库。

如果需要多主多从,最好每个写库都保留全量的数据,通过路由将请求路由到不同的写库,写库之间需要互相同步数据。

多分片主多从有哪些缺陷:

1、写库只包含部分数据,但是读库包含全部数据,数据不对等

问:缓存在主从分离架构中的作用是什么,为什么有了很多读库还需要缓存

缓存用来存储高频访问的数据,不是数据库中所有的数据都会被加载到缓存,只有某几类数据中的高频且修改频率低的数据才会被加载到缓存,提高服务的响应速度,降低延迟,降低数据库的压力。从库供业务方请求不在缓存中的数据,比如热点数据发生变更从缓存中淘汰了,或者大部分数据压根就没存在缓存中。

问:数据库主从切换会丢数据吗

有可能会。

有两种可能导致丢数据

  • 正常来说如果如果主库数据还没完全同步到从库,主库就发生宕机的话,是会丢数据的。还在找不丢数据的方案。
  • 脑裂,2个主库,老主库因为网络连接不上LB,没有被设置为只读,也没有断开老连接,仍能接收写请求,导致这部分数据丢失。

丢失的数据是怎么找回来

binlog 存在定时备份,通过恢复备份的 binlog 人工介入找回丢失的数据。

半同步复制,但是当出现网络波动等情况时,半同步复制会退化为异步复制,也坑无法保证数据至少在一个从库上完成同步。

怎么避免丢数据

不使用主从切换,而是主库做双主热备,keepalived+虚拟ip

切换前设置主库为只读,阻塞写入。

想了解更多,参考:MySQL 主从切换异常导致数据丢失

问:单库宕机重启会丢数据吗

不会,重启时会再次执行保存好的redo log日志,恢复还没有刷盘的写操作。

问:数据库切换时是否会主动断开连接?

切换时可以自定义是否主动断开连接,当前切换逻辑中没有选择断开连接,长连接也不会主动断开。

比如对于 MHA,可以通过修改对应脚本实现切换时断开连接。

问:分库和分表选择的依据是什么,什么时候应该分表,什么时候应该分库

根据当前的瓶颈点来选择究竟是分库还是分表。

由于单个表数据量太大导致单个 sql 延迟高,分表

由于数据库整体请求量达到单个实例 qps 上限,且因为 qps 太高导致数据库或者数据行加锁冲突严重,请求延迟增加,则分库,这样可以降低单个数据库的数据量且每秒请求量,通过水平分库提高整体请求量。

问:主从 binlog 消息是推还是拉

在基于位点的主从关系中,一开始创建主备关系时, 由备库需要开始同步的 binlog 文件位置,主库从该位置开始发送 binlog 至从库。而主备复制关系搭建完成以后,只要主库有生成新的日志,会立刻主动发给备库。

提示:主从用于 binlog 传输的 IO 线程通过 TCP 建立了长连接,所以可以持续发送数据。

4、完整参考

依旧强推沈剑大佬的公众号“架构师之路”

典型数据库架构设计与实践 | 架构师之路

用uid分库,uname上的查询怎么办?

究竟为什么要引入数据库中间件

多对多业务,数据库水平切分架构一次搞定

多key业务,数据库水平切分架构一次搞定

12 | 写多读少:MySQL 如何优化数据存储方案?

MySQL 主从切换异常导致数据丢失

无损半同步复制下,主从切换后数据一致吗?

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

业界难题-“跨库分页”的四种方案

Mysql 主从复制

mysql 主从复制原理及步骤。

Mysql主从架构-主库宕机如何恢复业务

Golang面经

双机集群(HA)系统简称


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
150 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
2月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
3月前
|
关系型数据库 MySQL 数据库
|
3月前
|
存储 机器学习/深度学习 自然语言处理
LangChain与向量数据库:高效的信息检索方案
【8月更文第4天】随着自然语言处理技术的发展,特别是深度学习的进步,我们能够更加高效地处理大量的文本数据。LangChain 作为一种强大的工具链,旨在简化和加速构建复杂的自然语言处理应用程序。结合向量数据库,LangChain 可以实现高效且精准的信息检索功能。本文将探讨这一组合的工作原理,并通过一个具体的实现案例来展示其在实际应用中的效果。
440 2
|
14天前
|
缓存 关系型数据库 MySQL
高并发架构系列:数据库主从同步的 3 种方案
本文详解高并发场景下数据库主从同步的三种解决方案:数据主从同步、数据库半同步复制、数据库中间件同步和缓存记录写key同步,旨在帮助解决数据一致性问题。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
高并发架构系列:数据库主从同步的 3 种方案
|
28天前
|
缓存 弹性计算 NoSQL
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应
|
2月前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
399 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
3月前
|
存储 缓存 NoSQL
Redis内存管理揭秘:掌握淘汰策略,让你的数据库在高并发下也能游刃有余,守护业务稳定运行!
【8月更文挑战第22天】Redis的内存淘汰策略管理内存使用,防止溢出。主要包括:noeviction(拒绝新写入)、LRU/LFU(淘汰最少使用/最不常用数据)、RANDOM(随机淘汰)及TTL(淘汰接近过期数据)。策略选择需依据应用场景、数据特性和性能需求。可通过Redis命令行工具或配置文件进行设置。
78 2
|
3月前
|
消息中间件 负载均衡 应用服务中间件
高并发环境下的Nginx整合方案
【8月更文挑战第20天】在高并发环境下,整合Nginx代理服务器、静态文件服务器、Tomcat集群、Mycat数据库读写分离和消息队列,可以构建一个强大、灵活且可扩展的Web服务架构。
47 1
|
3月前
|
存储 缓存 运维
优化高并发环境下的数据库查询性能:实战经验与技巧
在高并发环境下,数据库性能往往成为系统瓶颈。本文将深入探讨在高并发场景下优化数据库查询性能的策略与实践,包括索引优化、查询优化、数据库架构设计以及缓存机制的应用。通过对具体案例的分析,读者将能够掌握提升数据库性能的关键技术,从而在面对大规模用户请求时提高系统的响应速度和稳定性。

热门文章

最新文章

  • 1
    高并发场景下,到底先更新缓存还是先更新数据库?
    66
  • 2
    Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
    74
  • 3
    Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
    68
  • 4
    Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
    62
  • 5
    Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
    55
  • 6
    Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
    69
  • 7
    在Java中实现高并发的数据访问控制
    42
  • 8
    使用Java构建一个高并发的网络服务
    29
  • 9
    微服务06----Eureka注册中心,微服务的两大服务,订单服务和用户服务,订单服务需要远程调用我们的用,户服务,消费者,如果环境改变,硬编码问题就会随之产生,为了应对高并发,我们可能会部署成一个集
    37
  • 10
    如何设计一个秒杀系统,(高并发高可用分布式集群)
    129