博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高性能架构模式
阅读量:4134 次
发布时间:2019-05-25

本文共 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/

你可能感兴趣的文章
C#入门
查看>>
C#中ColorDialog需点两次确定才会退出的问题
查看>>
数据库
查看>>
nginx反代 499 502 bad gateway 和timeout
查看>>
linux虚拟机安装tar.gz版jdk步骤详解
查看>>
python实现100以内自然数之和,偶数之和
查看>>
python数字逆序输出及多个print输出在同一行
查看>>
苏宁产品经理面经
查看>>
百度产品经理群面
查看>>
去哪儿一面+平安科技二面+hr面+贝贝一面+二面产品面经
查看>>
element ui 弹窗在IE11中关闭时闪现问题修复
查看>>
vue 遍历对象并动态绑定在下拉列表中
查看>>
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
python __future__
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>
pytorch(三)
查看>>
ubuntu相关
查看>>
C++ 调用json
查看>>