数据库优化支持高可用

背景:

假如一个系统注册⽤户就 20 万,每天活跃⽤户就 1 万,每天单表数据量就 1000,然后⾼峰期每秒钟并发请求最多就 10。

公司业务发展迅猛,过了⼏个⽉,注册⽤户数达到了 2000 万!每天活跃⽤户数 100 万!每天单 表新增数据量达到 50 万条!⾼峰期每秒请求量达到 1 万,因为每天单表新增 50 万条数据,⼀个⽉就多 1500 万条数据,⼀年下来单表会达到上亿条数据。经过⼀段时间的运⾏,单表已经两三千万条数据了,勉强还能⽀撑着。但是单表数据量越来越⼤,拖垮了⼀些复杂 查询 SQL 的性能

问题:

服务器方面:峰期请求现在是每秒 1 万,咱们的系统在线上部署了 20 台机器,平均每台机器每秒⽀撑 500 请求,这个还能抗住,没啥⼤问

数据库方面:⼀台数据库服务器在⽀撑每秒上万的请求,会有以下问题:

数据库服务器的磁盘 IO、⽹络带宽、CPU 负载、内存消耗,都会达到⾮常⾼的情况
⾼峰期时,本来你单表数据量就很⼤,SQL 性能就不太好,这时加上你的数据库服务器负 载太⾼导致性能下降,就会发现你的 SQL 性能更差了
就是你的系统在⾼峰期各个功能都运⾏的很慢,⽤户体验很差,点⼀ 个按钮可能要⼏⼗秒才出来结果
如果数据库服务器的配置不是特别的⾼,也许数据库会宕机


设计方案:

步骤1:多台服务器分库⽀撑⾼并发读写

⾸先我们先考虑第⼀个问题,数据库每秒上万的并发请求应该如何来⽀撑呢? 要搞清楚这个问题,先得明⽩⼀般数据库部署在什么配置的服务器上。

(1)普通配置的服务器:

起码是 16 核 32G 的机器配置。 这种⾮常普通的机器配置部署的数据库,⼀般线上的经验是:不要让其每秒请求⽀撑超过 2000,⼀般控制在 2000 左右。在上万并发请求的场景下,部署个 5 台服务,每台服务器上都部署⼀ 个数据库实例。然后每个数据库实例⾥,都创建⼀个⼀样的库,⽐如说订单库。

此时在 5 台服务器上都有⼀个订单库,名字可以类似为:db_order_01,db_order_02,等等。 然后每个订单库⾥,都有⼀个相同的表,⽐如说订单库⾥有订单信息表,那么此时 5 个订单库 ⾥都有⼀个订单信息表。⽐如 db_order_01 库⾥就有⼀个 tb_order_01 表,db_order_02 库⾥就有⼀个 tb_order_02 表。 这就实现了⼀个基本的分库分表的思路,原来的⼀台数据库服务器变成了 5 台数据库服务器, 原来的⼀个库变成了 5 个库,原来的⼀张表变成了 5 个表。然后你在写⼊数据的时候,需要借助数据库中间件,⽐如 sharding-jdbc,或者是 mycat。

(2)写操作:

可以根据⽐如订单 id 来 hash 后按 5 取模,⽐如每天订单表新增 50 万数据,此时其中 10 万 条数据会落⼊ db_order_01 库的 tb_order_01 表,另外 10 万条数据会落⼊ db_order_02 库的 tb_order_02 表,以此类推,这样就可以把数据均匀分散在 5 台服务器上了。

(3)读操作:

可以通过订单 id 来 hash 取 模,去对应的服务器上的数据库⾥,从对应的表⾥查询那条数据出来即可。

(4)好处

原来⽐如订单表就⼀张表,这个时候不就成了 5 张表了么,那么每个表的数据就 变成 1/5 了;

假设当前订单表⾥已经有 2000 万数据了,此时做了上述拆分,每个表⾥就只有 400 万数据 了;

写:每天新增 50 万数据的话,那么每个表才新增 10 万数据,初步缓解了单表数据 量过⼤影响系统性能的问题;

读:每秒 1 万请求到 5 台数据库上,每台数据库就承载每秒 2000 的请求,⼀下⼦把 每台数据库服务器的并发请求降低到了安全范围;

这样,降低了数据库的⾼峰期负载,同时还保证了⾼峰期的性能。

步骤2:量分表来保证海量数据下的查询性能

上述的数据库架构还有⼀个问题,那就是单表数据量还是过⼤,现在订单表才分为了 5 张 表,那么如果订单⼀年有 1 亿条,每个表就有 2000 万条,这也还是太⼤了。所以还应该继续分表,⼤量分表。⽐如可以把订单表⼀共拆分为 1024 张表,这样 1 亿数据量的话,分散到每个表⾥也就才 10 万 量级的数据量,然后这上千张表分散在 5 台数据库⾥就可以了。

在写⼊数据的时候,需要做两次路由,先对订单 id hash 后对数据库的数量取模,可以路由到 ⼀台数据库上;

然后再对那台数据库上的表数量取模,就可以路由到数据库上的⼀个表⾥了;

通过这个步骤,就可以让每个表⾥的数据量⾮常⼩,每年 1 亿数据增⻓,但是到每个表⾥才 10 万条数据增⻓,这个系统运⾏ 10 年,每个表⾥可能才百万级的数据量

步骤3:读写分离支撑按需扩容、性能提升

还有⼀个问题,假如说每台数据库服务器承载每秒 2000 的请求,然后其中 400 请求是 写⼊,1600 请求是查询?(也就是说,增删改的 SQL 才占到了 20% 的⽐例,80% 的请求是查询)

此时假如说随着⽤户量越来越⼤,假如说⼜变成每台服务器承载 4000 请求了。 那么其中 800 请求是写⼊,3200 请求是查询,如果说你按照上班步骤⽬前的情况来扩容,就需要增加⼀ 台数据库服务器。但是此时可能就会涉及到表的迁移,因为需要迁移⼀部分表到新的数据库服务器上去,是不是 很麻烦?(分表麻烦)

其实完全没必要,数据库⼀般都⽀持读写分离,也就是做主从架构

写⼊的时候写⼊主数据库服务器,查询的时候读取从数据库服务器,就可以让⼀个表的读写请 求分开落地到不同的数据库上去执⾏。写⼊主库的时候,会⾃动同步数据到从库上去,保证主库和从库数据⼀致。然后查询的时候都是⾛从库去查询的。

具体操作:

现在的好处就是,假如说现在主库写请求增加到 800,这个⽆所谓,不需要扩容。然后从库的 读请求增加到了 3200,需要扩容了。 这时,你直接给主库再挂载⼀个新的从库就可以了,两个从库,每个从库⽀撑 1600 的读请求, 不需要因为读请求增⻓来扩容主库。

实际上线上⽣产你会发现,读请求的增⻓速度远远⾼于写请求,所以读写分离之后,⼤部分时 候就是扩容从库⽀撑更⾼的读请求就可以了。

优点:

对同⼀个表,如果你既写⼊数据(涉及加锁),还从该表查询数据,可能会牵 扯到锁冲突等问题,⽆论是写性能还是读性能,都会有影响。 所以⼀旦读写分离之后,对主库的表就仅仅是写⼊,没任何查询会影响他,对从库的表就仅仅 是查询。

高并发下数据库架构总结:

分库来⽀撑⾼并发的请求,⼤量分表保证每个表的数据量别太⼤,读写分离实现 主库和从库按需扩容以及性能保证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值