从单一WAR到多活, 记述一个创业公司的架构演变

本故事纯属虚构,如有雷同,实属巧合

程 是一个爱折腾,喜欢交朋友的程序员。

某一天,程一个朋友介绍了另外一个朋友 创 给他,创说他有个点子,可以改变世界,现在就差一个程序员。程看了创的PPT,觉得还不错,反正也没妹子,平时下班回家或者周末也没事干,就答应创,做他的合伙人,给他开发网站。

单一垂直架构

程把他自己在大学的时候做的基于Java的考试管理系统,拿来改了改,又自学了一些前端,三个月后,第一个版本的网站上线了。这个东西的后台大概这个样子,所有的东西都部署在一台服务器上。

负载+垂直架构

上线后的半年,为了适应业务的变更,网站做了多次升级和新功能的研发。伴随着代码越来越庞大,注册用户越来越多,有时候要卡半天,才能刷出页面。创又多花几倍的预算在技术上,买了几台新服务器。然后这套系统变成了下面的样子,Mysql终于可以单独放在一台服务器上了,使用负载均衡后,可以把服务器实例(war)拷贝后部署到几台机器上了。

升级后,瞬间快了很多。

分布式服务架构

后来,这个公司拿到了天使投资,程也全职加入了,身份是CTO,而理所当然的,创做了CEO。陆续也有运营和市场的合伙人加入,日活有几万了。程也不用自己写前端了,因为招了2个专门的前端工程师,还有另外2个做服务器的小伙子。市场变化很多,每天都有新需求,每天都可能上线新功能。

但是,当前这样的服务器代码体系,让他越来越力不从心。

1. 这么一坨庞大的代码融在一起,维护成本和新人学习成本都是特别高的。 2. 想招一个实习生,但是如果开放给他权限就是所有代码,真担心这个实习生把代码拿去卖了。 3. 代码构建的时间越来越长,程序员最不喜欢的就是等了。 4. 发布成本也很高,因为每次发布都是全量发布。有些核心功能,需要全天服务用户,所以白天几乎不可能发布。即时发布一个无关紧要的功能,也要等到晚上,出了Bug还要赶紧修复,长期熬夜,真是觉得这个世界充满恶意。

不能再这样下去了......

其实程很早就听过分布式架构(SOA),也知道主流的公司都在用这些。但是现在业务代码已经十分庞大了,至少十几万,并且有大量重复和“不敢动的”代码,重构成SOA,至少要两个月,公司新需求不断,怎么可能。

经过一个月的挣扎,真心觉得不能忍了,决定升级架构成SOA,调研后发现阿里的开源框架Dubbo (dubbo.io) 好像使用的蛮多,文档也挺全的,所以决定用它。

重构前,首先梳理了一下业务,按照业务相关性,拆分成若干的底层SOA服务和API层服务。这个重构大概进行了2个月,CEO没技术背景,完全不知道他们提的SOA是个啥,新需求不能被满足,已经处于崩溃边缘。

终于,新架构上线了,它大概长成这个样子。

这里,每个服务包括API服务和基础的SOA服务都可以部署在不同的机器上,他们之间的发现是通过Zookeeper集群协调的。启动一个服务后,它就会注册自己到Zookeeper上,服务调用方被通知,新的服务实例上线。服务调用方持有一个服务的多个调用实例,采用某种策略进行负载。

可以按照业务需求,有选择的扩容指定服务,举个栗子,例如商城做双十一活动,有很多秒杀商品,那么只需要多部署几个和商城相关的服务即可。如果按照之前的架构设计,所有功能都在一个war中,只能对所有功能扩容,浪费计算资源。

当然,还有一些任务被改造成定时任务,就是图中的Scheduled模块,例如结算等,这样运营或者程序员就不用大半夜起来做事了。

分库分表,读写分离

半年后,公司又融了几千万的A轮,用户数进一步扩大。高峰时段越来越卡,各种Log分析系统时间和分析Mysql慢日志发现,因为数据量越来越多,并发数越来越大,主存储已经有点Hold不住了。并且程越来越担心万一哪天,那台Mysql机器硬盘出故障,废了,公司的所有的数据就都没了。

后来无意见,程发现了Mycat(mycat.io) 这个数据库中间件,原来还以利用它做分库分表,读写分离这些自己实践起来十分困难的高级Feature。

经过了差不多一个月的调研,实践,测试,升级后的Mysql集群变成了如下的样子。

做了分库分表后,再也不用担心太多数据把单一Mysql服务器硬盘撑满的问题了,并且也更方便了权限管理。启用Slave从节点后,也不用担心单一主节点硬盘故障后,数据的丢失问题了。读写分离后,前端访问速度也快了很多,增删改查被分散到不同的机器,单节点的效率瓶颈有了很明显的缓解。

DRC(Data Replication Center)

伴随着业务种类越来越多,数据越来越多,依赖Mysql的索引的搜索早就显得力不从心。为了性能,只能支持某个字段的StartWith搜索。包含和模糊搜索都不能做,所以就用了Elastic Search做通用搜索引擎。为了进一步提升读效率,也把很多登录信息和用户好友关系这些经常读的数据,放入Redis中做缓存。

同一份数据,既要放入ES,还要放入Redis,早期这个功能实现大概如下:

更新代码往往要关心缓存,同步ES数据,如果同步间隙过长,会有数据延迟,如果同步间隙太短,还要增加DB负担。并且伴随这个业务变多,越来越多这样的操作:从一个表中全量拉取更新数据,做进一步业务处理,给业务库造成很多额外的压力。

如果主数据变动,就把变动发送到一个中心,感兴趣的一·方只要订阅这些消息,就可以实现自己的逻辑,实时性高的同时,不会给业务库造成任何压力。于是DRC诞生了:

可以理解DRC Replicator模拟了一个Mysql Slave,从主节点拉binlog,然后解析binlog,并将结果发送到消息队列中。

而感兴趣的程序,可以去订阅消息,然后执行相应的更新,这样就把更新缓存的事情和业务代码解耦了,更新ES这种操作也可以做到既实时性高,也不用经常去Mysql库中扫描表了。当然DRC还有一个重要的应用,它也是多活的核心组件之一。

多活

伴随用户体量进一步提高,交易量的暴增,简单的数据备份,已经不能很好的满足需求了。如果机房宕机,依然会导致服务不可用。

另外,所有的流量都打到机房的服务集群,也会导致一定的系统瓶颈。可能更理想的方式是:一个北京的用户下单,他的整个业务流都落在北京的机房;上海的用户下单,也希望所有的数据落在上海的机房,两个机房的主数据互备,同时满足数据的一致性。其中某个机房挂掉后,所有的流量切到另外一个机房。

而对于强一致性的数据,例如用户表存在用户名的uniq索引,对于这类数据,可以放在一个倍成为全局数据的机房,所有写落在这里,其他机房只是执行备份。

就这样,随着用户的逐渐增多,融资一次一次到来,团队越来越多,业务线越来越多,架构的也一次一次升级演化。路已经走了很远,并且伴随着越走越远,未来可能还有更多的升级和演化。

这个架构演化的故事,讲完了。如有陈述不当或错误,欢迎留言讨论~

传送门 : https://zhuanlan.zhihu.com/p/27903657

从单一WAR到多活, 记述一个创业公司的架构演变的更多相关文章

  1. [Android]一个干净的架构(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5276587.html 一个干净的架构 原文:https://b ...

  2. 、web前端的这么知识应该是怎样的一个知识体系架构?

    .web前端的这么知识应该是怎样的一个知识体系架构?之前我以为可以以W3C为纲要,把W3C的东西学会了就够了.后来发现我错了,W3C还不全面. 真正全面的覆盖了web前端知识体系的东西是——浏览器内核 ...

  3. 【转】傅盛:怎样做一个创业公司CEO?

    摘要 : 傅盛High聊会,泉灵姐姐给的命题作文.怎样做一个创业公司CEO,核心还是思维模式. 这次傅盛High聊会,泉灵姐姐给我的命题作文.创业要如何开始,本质还是思维模式.首先学会把一个开放式问题 ...

  4. 我发起了一个 支持 ServerFul 架构 的 .Net 开源项目 ServerFulManager

    大家好,  我发起了一个 支持 ServerFul 架构 的 .Net 开源项目 ServerFulManager . ServerFulManager 的 目标 是 实现一个 支持 ServerFu ...

  5. 多个微信小程序一个服务端架构

    由于某些特定的业务场景,当多个小程序需要一个服务端后台提供数据时,大家可能想到是HTTP路由.是的,实际上我们使用微服务的GateWay网关也是一样的,如下图微服务架构: 网关GateWay的作用在于 ...

  6. SaltStack 是一个服务器基础架构集中化管理平台

    SaltStack详细部署   一.基础介绍============================================================================== ...

  7. 成为一个高级java架构师所需要具备那些技能呢?

    一.什么是架构师 所谓架构师,思考的是全局的东西,是如何组织你的系统,以达到业务要求,性能要求,具备可扩展性(scalability),可拓展性(extendability),前后兼容性等.可能涉及到 ...

  8. 2020年如何成为一个高级AVA架构师(50W~100W年薪)

    2020年如何成为一个高级AVA架构师(50W~100W年薪)

  9. 实现类似QQ单一账户登录,在另一个地方登录后在原登录窗口提示下线

    首先,使用框架做的最好,可以在框架页直接做一次就好了 再登陆成功后保存session的代码后添加以下代码: 注意:需要引入命名空间using System.Collections; SetApplic ...

随机推荐

  1. H.264 RTP PAYLOAD 格式

    H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+      |0|1|2|3|4|5|6|7 ...

  2. MySQL自成一派的查询提示

    [查询提示] MySQL中可以给select语句各种提示,比如告诉它“查询的结果集特别大,请直接用磁盘临时表”,“请让这条select优先执行” .... [查询提示:与结果集相关] 与结果集相关的查 ...

  3. django 用户管理系列:1 user

    :first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdow ...

  4. CentOS 7.3 安装指南

    摘要: 基于 Red Hat 企业版的源代码的最新版本的 CentOS 7 在今年的 12月发布了 CentOS Linux 7 (1611),包含了许多 bug 修复.新的包更新,比如 Samba. ...

  5. flask中路由的本质源码分析

    flask中url的本质: 吧url和视图函数封装到一个Rule对象里面去了,并且吧这个对象添加到url_map中 Rule={"url":'/index','method':'i ...

  6. js两个日期相减

    function dateHanle(d1,d2){ if(Date.parse(d1) - Date.parse(d2)==0) { console.log("d1等于d2"); ...

  7. ASP.NET MVC中切换模板页(不同目录的cshtml文件)

    看来以后建立一个父类控制器还是有必要的... using System;using System.Collections.Generic;using System.Linq;using System. ...

  8. ios获取文件的MD5值

    一般我们在使用http或者socket上传或者下载文件的时候,经常会在完成之后经行一次MD5值得校验(尤其是在断点续传的时候用的更 多),校验MD5值是为了防止在传输的过程当中丢包或者数据包被篡改,在 ...

  9. Android Lock Pattern 图案解锁

    参考链接:http://www.cnblogs.com/dyingbleed/archive/2012/12/03/2800007.html http://blog.csdn.net/way_ping ...

  10. DOUHAO

    https://www.java-forums.org/new-java/42610-java-regular-expressions-comma-seperated-list.html https: ...