当前位置: 首页 > 科技观察

数据库读写分离和分库分表

时间:2023-03-21 18:33:03 科技观察

读写分离读写分离的主要目的是将对数据库的读写操作分散到不同的数据库节点上。一般情况下,我们会选择一主多从,即一个主库负责写,其他从库负责读。主库和从库之间会进行数据同步,保证从库数据的准确性。这样的架构实现起来比较简单,也符合系统少写多读的特点。#读写分离会导致什么问题?怎么解决?读写分离对于提高数据库的并发性是非常有效的,但是也带来了一个问题:主库和从库的数据存在延迟。比如你写好主库后,需要时间把主库的数据同步到从库。是的,这个时间差导致主从库数据不一致。这就是我们常说的主从同步延时。主从同步延迟的问题目前还没有特别好的解决办法(可能是我太擅长了,欢迎评论区补充)。您可以根据自己的业务场景参考以下解决方案。1.强制将读请求路由到主库处理。既然你的出库数据过期了,那我就直接从主库读取吧!这种方案虽然会增加主库的压力,但是实现起来比较简单,也是我学习到的用的最多的方法。比如Sharding-JDBC就是采用的方案。通过使用Sharding-JDBC的HintManager分片键值管理器,我们可以强制使用主存储库。HintManagerhintManager=HintManager.getInstance();hintManager.setMasterRouteOnly();//继续JDBC操作对于这种方案,可以将必须??获取最新数据的读请求交给主库处理。2.延迟阅读。有的朋友肯定会想,既然主从同步有延时,那我延时之后再读。比如主从同步延迟0.5s,那我就1s后读取数据。多方便啊!方便是方便,也是扯淡。但是,如果将业务流程设计成这样会好很多:对于一些对数据敏感的场景,可以避免写请求完成后立即执行请求操作。比如支付成功后,会跳转到支付成功的页面,点击返回后才会返回账户。说到项目本身,常用的方法有两种:1.代理模式我们可以在应用和数据之间加一个代理层。应用的所有数据请求都交给代理层处理,代理层负责分离读写请求,路由到对应的数据库。提供类似功能的中间件有MySQLRouter(官方)、Atlas(基于MySQLProxy)、Maxscale、MyCat。2.组件方式在这种方式中,我们可以通过引入第三方组件来帮助我们读写请求。这也是我推荐的方式。这种方式目前在各个互联网公司使用最多,相关的实际案例也很多。如果要使用这种方式,推荐使用sharding-jdbc,导入jar包就可以直接使用,非常方便。同时,也节省了大量运维成本。sharding-jdbc关于读写分离的操作可以在官方的shardingsphere中找到。MySQL主从复制原理MySQLbinlog(binarylog即二进制日志文件)主要记录了MySQL数据库中数据的所有变化(数据库执行的所有DDL和DML语句)。因此,我们可以根据主库的MySQLbinlog日志,将主库的数据同步到从库。主库将数据库中的数据变化写入binlog。从库连接到主库。从库会创建一个I/O线程向主库请求更新的binlog。主库会创建一个binlogdump线程发送binlog,从库中的I/O线程负责接收从库的I/O线程,并将接收到的binlog写入relay日志。从库的SQL线程读取relaylog,在本地同步数据(即再次执行SQL)。分库分表什么是分库?分库就是将数据库中的数据分散到不同的数据库中。下面的操作都涉及到分库:你把数据库中的用户表和用户订单表分别放在两个不同的数据库中。因为user表的数据量太大,所以你把user表横向拆分,然后把拆分后的2个user表放在两个不同的数据库中。#什么是分表?分表就是将单个表的数据进行拆分,可以垂直拆分,也可以水平拆分。什么是垂直拆分?垂直拆分简单来说就是数据表列的拆分,将一个列很多的表拆分成多个表。比如:我们可以把用户信息表中的一些列单独提取出来作为一张表。什么是水平拆分?简单来说,水平拆分就是数据表行的拆分,将一个行数很多的表拆分成多个表。例如:我们可以将用户信息表拆分成多个用户信息表,这样可以避免单表数据量大而带来的性能影响。《从零开始学架构》中有一张图,非常直观的描述了垂直拆分和水平拆分。#什么情况下需要分库分表?以下场景可以考虑分库分表:单表数据达到千万级以上,数据库读写速度比较慢(分表)。数据库中的数据占用空间越来越大,备份时间越来越长(分库)。应用的并发量过大(分库)。#分库分表会带来什么问题?记住,你在公司做任何技术决策,不仅要考虑技术是否能满足我们的要求,是否适合当前的业务场景,更要关注它带来的成本。分库分表引入后,会给系统带来哪些挑战?join操作:同一个数据库中的表分布在不同的数据库中,不能使用join操作。这导致需要手动封装数据。比如你在一个数据库中查询了一条数据,你可以根据这条数据在另一个数据库中找到对应的数据。事务问题:同一个数据库中的表分布在不同的数据库中。如果单个操作涉及到多个数据库,那么数据库自带的事务就不能满足我们的要求。分布式id:数据库分库后,数据分散在不同服务器的数据库中,数据库的自增主键已经不能满足生成主键的唯一性。我们如何为不同的数据节点生成全局唯一的主键?这时候我们就需要在我们的系统中引入分布式id。...另外,引入分库分表后,一般需要DBA的参与,同时需要更多的数据库服务器,这些都是成本。分库分表有什么推荐的方案吗?ShardingSphere项目(包括Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar)由当当网捐赠给Apache,目前主要由京东数科的一些巨头维护。ShardingSphere绝对可以说是现在分库分表的首选!ShardingSphere功能齐全。除了支持读写分离、分库分表外,还提供分布式事务、数据库治理等功能。此外,ShardingSphere拥有完整的生态系统、活跃的社区、完备的文档、频繁的更新和发布。#分库分表后,如何迁移数据?分库分表后,我们如何将数据从旧库(单库单表)迁移到新库(分库分表后的数据库系统)?一个比较简单但也很常见的解决方案是停止迁移,写一个脚本将数据从旧数据库写入新数据库。比如凌晨2点,系统使用人数很少的时候,你挂了个公告,说系统维护升级,预计1小时。然后,您编写脚本将旧库中的所有数据同步到新库中。如果不想宕机迁移数据,也可以考虑双写方案。双写方案针对的是无法停止迁移的场景,实现起来有点麻烦。具体原理是这样的:当我们对旧库进行更新(增删改查)的时候,也需要对新库进行写入(双写)。如果要操作的数据在新库中不存在,则需要插入到新库中。这将确保我们新图书馆中的数据是最新的。在迁移过程中,双写只会将更新后的旧数据库中的数据同步到新数据库中。我们还需要编写脚本,将旧数据库中的数据与新数据库中的数据进行比较。如果它不在新库中,那么我们将数据插入到新库中。如果新库存在,旧库不存在,则删除新库对应的数据(冗余数据清理)。重复上一步的操作,直到旧库和新库的数据一致。项目中实现双写还是比较麻烦,容易出问题。我们可以使用上面提到的数据库同步工具Canal做增量数据迁移(还是依赖binlog,开发维护成本低)。总结读写分离主要是将对数据库的读写操作分散到不同的数据库节点上。这样可以稍微提高写性能,大大提高读性能。读写分离基于主从复制,MySQL主从复制依赖于binlog。分库就是将数据库中的数据分散到不同的数据库中。分表就是将单个表的数据进行拆分,可以垂直拆分,也可以水平拆分。引入分库分表后,需要系统解决事务、分布式ID、无法join操作等问题。ShardingSphere绝对可以说是现在分库分表的首选!ShardingSphere功能齐全。除了支持读写分离、分库分表外,还提供了分布式事务、数据库管理等功能。此外,ShardingSphere拥有完整的生态系统、活跃的社区、完备的文档、频繁的更新和发布。

猜你喜欢