为什么需要分库分表?
1、解决连接数的问题 单机并发有限1000-3000
2、数据库处理能力问题
3、存储容量的问题
1的解释
数据库是C/S架构模式,这种模式决定动态语言的开发都属于I/O密集型,这就涉及到I/O开销。
每次操作客户端需要与服务端通信,如PDO何MYSQL服务端。一般分为两步,1:建立连接,获取标识符。2:发送SQL请求
服务端有个连接器,MySQL分配线程调用连接器里面的代码处理请求,1:检查用户,鉴权。鉴权成功就返回一个文件句柄,也就是拿到一个对象,
通过这个对象发送SQL请求,服务端通过链接句柄判断是哪个连接。
网络通信 不能够直接发,启动一个程序,可能会有sock文件或者pid文件,这个文件专门做数据的接收和响应,比如说 服务端要发数据,SQL语句的数据拿到后不是立马发
,先把它写到缓冲区,缓冲区有大小,这个缓冲区就是通过这个文件存放。写到里面等到缓冲区满了之后, 再把缓冲区里面的数据发给
网卡,由网卡通过网络发给客户端。
2的解释
资源上限,内存有上限,超过就放不了。单机时查找也慢,比如存了10亿数据,就算用到索引查找速度也会下降,千万级用索引能提速
但是亿级别用索引也不会提速。设计索引的原理和数据库的模式。因为索引用到B+树,特点是矮胖。数据量大会变得更胖,当然也会变高(但高不是主要影响)因为每个节点一般只能容纳整数页,一页为16K大小,那你超过1页的数据就不行了,只能开启更多的节点,开启更多的节点树就会上升,第二能树也会变得很胖,横向上面节点就会更多。这时候的查找,需要加载的节点更多,而内存有上限,但是我们要加载很多节点,这时候就需要分割,分割一旦过多就会从以前的顺序I/O变成随机I/O,因为内存放不了那么多,我只能每次放一部分,我找完再去找后面的,那这样的话,我们以前能一次能读完的,现在不行了,我只能够多次随机,可能要找上千上万次,可能更多,这样来找,开销大。
第二点,创建索引,索引也是需要维护的,一旦更改,索引就要更改,一旦维护,可能有卡死现象或者有索引碎片。
什么场景下适合做分库分表?
数据库量过大,达到10t 或者单表1000W行数据 数据量增长过快每天增长20w 需要保证安全性和可用性的时候(高并发条件下,一次性载入的数据量太大)
分库分表方案有哪些?
- 分库不分表
- 分表不分库
- 分库分表
分库分表的手段
垂直
分库:业务当中按功能模块、关系划分,部署到不同的库上
分表:大表拆小表,通过热点字段冷热程度划分
为什么考虑字段来分表?
因为MySQL的特性:
行数据存储,一般关系型数据都是行数据,读数据的时候都是一行行的度,
比如字段有100多个的时候,你select id,name...... from xxx 也就是你指定了字段来查询
请求走到数据库服务端,数据时放到磁盘上面的,读的时候需要先把磁盘的数据读到MySQL服务层中,但是磁盘中数据时一列一列存放的,读的时候一列一列的读到MySQL服务层 然后MySQL会组合,拼成一行一行的数据。根据where条件,看看到磁盘读取多少数据,就把这么多数据的所有字段都拿出来放到MySQL服务层,找到所有MySQL作相应,这时候匹配select中的字段,匹配到的才相应,比如我们查id和name,响应的时候就只会返回id和name。所以说字段越少,减少寻找数据的时间(磁盘开销)和网络传输。
优点:
• 拆分后业务清晰,拆分规则明确;
• 系统之间整合或扩展容易;
• 数据维护简单。
缺点:
• 部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度;
• 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高;
• 事务处理4复杂。
由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。
水平
范围 hash 时间
分库:单一个表数据量过大,就可以把表的数据按照规则来做划分,然后存到多个结构相同的表中
优点:
• 拆分规则抽象好,join 操作基本可以数据库做;
• 不存在单库大数据,高并发的性能瓶颈;
• 应用端改造较少;
• 提高了系统的稳定性跟负载能力。
缺点:
• 拆分规则难以抽象;
• 分片事务一致性难以解决;
• 数据多次扩展难度跟维护量极大;
• 跨库 join 性能较差
不同方式的优缺点
Hash优缺点:不方便扩容,但可以让数据分配得更平均
范围优缺点:方便扩容,但容易造成数据倾斜。
了解事务和锁,innodb引擎高并发写入数据的时候,innodb有含锁,表锁。加入多请求同时来写,首先进入写缓冲,缓冲里面写完
缓冲区写满的时候才会把数据写入磁盘。我们在写的时候,假如不给表加锁,如果数据库里面有ID为4 和5的数据,高并发插入的时候,
下一条ID就是6,第一个请求进来后就把写操作给第一个请求,其他请求等待。数据库解决并发请求,有个队列来解决并发请求。
更新的时候默认加上排它锁,每个请求都加上排他锁,因为插入的时候记录还没有,所以是表锁(表级别的排它锁)。
总结:MySQL用队列接收并发请求,如果并发中既有查询也有更新,这时候更新比查询有优先权,表级上锁,其他操作效率都会降低。
所以一般提高并发写入的方法是 异步批量写入。这样只需要锁一次。
扩容方案 范围扩容+hash消除流量倾斜