本系列是极客时间《从0开始学架构》的读书笔记。
很多情况下,高性能设计的核心就是存储系统的设计,而关系型数据库由于ACID特性和强大的SQL功能,是存储系统的核心部分。
一、高性能数据库
由于互联网的发展,海量数据的出现,数据库的发展远远跟不上业务,所以现在数据库的高性能需要通过集群来实现。
第一种方式,读写分离,将访问压力分散到集群中的各节点。第二种方式,分库分表,既可以分散访问压力,还可以分散存储压力。
1. 高性能数据库集群第一种方式:读写分离
对应《14 | 高性能数据库集群:读写分离》
适合的场景是:读操作远远多于写操作。
需要搭建数据库主从集群,其中主机负责读写操作,从机只负责读操作。数据通过同步从主机复制到从机,所有数据库均存储全部数据。在集群之上需要有Load Balance功能的机器/软件实现将读写操作分发给不同的数据库。
此方案有两个复杂点:主从复制延迟和分配机制。
出现复制延迟,会导致数据的不一致性。解决方法:
1.写操作后的读操作发送给主服务器。这样做会将业务和存储强耦合。
2.读失败后再读一次主服务器。通常所说的“二次读取”,消除了强耦合,但过多的二次读取会对主服务器造成读操作压力。
3.关键业务只使用主服务器,非关键业务采用读写分离。
对于分配,可以使用代码封装,还可以使用中间件封装。
中间件的复杂度远大于代码封装。它们的最小功能是Load Balance,复杂点的功能包括跨语言、跨数据库、主从判断和检测,等等。
代码封装的开源实现,有淘宝的TDDL(Taobao Distributed Data Layer,外号:头都大了),等等。
中间件封装,对于MySQL,有MySQL Proxy/MySQL Router/Atlas…
需要注意的是,如果出现性能问题,并不是一上来就采用读写分离,而是先应该优化,如优化慢查询,调整不合理的业务逻辑,引入缓存,等等,最后才考虑对数据库动手。进行读写分离后,可以单独对读库进行索引优化,写库减少索引,这样对读写都有提升。
2. 高性能数据库集群第二种方式:分库分表
对应《15 | 高性能数据库集群:分库分表》
适合的场景:单库单表的数据量过大。
此时需要将数据进行分散。
可以分库。一般按照业务进行分库。但是分库会引入问题,一是查询时的join操作无法实现,二是会有跨数据库事务,三是会有成本问题。所以小业务刚开始的时候是完全不需要进行分库的,单台服务器的性能可以支撑10w用户量级的业务,等业务真正发展起来了,钱和人都到位了,那时候再分库也不迟。
说点不相关的。在微服务架构中,各个微服务都是独立的,都有自己的存储,同样存在以上的三个问题。虽然此处采取分库的依据(是由于微服务要求的独立性导致)和此处的场景完全不同。
还可以进行分表。有垂直分表和水平分表两种类型。
单表切分后,并不一定需要将切分后的多表分撒到多个数据库中。
垂直分表将一条记录拆分为多个部分,分散到多张表中。适合将表中不常用,但是占据大量空间的列拆出去。引入的复杂度主要是原先的一次查询变成了多次查询。
水平分表适合行数特别大的表,将原先一张行数特别大的表,拆分成多张行数较小的表。行数的多少时进行拆分按照实际的性能来判断,一般来说达到千万级就需要注意了。
水平分表有多个复杂度来源:
1.路由。常见的有范围路由、Hash路由、配置路由。范围路由扩展新表方便,但是分布是不均匀的,Hash路由恰恰相反。配置路由用单独的一张表记录数据和表的关系,但是问题在于新出现的配置表同样会有性能瓶颈。
2.join操作。
3.count()。
4.order by。
分库分表的实现方法同读写分离,依旧是代码封装和中间件封装。
虽然关系型数据库集群可大大提高存储系统的性能,但是,由于关系型数据库本身的原因,