本文共 4091 字,大约阅读时间需要 13 分钟。
高性能架构模式
高性能数据库集群 读写分离 原理:将数据读写操作分散到不同的节点上 基本实现: 数据库服务器搭建主从集群,一主一从、一主多从都可以 数据库主机负责读写操作、从机只负责读操作 数据库主机通过复制将数据同步到主机,每台数据库服务器都存储了所有的业务数据 业务服务器将写操作发给数据库主机,将读操作发给数据库从机 设计复杂度 主从延迟 如果业务服务器将数据写入到数据库主服务器后立即进行读取,此时读操作访问的是从机,主机还没有将数据复制过来,到从机读取不是最新数据,业务就可能出现问题 解决主从复制延迟的常见问题 1、写操作后的读操作指定发给主服务器 问题:和业务强绑定,对业务的侵入和影响较大 2、读从机失败后再读一次主机 这就是通常所说的“二次读取”,二次读取和业务无绑定,只需要对底层数据库访问的API进行封装即可,实现代价较小,不足之处在于如果有很多二次读取,将大大增加主机的读操作压力。如黑客暴力破解账号,主机可能顶不住压力而崩溃 3、关键业务读写操作全部指向主机,非关键业务采用读写分离 分配机制 程序代码封装 程序代码封装指再代码中抽象一个数据访问层(中间层封装)实现读写操作分离和数据库服务器连接的管理 特点 实现简单,而且可以根据业务做较多定制化的功能 每个编程语言都要自己实现一次,无法通用 故障情况下,如果主从发生切换,则可能需要所有系统都修改配置并重启 开源方案:淘宝TDDL,将所有功能封装在jar包中提供给业务代码调用。基本原理是一个基于集中式配置的-datasource实现 中间件封装 中间件封装指独立一套系统,实现读写分离和数据库和数据库服务器连接的管理。中间件对业务服务器提供SQL兼容的协议,业务服务器无须自己进行读写分离 特点 能够支持多种编程语言,因为数据库中间件对业务服务器提供的是标准SQL接口 数据库中间件要支持完整的SQL语法和数据库服务器的协议,实现比较复杂,细节特别多,很容易出现bug,需要较长时间才能稳定 数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都要经过中间件,中间件的性能要求也很高 数据库主从切换对业务管理器无感知,数据库中间件可以探测数据库服务器的主从状态 开源方案:MYSQL Proxy、MYSQL Router以及360公司的Atlas 分库分表 业务分库 业务分库指的是按照业务模块将数据分散到不同的数据库服务器 问题 join操作问题 事务问题 成本问题 分表 垂直拆分 记录数相同但包含不同的列 适合将表中某些不常用且占列大量空间的列拆分出去 复杂度主要提现在表操作的数量要增加 水平拆分 表的列相同,但包含不同的行数据 适合表行数特别大的表 复杂度 路由 水平分表后,某条数据属于哪个切分后的子表,需要增加路由算法进行计算 常见路由算法 范围路由 选取有序的列(整型、时间戳等)作为路由条件 设计复杂点主要提现在分段大小的选取上,分段太小会导致切分后子表数据过多,增加维护复杂度;分段太大依然存在性能问题,一般建议分段在100-2000万之间,具体需要根据业务选取合适的分段大小 优点是可以随着数据的增加平滑地扩充新的表 缺点是分布不均匀 Hash路由 选取某个列(或组合)的值进行Hash运算,然后根据Hash结合分散到不同数据库表中 复杂点主要体现在初始表数量的选取上,表数量太多维护比较麻烦,表数量太小又核能导致但表性能问题,而且Hash路由后,增加表数量所有数据都需要重新分布 优点是表分布比较均匀,缺点是扩充新表麻烦 配置路由 配置路由就是路由表,用一张独立的表来记录路由信息 优点:设计简单,使用起来非常灵活,尤其在扩充表时,只需迁移指定数据,然后修改路由表就可以了 缺点:必须多一次查询,会影响整体性能,路由表本身如果太大,性能同样可能成为瓶颈,需要分库分表 join操作 水平分表后,数据分散中多个表中,如果需要与其他表进行join查询,需要在业务代码或者数据库中间件中进行多次join查询,然后将结果进行合并 count操作 如获取记录总数用于分页或者展示 处理方法 count相加:对每个表进行count操作,然后将结果相加 记录数表:新加一张表,操作数据后都更新记录数表 优点:只需要一次简单查询就可以获取数据 缺点:增加了复杂度,对子表的操作要同步操作记录数表,可能出现数据不一致;增加了数据库写压力 order by操作 数据分散到多个子表中,排序操作无法在数据库中完成,只能由业务代码或者数据库中间件分别查询后进行汇总排序 高性能NoSQL 关系型数据库缺点 关系数据库存储的是行记录,无法存储数据结构 关系数据库的schema扩展很不方便 表结构的schema是强约束,操作不存在的列会报错,扩充列需要执行DDL 关系数据库在大数据场景下IO较高 如果对一些大量数据的表进行统计之类的运算,关系数据库的IO会很高,因为即使只针对其中一列进行查询,关系数据库也会将整行数据从存储设备读入内存 没有索引的查询使用大量IO,建立索引和物化视图需要花费大量时间和资源 面对查询的需求,数据库必须被大量膨胀才能满足性能要求 关系数据库的全文搜索功能比较弱 NoSQL方案带来的优势,本质上是牺牲ACID中的某个或某几个特效。应该将NoSQL作为SQL的一个有礼补充 常见的NoSQL方案 文档数据库 解决关系数据库强schema约束问题,以MongoDB为代表 优点:可以存储和读取任意的数据,数据格式如json。1、增加字段简单 2、历史数据不回出错,3可以很容易存储复杂数据。适合电商和游戏类业务场景 缺点:1、不支持事务。某些对事务要求严格的场景不能使用文档数据库。无法实现关系数据库的join操作 K-V存储 解决关系型数据库无法存储数据结构的问题,以Redis为代表 缺点:并不支持完整的ACID事务,Redis提供只能保证隔离性和一致性,不能保证原子性和持久性 列式数据库 解决关系数据库大数据场景下的IO问题,以HBase为代表 列式数据库是按照列来存储数据的,传统数据库称为行式数据库 关系数据库的行式存储优势为 1、业务同时读取多个列时效率高,因为这些列都是按行存储在一起的,一次磁盘操作就能够把一行数据都读到内存中 2、能够一次性完成对一行中的多个列的写操作,保证了针对数据写操作的原子性和一致性 列式数据库优势 1、数据即是索引,可以读取某个字段的值,不用将整行记录加载到内存中,节省IO 2、具有更高的存储压缩率,因为单个列的数据相似度比行来说更高,能够达到更高的压缩率 列式数据库缺点 1、列式存储将不同列存储在磁盘不连续的空间,导致更新多个列时是随机写,而行式存储同一行是在连续的空间,一次磁盘操作就可以完成 2、列存储高压缩率在更新场景下也会成为劣势,因为更新时需要将存储数据进行解压后更新,然后再压缩写入磁盘 列式更适合OLAP,非常适合于在数据仓库领域发挥作用,比如数据分析、海量存储和商业智能;涉及不经常更新的数据。 全文搜索引擎 解决关系数据库全文搜索性能问题,以Elasticsearch为代表 优势 全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引数量会非常多 全文搜索的模糊匹配方式,索引无法满足,只能用like查询,like是整表扫描,效率非常低 技术原理被称为“倒排索引”或者反向索引,基本原理是建立单词到文档的索引 正排索引适用于根据文档名称来查询文档内容 倒排索引适用于根据关键字来查询文档内容 全文搜索引擎的索引对象是单词和文档,而关系型数据库的索引对象是键和行 高性能缓存架构 存储系统的不足 需要经过复杂运算后得出的数据,存储系统无能为力 读多写少的数据 缓存原理:将可能重复使用的数据放到内存中,一次生成,多次使用,避免每次使用都去访问存储系统 架构设计要点 缓存穿透 指缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,需要再读取存储系统 原因和解决 存储数据不存在;解决方案:如果存储系统中未找到数据,则直接设置一个默认值放到缓存中,第二次读取缓存时会获取到默认值 缓存数据生成耗费大量时间或资源,存储系统中存在数据,但生成缓存数据需要耗费较长时间或耗费大量资源,如果刚好在业务访问时业务失效来,那么也会出现缓存没有发挥作用,访问压力全部集中再存储系统上的情况,如爬虫,通常方案是识别爬虫然后禁止访问,但是可能影响SEO和推广;要么做好监控,发现问题及时处理,因为爬虫不是攻击,不回进行暴力破坏,对系统的影响是逐步的,监控发现问题后有时间进行处理 缓存雪崩 指缓存失效(过期)后引起系统性能急剧下降的情况 解决方案 更新锁机制 对缓存更新操作进行加锁保护,保证只有一个线程进行缓存更新,未能获取更新锁的线程要么等待锁释放后重新读取缓存,要么返回空值或者默认值。如果采用分布式集群的业务系统,则需要用到分布式锁 后台更新机制 由后台线程来更新缓存,而不是由业务线程来更新缓存,缓存本身的有效期设置为永久,由后台线程定时更新缓存。既适合单机多线程场景,也适合分布式集群场景。需要考虑当缓存系统内存不够时,会“踢掉”一些缓存数据; 解决方案 后台线程除了定时更新缓存,还要频繁地读取缓存,如果发现缓存被“踢了”就立即更新缓存。实现简单,但读取时间间隔不能太长 业务发现缓存失效后,通过消息队列发送一条消息通知后台线程更新缓存。依赖消息队列,复杂度会高一些,但缓存更新更及时 缓存热点 虽然缓存系统本身性能比较高,但对于一些特别热点的数据,如果大部分甚至所有业务请求都命中同一份缓存数据,则这份数据存在的缓存服务器的压力也很大 解决方案:复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力 设计细节:不同缓存副本不要设置统一过期时间,否则会出现所有缓存副本同时失效问题,正确做法是设置一个过期范围,不同缓存副本的过期时间为指定范围内的随机值转载地址:http://gmsvi.baihongyu.com/