转自:https://mp.weixin.qq.com/s/rpiYZkxiLKa77OFw8XaBwA

不堪重负的数据库

张大胖公司的数据库已经不堪重负了。

这个系统最早是两个实习生写的, 按照最初的设计,只是内部用户玩的, 大家可以把一些闲置不用的东西放在上面做交换,  仅此而已,后来为了在互联网的大潮中赚点钱,又包裹上了一层Web的外衣, 让外界也可以访问。

大家没有想到互联网威力如此巨大, 用户量会如此之多, 他们系统使用的Mysql数据库很快就撑不住了。

作为技术负责人的张大胖早已经向老大申请了一笔费用, 专门买了一个高性能的服务器来应对, 但是汹涌而来的用户很快就把高性能给吃得连渣都不剩。

张大胖忧心忡忡: “老大,怎么办? ”

老大也是技术出身,反问道: “你分析过为什么数据库压力这么大吗? ”

“无非就是读写量太大了,尤其是有一些非常复杂的查询, 比如最近24小时最热门的物品之类,需要写很复杂的SQL, 运行起来实在太慢了。”

“我记得咱们俩聊过读写分离啊, 怎么不试一试?”

“老大啊, 你不知道,这实在是不好弄啊, 为了实现读写分离, 得把数据库拆分成master库和slave库, 还比较简单, 但是我们的系统代码也得改啊, 写数据的时候用master 库, 读数据的时候用slave库, 你知道我们这是上个世纪开发的系统,典型的遗留代码,  改动起来太麻烦了。”

老大说:“那也得改啊, 你要知道现在这个系统可是咱们公司最大的收入来源了。 你们要是不想改,就退下来,我只好去找李小疯去做了”

张大胖向来瞧不起马屁精李小疯,技术不咋地,升的到挺快,一起进公司的, 现在已经比自己高一级了。

张大胖赶紧说:“ 别别, 还是我来”

张大胖带着几个弟兄和遗留代码奋战了几个月,  工作量不亚于一次重写。 张大胖深深地体会到,别看现有代码很烂, 但是经过无数人的修补,勉强能工作。 现在自己从头写一遍,出的问题更多,很多小细节考虑不到,被测出了无数Bug。

不过好处也是巨大的,这次重写,理清了业务, 实现了读写分离,还把缓存也用上了, 最后熬了两天两夜,新系统终于上线了。

张大胖想着好日子就要开始了,崭新的代码, 崭新的系统,应该可以撑一段时间。

2复杂的查询

可是新系统上线了一周后,问题又出现了,这次的问题主要集中在一些复杂的SQL查询上,这些SQL查询最要命的得有几十行! 严重地拖累了数据库 !

张大胖找来DBA 小梁过来做优化,小梁看了半天说: “没辙, 你们的业务太复杂了, 你看看有这么多表在做Join,怎么可能快呢?”

张大胖说:“这没办法啊,数据库就是这么设计的啊, 你懂的,无论如何也得满足第一范式吧。 要不这样,你给我们创建一个视图(View) 吧, 把这个复杂的查询给封装起来, 这样我们使用起来就简单了”

“那也是换汤不换药啊, 实际的查询还在, 没有本质的改变,  照样还是慢。”

“唉,这可怎么办, 我们有20多个复杂查询,怎么才能提高速度呢?”

小梁说: “你看看这个超级复杂的查询, 不就是为了获得过去24小时的热门产品吗,要是有个表单独存放就好了 hot_products(id, name, desc, total_sold) , 这样以来一条简单的SQL就搞定”

小梁的话启发了张大胖: 实际上,一套单一的数据库表 对于报表、搜索、事务等不同的行为是不适当的 !

现在复杂的数据查询和简单的数据修改利用的就是同一套领域模型和数据库表, 现在的数据库表主要是为了新增、修改数据而设计的, 对于复杂的查询并不友好。  我们能不能单独的建一套数据库,专门应对查询呢?

有了这个专门的查询库, 用户在界面上发起查询的时候处理起来非常简单, 一条SQL就搞定,甚至都不用通过业务领域层,换句话说数据库模型和展示层是对应的!  再也不用像原来那样从原始数据库表中得到数据,转化成领域对象, 然后再转化成展示层对象, 实在是太麻烦了 !

但是这个专门的查询库该如何更新呢? 更重要的是能不能忍受数据的延迟呢?

3CQRS

张大胖把自己的想法和苦恼给老大讲了下。

老大拍了拍他的肩膀: “看来你小子开窍了啊, 想得挺深入的, 从业务上看数据的延迟可以忍受,比如过去24小时的热门产品,一点点过时的数据对用户不会产生重大的影响。只要你能达到最终一致就可以了。”

“那我们该怎么更新这个专门的查询库呢?”

“我最近在看一个叫做CQRS的东西”  老大说  “ 你遇到的这个问题可以用同样的思路来解决下”

“什么是CQRS ? ”

"Command Query Responsibility Segregation,就是命令(增删改)和查询的责任分离, 你看看这个图"

“这和我刚才的图差不多啊” 张大胖说

“所以说思路是一致的嘛, 在CQRS中, 强调的是读(Query)和写(Command) 的分离 ,  它背后的理念是用户读到的数据通常是过时的,比如过去24小时最火的产品, 既然如此, 为什么还要从数据库中读取一遍,转化为领域模型,DTO, VO, 最后在UI层展示呢? 何不直接一点,干脆为‘读’专门建立一个直接的数据源呢? 这新的数据源不一定是关系数据库,可以是Cache ,可以直接存储为xml/json数据, 只要界面查询起来方便即可。 ”

“是,最早我也是这么想的,那这个Event是怎么回事?”

“Event 就是事件喽,例如有人下了一个订单, 导致某个产品已经卖出, 这个时候就可以发布一个产品已经卖出(ProductSold)的事件 , 其中包含产品的ID, 价格,卖出时间等属性, 这样的事件被处理以后,可以变成任意的Read Model,例如过去24小时最火的产品 。”

“奥,原来是这么玩的啊, 通过事件机制把同步变成异步 ”  张大胖说 “ 还有一个问题,如果我们用CQRS, 难道我们的应用需要把所有的Command 和Query完全分开吗, 查询都通过新的数据源?  可是很多查询很简单,直接使用关系数据库就够了啊。 ”

“不,不要把摊子铺得太大, 引入一种新的技术也是需要付出代价的,我们把同步操作变成了异步的操作, 得有良好的事件处理机制才可以。 所以先用这种思路把你的当前问题,也就是复杂查询的问题解决掉吧!” 老大最后拍了板。

(完)

从读写分离到 CQRS,张大胖是如何解决性能问题的?的更多相关文章

  1. mysql读写分离配置,利用mybatis实现,解释为什么dynamicDataSource不行

    之前发布了mysql主从配置的博客,配置完成之后,那么我们肯定要拿主从来做点什么. 我第一想到的就是mysql的读写分离,让读写分离之后可以大大的提供mysql的性能,比单纯用mysql主从做备份好很 ...

  2. (转)Django配置数据库读写分离

    转:https://blog.csdn.net/Ayhan_huang/article/details/78784486 转:http://www.cnblogs.com/dreamer-fish/p ...

  3. Django----配置数据库读写分离

    Django配置数据库读写分离 https://blog.csdn.net/Ayhan_huang/article/details/78784486 https://blog.csdn.net/ayh ...

  4. springboot实现读写分离(基于Mybatis,mysql)

    近日工作任务较轻,有空学习学习技术,遂来研究如果实现读写分离.这里用博客记录下过程,一方面可备日后查看,同时也能分享给大家(网上的资料真的大都是抄来抄去,,还不带格式的,看的真心难受). 完整代码:h ...

  5. node.js web应用优化之读写分离

    概述 先了解读写分离是什么,什么原理,解决了什么问题.什么是读写分离? 其实就是将数据库分为了主从库,一个主库用于写数据,多个从库完成读数据的操作,主从库之间通过某种机制进行数据的同步,是一种常见的数 ...

  6. MySQL 主从复制&读写分离 简介

    1. 读写分离&读写分离 简介 主从同步延迟 分配机制 解决单点故障 总结 2. 主从复制&读写分离 搭建 搭建主从复制(双主) 搭建读写分离 1. 读写分离&读写分离 简介 ...

  7. MySQL主从复制及读写分离

    MySQL主从复制 MySQL数据库自身提供的主从复制功能可以方便的实现数据的多处自动备份,实现数据库的拓展.多个数据备份不仅可以加强数据的安全性,通过实现读写分离还能进一步提升数据库的负载性能. M ...

  8. akka-typed(8) - CQRS读写分离模式

    前面介绍了事件源(EventSource)和集群(cluster),现在到了讨论CQRS的时候了.CQRS即读写分离模式,由独立的写方程序和读方程序组成,具体原理在以前的博客里介绍过了.akka-ty ...

  9. .NET Core 使用MediatR CQRS模式 读写分离

    前言 CQRS(Command Query Responsibility Segregation)命令查询职责分离模式,它主要从我们业务系统中进行分离出我们(Command 增.删.改)和(Query ...

随机推荐

  1. 多校第六场 1003 hdu 5355 Cake(贪心)

    题目链接:(数据加强后wa了) hdu 5355 题目大意: 给出一个蛋糕.切成1~n大小的n块.问是否能在不继续分割的情况下拼凑出m等份. 题目分析: 首先我们是可以知道每份蛋糕的尺寸的,利用n*( ...

  2. Xsolla与蜗牛一起共创黑金

    Xsolla和蜗牛游戏强强合作,公布了黑金在线,是中国知名网络游戏武术时代的一个新项目. Xsolla与蜗牛黑金 2014年6月10日至20日,蜗牛的黑金在线首次在美国洛杉矶E3展会上亮相. 该游戏官 ...

  3. discuz新的单点论坛(不依赖UCenter)

    discuz 本身提供UCENTER用户中心能够实现单点登录. 可是其它应用要单点登录到discuz还是存在若干问题: 须要2次激活.可能造成server无响应,论坛显示的最新注冊用户无法同步更新,官 ...

  4. robin 今天来南大了

    今天非常高兴,在学校的体育馆见到了李彦宏博士. 这是第一次真实的见到了曾经仅仅能在媒体上才干够见到的人,真实,感觉非常好. 我算不上李彦宏的粉丝,也不是非常热衷于百度这个公司,可是我如今仍然心情澎湃. ...

  5. Oracle经典教程学习笔记

    Oracle学习 1.为表创建约束:alter table 表名 add constraint 约束名 约束内容 演示样例:alter bable infos add constraint UN_ST ...

  6. WCF学习笔记——配置服务引用

    WCF传过来的东西要序列化. 比如,在WCF服务中,象这么个方法 public IEnumerable<UserItem> GetUserList() 默认情况下,在客户端会调用,是这样: ...

  7. luogu1415 拆分数列

    题目大意 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小:如果有多组解,则使得第一个数尽量大:如 ...

  8. c++ 数据预处理(数据去噪,归一化)

    正态分布3σ原则,把3倍方差之外的点设想为噪声数据来排除. 归一化,将数据经过处理之后限定到一定的范围内,一般都会将数据限定到[0,1]. #include <iostream>#incl ...

  9. PCB Genesis加邮票孔(弧形连接位宽度校正)实现算法

    采用弧形作为加接位,当两边距离较远时,会造成连接位变窄,由于之前算法是基于连接位间距做为半径画弧, 必然存在这个缺陷,这边做少许的改进解决此问题. 现将几个种增加孤形连接位的图形对比如下: 一.两边外 ...

  10. JS网页播放声音实现代码兼容各种浏览器

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...