mysql分库分表:

场景:在进行设计数据库时,在用户量不大的情况下单表单库在承载最大2000/s以下的请求应该是没有问题的,单表磁盘存储200w已经就够多了。但是如果单表单库的情况下达到这么高的并发和存储对mysql数据库的性能有极大的挑战。当业务发展变大可以进行redis缓存解决一部分查请求并发减少mysql压力值,达到mysql阈值可以使用MQ进行削峰,但是这个不是长久的办法,如果业务量再次加大那么前面的措施会极大的影响程序性能。

mysql的分库分表用于在高并发大业务量的情况下的mysql性能优化。

分库:在原本的但库的情况下最大能承载的并发量也就2000/sQPS,万一QPS直接到1w及以上就算使用MQ也会堆积大量数据请求需要处理,这个时候就可以进行数据库分库,单库时2000/sQPS那么来5个库就是最高1wQPS承载量

分表:大量的写操作在单表的情况下很容易堆积大量数据,假设单表存储600w数据,整个查询的速率都会下降,整个性能都会下降。怎么办?分表。把这么大的表进行拆分,拆分可以用垂直和水平拆分。垂直拆分就是把一个表的字段往小了拆,把查询高频字段保留低频拆成一个表,需要低频数据直接缓存拿。水平拆分就是把表砍成几段,也就是这样的分表是在表结构一样的前提下分表,按照表的唯一id进行划分

分库分表场景:例如在大型互联网公司有上亿的用户,这么高并发大数据的进行对数据库的操作需要进行分库分表,首先假设现在已有1w/sQPS进行分库分5个库,一张表1000w数据,先进行每个库的分表水平分5个表给每个库,在每个库里面在水平分4个表也就是现在每个表才50w数据,怎么分呢,可以用hash,也可以用range,用hash就直接hash路由id到对应的库的对应的表,也就是现在有5个库20张表,hash路由先%5找库,在%20找表

分库分表问题:

1.如果之前进行架构时是单表单库但是因为业务量增加需要分库分表怎么办?

①停机维护,及其不建议(这个停机肯定是要在没人的时候也就是凌晨开始加班到第二天早上,不好不好对身体不好)。首先写个后台程序去吧数据库数据全部读出来,按照分库分表的架构把库和表搭起来,然后把全部的数据按照hash或者range的方式进行数据划分,如果按照hash路由,就直接程序跑起来id取模找对应的库和表存储。这个方法不仅伤身体还费力,如果在早上5前这个数据还没分完那就没办法了直接按照原先的单库单表运行然后在等下一个天亮。

②不停机维护,双写迁移。什么叫双写,就是在不影响用户的情况下进行分库分表操作。怎么操作,首先一样的先把库和表结构搭出来,然后在系统后台开一个程序进行迁移,在用户进行读写操作时,往旧库操作同时向新库操作。后台程序和用户读写同时进行操作新库,为了数据一致性在进行操作时激进型判断,这条数据是否存在不存在就插入存在就看最后的修改时间按照最新的修改时间数据进行存储

2.如果一开始我就是用的分库分表,但是现在需要扩容怎么办?

怎么办,加班!扩容的话,首先这里会有一个问题,如果是按照hash来进行的路由分库分表,那么在进行扩容的时候就不是那么简单了,直接扩容就会导致原先例如3个库取模3的值和现在6个库取模6得到值不一样也就是大部分数据可能找不到之前的位置了。如果一定要扩容,停机维护,加班!先把原先分库的数据全部读出来在安装现在需要的架构再次进行分配,配置变量然后部署。

所以,在考虑使用分库分表的时候就该考虑清楚,所以可以借用一致性hash的思想,直接部署32台,进行32*32的分库分表,按照32*32=1024张表的规格进行划分,这个大规格足够应付32*1500/sQPS,存储1024*500w的数据量了,QPS在高一点还可以使用MQ进行分流。整个hash分配就按照取模32找库,取模32*32找表。如果需要再次进行扩容ok,场景假设我有现在只有4台数据库服务器按照32*32进行分库分表也就是每个数据库服务器8个库每个库32张表,并发不够了加4台服务器把每台服务器的库在分为4*32的规模,因为我们是按照32来取模,库没有增加表也没有增加只是多了服务器把库数据迁移过去而已,也就是只需要配置一下hash路由的库在那个服务器就好了,还需要扩容就扩充为16,32,64...1024都可以,最多可以加到1024个服务器每一个服务器一个库一张表。

3.既然分库分表是按照id进行路由的,那么路由到每个不同的库插入以后和原来的id是不等的(使用自增的话)怎么解决ID唯一?

snowflake算法:

具体思路就是把一个64位的long型的id,1个bit是不用的,用其中的41 bit作为毫秒数,用10 bit作为工作机器id,12 bit作为序列号

1 bit:不用,因为二进制里第一个bit为如果是1,那么都是负数,但是我们生成的id都是正数,所以第一个bit统一都是0

41 bit:表示的是时间戳,单位是毫秒。41 bit可以表示的数字多达2^41 - 1,也就是可以标识2 ^ 41 - 1个毫秒值,换算成年就是表示69年的时间。

10 bit:记录工作机器id,代表的是这个服务最多可以部署在2^10台机器上,也就是1024台机器。10 bit里前5个bit代表机房id,后5个bit代表机器id。意思就是最多代表2 ^ 5个机房(32个机房),每个机房里可以代表2 ^ 5个机器(32台机器)。

12 bit:这个是用来记录同一个毫秒内产生的不同id,12 bit可以代表的最大正整数是2 ^ 12 - 1 = 4096,也就是说可以用这个12bit代表的数字来区分同一个毫秒内的4096个不同的id

64位的long型的id,64位的long -> 二进制

0 | 1011011  00100000  00101100  10111110  10110010  00 | 10001 | 1 1001 | 0000 00000000

2019-08-11 20:46:24 -> 做了一些计算,再换算成一个二进制,41bit来放 -> 1011011  00100000  00101100  10111110  10110010  00

机房id,17 -> 换算成一个二进制 -> 10001

机器id,25 -> 换算成一个二进制 -> 11001

MySQL主从复制读写分离:

配置的话找对应的博客吧,首先做主从和读写分离一是加大处理访问请求二是减轻数据库访问压力。一个数据库读写最高也就2000QPS,进行读写分离如果有1000走写,2000走读也是可以解决的。

主从复制原理:主库会写一个binlog日志,从库连接上之后开启IO线程去读这个binlog日志文件,因为是串行读有可能出现你刚刚写入的数据读取不出来(在高并发的情况下读的就会比主库慢一点),读完之后执行SQL保证和主库的数据一致。

数据丢失问题,进行主从因为是串行从库比主库慢加载,这个时段主机宕机数据就丢失了,要十分注意这个数据的丢失,进行主从有可能这个时差差了几毫秒相对容易出现数据丢失。可以使用半同步复制,也就是主库将数据写入带binlog文件的时候强制从库将数据同步到数据库,直到从库完成返回ack才算完成