当前位置: 首页 > 后端技术 > PHP

Mysql分库分表详解

时间:2023-03-29 18:11:12 PHP

Mysql分库分表方案1.为什么要分表:当一个表的数据达到千万级的时候,你分表的时间会比较长查询一次。如果有联合查询,我觉得死在那里也是有可能的。分表的目的是减轻数据库的负担,缩短查询时间。mysql中的一种机制是表锁定和行锁定,这是为了保证数据的完整性。锁表就是说你们谁都不能对这个表进行操作,你要等我对这个表操作完。行锁定也是如此。其他SQL必须等我对这个数据进行操作,我才能对这个数据进行操作。2、mysql代理:amoeba作为mysql集群,使用amoeba。从上层java程序的角度来说,不需要知道主从服务器的来源,即主从数据库服务器对上层是透明的。它可以由变形虫配置。3、把数据量大、访问频繁的表分成几个表。比如某网站平台的数据库表-公司表,数据量非常大。对于这么大数据量的表,可以预估,我们会提前分离出N张表。N的数量视实际情况而定。某网站目前数据量最多5000万,可以设计每张表容纳500万条数据,即拆分成10张表。那么如何判断一张表的数据容量是否已满呢?在程序段插入要添加的表之前,可以统计表中的记录数。4.使用merge存储引擎实现分表现有的大数据规模分表是一件很痛苦的事情。最痛苦的是改代码,因为程序中的sql语句已经写好了。更适合使用合并存储引擎来实现分表。实例:数据库架构1.简单的MySQL主从复制:MySQL的主从复制解决了数据库的读写分离,很好的提高了读的性能。图如下:主从复制的过程如下图所示显示:但是主从复制也带来了其他一系列性能瓶颈问题:写不能扩展,写不能缓存,复制延迟锁tablerate增加,table变大,cacherate降低。问题必须要解决,这就导致了下面的优化方案。2、如果MySQL的垂直分区把业务足够独立,将不同业务的数据放在不同的数据库服务器上是一个很好的解决方案,而且如果其中一个业务挂掉了,也不会影响其他业务的正常运行.并且还起到了负载分配的作用,大大提高了数据库的吞吐量。垂直划分后的数据库架构图如下:但是,虽然业务足够独立,但有些业务或多或少是有关联的,比如用户,基本上每个业务都有关联。分区的方式解决不了单表数据量暴涨的问题,为什么不试试水平切分呢?3.MySQL水平分片(Sharding)是一个很好的想法,将用户按照一定的规则进行划分(根据idxi)分组,将这组用户的数据存储在一个数据库分片中,即一个sharding,这样随着用户数量的增加,只需要简单地配置一个服务器就足够了。示意图如下:如何确定某个用户所在的shard,可以创建用户和shard对应的数据表。对于每一个请求,先从这张表中找到用户的shardid,然后从对应的shard中查询相关数据,如下图所示:单库单表数据库表是最常见的数据库设计。比如数据库db中有一张用户(user)表,所有的用户都可以在db库中的user表中找到。单库多表随着用户数量的增加,用户表的数据量会越来越大。当数据量达到一定程度时,对user表的查询会逐渐变慢,从而影响整个DB的性能。如果用mysql,问题就更严重了。当需要增加一列时,mysql会锁住表,所有的读写操作只能等待。可以通过某种方式对用户进行水平切分,生成两张user_0000、user_0001等表结构完全相同的表,user_0000+user_0001+……的数据就是一个完整的数据。随着数据量的增加,单个DB的存储空间可能不足以容纳多个数据库和多个表。随着查询量的增加,单一的数据库服务器已经无法支撑了。这时候就可以进一步横向区分数据库了。分库和表分库规则在设计表时,需要确定表的分库和表分库规则。例如,当有一个新用户时,程序要确定将用户信息添加到哪个表中;同样,在登录的时候,我们要通过用户的账号在数据库中找到相应的记录,这一切都需要按照一定的规则进行。路由就是通过分库分表的规则,找到对应的表和库的过程。比如分库分表的规则是user_idmod4,当一个用户新注册了一个账号id为123的账号,我们可以通过idmod4来判断这个账号应该保存在User_0003表中。当用户123登录时,我们通过123mod4确认记录在User_0003中。规则如下:判断一个ID在哪个库的公式为:id%4/2判断一个ID在哪个表的公式为:id%4%2其中4表示有多少个子表intotal,2表示数据库总共有多少个子表;上面的例子表示总共有2个数据库,每个数据库有2个子表,所以2*2=4;因此,对于ID为1、2、3、4、5的情况,fall到达的库和表如下:ID=11%4/2=0(注:0表示index=0的库,即第一个库,这里计算的值从0开始)1%4%2=1(注:1表示index=1的表,即第二个表,值这里计算从0开始)即第一个库中第二张表的ID=22%4/2=12%4%2=0表示第二个库中第一个表的ID=33%4/2=13%4%2=1表示第二个库中的第一个表2tableIDs=44%4/2=04%4%2=0即第一个库中的第一个表ID=55%4/2=05%4%2=1即在一库二表中,分库分表引起的问题及注意事项1.分库分表的问题-表维度如果用户购买了商品,需要保存和检索交易记录。纬度分表,每个用户的交易记录都存储在同一个表中,所以查找一个用户的购买情况非常快捷方便,但是某个商品的购买情况很可能分布在多个表中。比较麻烦。反之,按照产品维度细分表格,可以很方便的找到该产品的购买状态,但是要找到买家的交易记录就比较麻烦了。所以常见的解决办法是:通过扫表来解决,这种方法基本不行,效率太低。记录两组数据,一组按用户纬度分表,一组按产品维度分表。通过搜索引擎解决,但是如果实时性要求很高,就得和实时搜索相关。2.联合查询的问题联合查询基本上是不可能的,因为关联的表可能不在同一个数据库中。3、避免跨库事务避免在一个事务中一边修改db0中的表,一边修改db0中的表。一是操作比较复杂,效率也会受到一定影响。4.尽量把同一套数据放在同一个DB服务器上。比如把卖家a的商品和交易信息放到db0中。当db1宕机时,卖家a相关的东西可以正常使用。也就是说,避免一个数据库中的数据依赖于另一个数据库中的数据。一主多备在实际应用中,大多数情况下读远大于写。Mysql提供了读写分离机制。所有的写操作都必须对应Master。可以在Master和Slave机器上进行读操作。Slave和Master具有完全相同的结构。Slave可以联动,这种方式可以有效提高DB集群的QPS。所有的写操作都是先在Master上进行,然后同步更新到Slave,所以从Master同步到Slave有一定的延迟。在繁忙的时候,延迟问题会比较严重,Slave机器数量的增加也会让这个问题更加严重。另外可以看出Master是集群的瓶颈。当写操作过多时,会严重影响Master的稳定性。如果Master挂了,整个集群将无法正常工作。所以1.当阅读压力很大时,可以考虑加入分库分库,但是当分库数量达到一定数量后,就不得不考虑分库了。2.当写压力很大时,需要进行数据库分操作。为什么MySQL要分库分表?可以说用到MySQL的地方,只要数据量大,马上就会出现一个问题,那就是必须分库分表。这里有个问题:为什么要分库分表?MySQL不能处理大表吗?事实上,它可以处理大表。在我经历过的项目中,单表的物理文件大小在80G以上,单表的记录数在5亿以上,而这个表属于一个非常有用的表:朋友关系表。但这种方式可以说不是最好的方式。因为Ext3文件系统等比大文件大的文件系统在处理上存在很多问题。这个级别可以用xfs文件系统代替。但是当MySQL单表过大时,有一个问题很难解决:表结构调整相关的操作基本无法进行。所以在大项的使用中,会监控分库分表的应用。从Innodb本身来看,数据文件的Btree上只有两把锁,叶子节点锁和子节点锁。可以想象,当一个页被拆分或者添加一个新的叶子时,表中就不能写入数据了。所以分库分表是比较好的选择。那么分库分表多少合适呢?经过测试,在单表1000万条记录以下时,读写性能都比较好。这样,如果留一些buffer,那么所有数据字体的单表会保持800万条记录以下,字符类型的单表保持在500万条以下。如果按照100个数据库和100张表来规划,比如用户业务:心里有个想法,按照业务来规划还是比较容易的。