架构设计-高性能(一、存储高性能)

1.简介

        数据存储的性能是系统高性能的两大组成部分之一。目前市场的数据存储技术是五花八门,并且目前针对在大数据环境下针对不同的需求和场景提出了更多不同类型的数据库。本文主要讲解分类中的关系型数据库和NoSql数据库的高性能。

2.关系型数据库

        虽然存储技术在疯狂的迭代,但是传统关系型数据库基于器ACID的特性和强大的sql查询依然在数据存储界占据核心地位。但是随着大数据的发展,单个数据库服务很多时候很难满足具有庞大数据存储的业务需求,所以必须考虑数据库集群的方式来提升性能。高性能数据库集群的方式主要有两种:

  • 读写分离:本质为将访问压力分散到集群的多个节点。
  • 分库分表:既可以分散访问压力,又可以分散存储压力,但是架构相对更加复杂。

2.1.读写分离

        读写分离的原理是将数据库读写操作分散到不同的节点上。这里采用的是主从集群。从机是提供读数据功能的节点。

架构设计-高性能(一、存储高性能)_第1张图片

 

读写分离的实现逻辑比较简单,在实际应用中主要应对的是数据复制延迟带来的复杂性。

解决主从复制延迟的方案:

  1. 写操作后的读操作指定发送给数据库主服务器
  2. 读从机失败后再读一次主机
  3. 关键业务读写操作都指向主机,非关键业务采用读写分离

其各种方案都有其各自的优缺点且也只是只能解决一部分问题,需根据业务需求实际问题实际考虑。

2.2.分库分表

        读写分离只能缓解数据的读写压力,不能解决大量数据的存储压力。常见的分散存储的方法有“分库”和“分表”两大类。

2.2.1.分库

        指按照业务模块将数据分散到不同的数据库服务器。这样就能一定程度分散存储和访问的压力,但是也会带来一系类的问题:

  • join问题:不在一个库的表无法使用sql的join操作
  • 事务问题:在同一数据库中的表可以在同一事务修改,分库后无法通过事务统一修改。虽然有的数据库厂家提供了分布式事务的解决方案(如Mysql的XA),但是性能很低
  • 成本问题:分库需要增加服务器,所以会带来成本相关的问题。

所以,初始业务不建议一开始就进行分库操作,当用户发展到一定的程度,业务需要时在进行考虑。

2.2.2.分表

        当同一表的数据达到百万千万甚至更高时,单表数据就会达到性能瓶颈,此时就需要对单表数据进行拆分,单表的拆分分为垂直拆分水平拆分两种方式。

        单表拆分后的表是否要分散到不同的库需要根据实际情况来定,并非强制要求一定要分散到不通的库。因为拆分成多表后新的表即使在同一库也能带来很大的性能提升,如性能可以满足就不需要分散到不同的库,且分散到不同的库也会带来很多复杂性的问题。

  • 垂直拆分:

        也叫列拆分,适合将表中不常用且占用大量空间的列切分出去。其复杂度主要在表操作的数量要增加

  • 水平拆分:

        也叫行拆分,适合表行数特别大的表<千万级以上>。其复杂性主要体现在怎么拆分聚合类的操作上。

【路由问题】

水平分表后某条数据具体属于那个切分后的子表,称为数据路由问题。常见的解决方案有:

路由方式 具体方案 复杂性 缺点
范围路由 选取有序的列(如整形,时间戳等)作为路由的条件,不同分段分散到不同的数据库表中 分段大小的选取 缺点是分布不均匀
Hash路由 选取某个或某些列的值做Hash运算,按照Hash的结果分散到不同的数据库表中 初始表数量的选取 缺点为扩充新的表很麻烦
路由表 用一张独立的表记录路由信息 需多查一次 如路由表过大,同样有性能瓶颈

【join问题】

如需进行join操作,需要在业务代码或数据库中间件中进行多次join查询,然后将结果合并。

【聚合问题】

聚合类操作也需要每个子表分别进行,然后对结果进行合并。

【排序问题】

排序操作无法在数据库中完成,只能由业务代码或者数据库中间件分别查询每个子表的 数据饭后汇总排序。

2.3.实现方案

        读写分离需要将读/写操作区分开,然后访问不同的数据库节点;分库分表是根据不同的数据访问来确定访问的数据库节点,都是同一种机制,即不同的sql到不同的数据库节点执行。常见的方式有程序代码封装中间件封装

2.3.1.程序代码封装

        指在代码中抽象一个数据访问层来实现读写分离、分库分表

架构设计-高性能(一、存储高性能)_第2张图片

特点:

  • 实现简单,且可以根据业务做较多的定制化功能。
  • 每种编程语言需自己实现无法通用
  • 如发生主从切换,可能需要所有系统修改配置并重启

开源的方案有,淘宝的TDDL等

2.3.2.中间件封装

指独立一套系统出来,实现读写分离和分库分表操作。在业务服务器看来,中间件就是一个数据库服务器。

架构设计-高性能(一、存储高性能)_第3张图片

 特点:

  • 能支持多种编程语言
  • 需支持完整的sql语法和数据库服务器协议
  • 数据库主从切换对业务服务器无感知,数据库中间件可以探测数据库服务器的主从状态
  • 成熟的中间件有:Mysql Router、Atlas等

数据库中间件的复杂度相对较高,所以一般情况下建议采用程序语言封装的方式或者使用成熟的开源数据库中间件。

 3.NoSql

        Nosql的出现时为了解决关系型数据库在某些方面的不足,但是器根本是以牺牲ACID特性中的某个或某几个来实现的。常见的Nosql分为:

类型 特性 代表
K-V存储 解决关系型数据库无法存储数据结构的问题 Redis
文档数据库 解决关系型数据库强schema约束的问题 MongoDB
列式数据库 解决关系型数据库大数据场景下的I/O问题 HBase
全文检索引擎 解决关系型数据库的全文检索性能问题 Elasticsearch

4.缓存

        为了弥补存储系统在复杂业务下的不足如读多写少等,其基本原理就是将可能重复使用的数据放到内存中,一次生成,多次使用,避免每次使用都去访问存储系统。

4.1.缓存穿透

指缓存没有发生作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去查询存储系统。一般有两种情况:

  • 存储数据不存在

        如果查询存储系统的数据没找到,则直接设置一个默认值并存入缓存,装第二次读取缓存时  就会获取默认值而不会继续访问存储系统。

  • 缓存数据生成耗费大量的时间或资源

 目前么有太好的解决方案

4.2.缓存雪崩

        指当缓存失效后引起系统性能急剧下降的情况。在高并发下多个线程同时去访问存储系统并生成缓存,对存储系统造成巨大的性能压力从而拖慢整个系统,甚至于造成数据库宏机,从而引起一系类连锁反应,造成整个系统崩溃。常见的解决方案有:

  • 更新锁:岁缓存更新操作进行枷锁保护,分布式系统需使用分布式锁,如ZooKeeper。
  • 后台更新:后台线程来更新缓存而不是业务线程,缓存本身有效期为永久,后台线程定时更新缓存。

4.3.缓存热点

描述:

        大部分业务或所有业务,请求命中统一缓存,对此缓存所在的缓存服务器造成的压力。

 解决:

        缓存热点的解决方案就是复制多份热点缓存,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力。

你可能感兴趣的:(设计,数据库)