在一个大数据量的系统中,这些数据的存储、处理、搜索是一个非常棘手的问题。
比如存储问题:单台服务器的存储能力及数据处理能力都是有限的, 因此需要增加服务器, 搭建集群来存储海量数据。
读写性能问题:单台数据库服务器的数据存储和数据处理能力都是有限的, 而大多数互联网业务,往往读多写少,而互联网特别是中大型的电商系统,业务都是非常繁忙的, 这个时候最容易出现的就是读性能瓶颈。
扩容问题:随着时间的推移,原有的集群中的机器不能够存储这么多的数据量时,这个时候我们就需要考虑扩容。
数据库架构设计 可用性设计在最原始的架构中,是单一数据库,一旦数据库宕机之后,整个服务都不可用,不存在高可用。解决高可用的思路,就是冗余、复制。
主从复制:在这种主从的架构中,即使Master节点挂掉,还有Slave节点,整个数据库的数据依赖存在,但是在
这种架构中,无法保证读、写的高可用,而且会存在一致性问题;
为保证“读”的高可用,还可以对读(从)库进行冗余,但是冗余读库,也会存在副作用: 读写有延时,可能存在不一致。保证"写"高可用,就可以在上述架构的基础上,再冗余写库,采用双主双从模式。而在这种架构下,两个主库,都会执行写请求,而且互相同步。
读性能设计在数据库中,我们为了提高读的性能,最常用的做法就是建立索引,但是如果索引过多,又会存在其副作用:
降低了增删改性能;索引占内存多了,放在内存中的数据减少,数据命中率降低,IO次数增多;
解决方案:
不同库建立不同的索引:主库只提供写操作, 不建立索引;从库提供读操作,在从库上建立适当的索引 ;
增加从库,负载均衡:这种做法上面已经提到,会存在主从不一致的问题,从库数量越多,主从延时越长,不一致问题越严重。
增加缓存层:①. 发生写请求时,先淘汰缓存,再写数据库②. 发生读请求时,先读缓存,缓存命中则直接返回,没有命中,则查询数据库,并将查询的结果缓存在redis中(而此时旧数据可能入缓存)。
一致性设计:引入中间件:通过中间件将key写操作路由到主, 在一定时间范围内,该key上的读也路由到主,当主从同步完成后再将读操作路由到从。
读写都到主:读写都到主,不做读写分离,也就不存在主从不一致的情况。
缓存两次淘汰:异常的读写时序,或导致旧数据入缓存,一次淘汰不够,要进行二次淘汰
a. 发生写请求时,先淘汰缓存,再写数据库,额外增加一个timer,一定时间(主从同步完成的经验时间)后再次淘汰
b. 发生读请求时,先读缓存,hit则返回,miss则读数据库并将数据入缓存(此时可能旧数据入缓存,但会被二次淘汰淘汰掉,最终不会引发不一致)
在上述的架构中,针对于单库的可用性、读性能、一致性进行了分析,在电商系统的数据库中,数据量是特别大的,而单台服务器的容量、性能都是有限的,如果来完成扩容,则我们需要考虑到拓展性的设计。
垂直拆分:根据业务划分,将不同的数据库表切分到不同的数据库上,以实现扩容的目的;
水平拆分:将同一块业务的数据库表,进行拆分,将一张表的数据根据一定的规则(取模,hash等)切分到不同的数据库上。
平滑、高效扩容:随着业务系统的扩张,数据库中的数据量会不断增加,如果实现扩容,最为直接了当的办法就是直接增加服务器,从而实现更多数据的存储;
如何来完成高效、平滑的扩容呢, 可以按照以下架构进行
MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
优势:
1) 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
2) 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
劣势:
1) 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
2) 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
MySQL数据库中默认的存储引擎InnoDB的索引结构为B+树,而根据叶子节点的内存存储不同,索引类型分为主键索引和非主键索引。
主键索引的叶子节点存储的是整行数据,在InnoDB中主键索引页被称为聚簇索引。其结构如下: