由此可见 , 即使我们使用高性能数据库服务器 , 安全运行的并发能力也只是6万的QPS , TPS可能还要低很多 。如果一个高并发的业务接口需要访问5次数据库 , 那么最高能支撑1.2万的接口并发 。如果前端业务功能每次点击需要走三四个接口 , 如果这三四个接口有查询有更新插入 , 也许连并发2000都撑不到 。而这都是基于单次查询只有一次磁盘IO的情况 , 如果单次查询数据量大于1页 , 或者查询内容需要跨页访问 , 那就会产生多次IO , 那性能就更低了 , 也许连四五百都撑不住 , 甚至于一个没有太高并发的业务 , 但是查询语句非常复杂 , 可能直接导致并发能力在几十甚至个位数 。而数据库又因为ACID的原因 , 基本只能实现多读无法实现多写 , 分布式事务到现在也是难以突破的一个技术鸿沟 , 要实现需要付出巨大成本 。
怎么优化分析到此 , 就找到了几千用户访问时无论怎么加应用服务器 , 最后还会雪崩的原因了 , 根儿就不在应用层面 , 加再多的服务器都没有用 。那么数据库的问题仅仅靠优化sql解决么?sql从慢到快 , 只是一个表象 , 系统宕机的根本原因在于数据库服务器达到了瓶颈 , 资源不足导致的 , 我们应该先分析什么问题导致了资源瓶颈 , 然后对症下药的分析 。也许只需在某几个点加个缓存 , 也许见个合理的索引 , 也许是变动下只查id不查内容避免回表 , 都可以一针见血的解决掉性能问题 。现在特别流行使用的nosql可以支持分布式存储 , 性能也可以随着节点数增多而线性递增 , 是不是换成分布式存储就可以支撑高并发了呢?也不是 , 仅仅支撑几万并发 , 使用数据库+缓存还是可以的 , 传统数据库的ACID、使用简单、技术成熟稳定是我们必须要考虑的 , 也是我们首次开发一个项目的首选存储 。这也是为何很多大的金融机构还在使用IOE(IBM+ORACLE+EMC)的原因 。
现在我们经过上述一系列分析 , 知道了系统真正的瓶颈点了 , 网络上只有流量会成为瓶颈 , 应用上只有锁、线程切换、递归调用和大数据量处理会成为运算和内存瓶颈 , 数据库因为ACID是单点 , 所以此处的性能是最难扩展的 。面对大流量 , 核心目标就是尽量让高并发接口可以支持横向扩展 。最开始的性能优化基本都是围绕着数据库的瓶颈而进行的 , 一般有如下几个阶段:
第一阶段:缓存热数据
有些热点数据如果需要多次查询 , 而且查多改少 , 那么一般是可以放到redis缓存中的 , 利用内存访问来替代磁盘访问 , 可以明显提升效率 。同时 , 针对数据库的回表问题 , 也可以在mysql中只查id , 根据id在redis中查询数据内容 。这种缓存只适用于大多数人查询的内容都相同的情况 , 缓存只需要存一份 , 更新缓存相对容易 。
第二阶段:扩散写
有些查询根据每个人会得到不同结果 , 那么每个人来访问系统都需要查询一次数据库 , 并发量上来后很可能会把数据库压到瓶颈 , 所以需要预先算出每个人的查询结果并缓存 , 这就是倒排索引 , 也就是扩散写的思路 。此时为了降低数据库压力提高查询效率 , 需要为每个人冗余一份数据 , 更新会比较复杂 , 因为需要重新计算每个人的数据 。但是查询会非常快 , 而且未来也可以针对查询做各种扩展 。
第三阶段:异步处理
有些业务场景是需要高并发插入更新的 , 此时数据库也容易成为瓶颈 。为了保证系统可以正常使用 , 只能延迟返回插入更新的结果 , 放入队列 , 慢慢消费 , 也算是削峰的一种 。
第四阶段:读写分离
上面三个阶段都处于单机状态 , 但是热点数据的缓存有很多场景还是先查库后缓存 , 也容易把数据库压崩 , 所以此时需要横向扩展 , 通过读写分离 , 扩展读的mysql服务器 , 但此时就会存在读写服务器的数据同步延时问题需要考虑和解决 。
第五阶段:分库分表
推荐阅读
- 新时代的网络工程师需要掌握哪些技能
- 关于一次弱口令的BC渗透
- 朱元璋向元朝称臣,朱元璋怎么打败元朝的
- 诗仙太白是哪朝的著名诗人,诗仙太白是哪里产的
- 对某edu站点的一次渗透测试
- Redis 有哪些数据类型?
- 尉迟恭为什么叫尉迟敬德,尉迟敬德的说法
- 实用-API接口设计
- 刘备有诸葛亮和五虎上将为啥会输,刘备的五虎上将是哪五虎
- JavaScript 如何检测文件的类型?
