现有系统实施微服务架构改进经验

5443

本文是凤凰牌老熊分享的关于微服务系统建设相关的话题。 分享已经做过的一个项目和正在做的一个项目。这两个项目都是对现有系统进行微服务改造,重点介绍具体技术改造的内容,为后来者提供借鉴参考。

先介绍第一个项目的技术改造。这是一个数据仓库的建仓项目。 公司的业务数据的读写往往都会分布在多个项目中,这给前端数据展示以及数据分析造成困难。拿视频数据来说,其元数据,如作者、演员等信息,一般会由内容管理系统来生产;而视频流数据,如编码、时长等,是由编码系统来产生的。视频的观看人数、点击数等,又是由统计系统来提供。

而在页面展示的时候,这些内容都要同时显示出来。这就需要一个数据仓库作为中介,将所有数据收集起来,并提供给前端使用。 这个数据仓库系统基本上会对接公司所有的业务系统,提供数据读、写和分析支持。

我在2014年接手这个项目的时候,已经有一个比较稳定运行的系统。实际技改工作是2015年初开始,2015年底完成。成果主要包括:

  • 数据读写的性能大幅提升。高峰期读的QPS 由 50次/分钟,提升到 2万/秒,日访问量也从2万左右,提升到接近20亿。并可以轻易横向扩展。数据写入能力,也从30TPS/秒,提升到3000TPS/秒。
  • 从单机房服务,扩展到异地三机房同时提供服务。让大部分业务访问都能够在同机房内部完成。跨机房数据同步,正常情况下,在1s内可以完成。
  • 新接口开发投入的effort缩短,从原有的1-2天,进一步缩短到2小时即可上线。

在这过程中,我们在对原有系统做技术升级的同时,也引入了微服务框架来做实现。作为技改项目,我们的原则是:小步快跑,积小胜为大胜。在保证线上系统稳定运行的同时,逐步改进原有系统。 这是一个核心系统,一旦出问题,公司整个业务都会受到影响。技术改造是一个高风险的工作。 除非是上级领导明确要求并同意把这个工作作为考核指标来激励团队,否则很难以推进。 另外也要得到团队成员的支持。 我们启动这个工作前有半年的准备期,其中很大一部分工作是在争取大家的支持。最后也是认可这个架构的人才参与系统改进工作,确保整个工作是按照预定设计逐步推进。

这个项目我们进行的还比较顺利,原来的系统的基础还算比较好。 老项目有三个大工程,实现数据读、写、同步。对外提供的是RPC接口,使用Apache Thrift作为RPC框架和服务器。 数据同时写入到MongoDB和HBase中。

MongoDB主要用来支持数据读取,而HBase用来支持数据写入。主要问题在于:

  • 虽然原项目设计打算用Mongodb和HBase来做读写分离,实际实现的时候并未达到这个目标。数据是同时写入MongoDB和Hbase的。这经常导致数据不一致,在高峰期写入时,由于MongoDB的特性,经常发生写入失败的情况。
  • 项目规模大,维护困难。几个核心类,每个类规模都超过2000行。新员工入职后,没有半年的熟悉时间,都不敢动核心代码。
  • 开发进展慢。由于这个项目提供的是后台数据功能,一般产品规划时很容易漏掉这里的工作。当想起来需要支持的时候,给的开发时间都不多。

需要我们在架构和流程上做调整。具体来说,在微服务化的层面,我们做了如下工作:

1. 建立服务网关

这是一个很重要的工作,有了网关的支持,我们就可以根据需要把流量在新老系统之间切换。我们采用的是zookeeper和网关服务来实现。所有服务注册到zookeeper上,网关服务根据zookeeper的注册项来将用户请求按比例打到具体的工作机上。这比直接访问工作机会增加1ms左右的开销。在网关上使用Netflix Hystrix来实现熔断和限流。

2. 细分业务,读写分离

一提到读写分离,很多人直观概念是使用主从的方式来实现。 实现上还需要根据业务情况来详细分析。 这个项目中,我们将数据写入场景做了详细的分析,按场景来拆分原有数据读写接口。 在写入上,我们按照场景拆分为如下接口:

  • 高速写入。主要用于离线分析结果入库。 采取的方案是分析数据通过MapReduce、Spark等框架写入到Kafka中,我们接受Kafka的数据,灌入到HBase中。 每天变更数据在千万量级,1小时左右时间完成写入。这些数据变更无需实时通知业务方。
  • 中速写入。主要用于支持线上数据的入库。数据通过RPC服务接口直接入库到Hbase中,支持每秒在3000TPS左右的写入。
  • 低速可靠写入。主要用于支持人工生产数据入库。数据也是通过RPC接口来写到HBase中。数据写入后,通过消息机制来通知各业务方相关的改动。

在读取功能上,我们也拆分为两类工作:

  • 可靠读取,主要用于支持数据生产工作。同一条数据会有不同业务方来通过工作流来写入,后写入者需要通过上一个写入者的数据来确定写的内容。这种情况,要求能够随时读取到可靠的数据。 对于这些读取,我们是直接将请求打到持久化库中(Hbase)。
  • 高速读取,主要用于支持线上数据查看。这类操作一般对数据的实时性要求不高。我们采用Couchbase来做缓存,支持线上读取。 废弃早期的MongoDB。我们一个Couchbase可以轻松支持线上上万的QPS。

这就涉及到数据同步问题了:

  • 读写库之间的数据同步,我们通过MQ(Apache ActiveMQ,桥接)来实现。 数据写入到HBase时,发出Message。读库接收到Message之后,更新自己的数据。
  • 跨机房数据同步,我们也是走的MQ。相对来说,MQ对网络不像数据库内部同步机制这么敏感。 在网络出问题的时候,MQ能够尽快恢复。同时监控起来也方便。

这里有一个小细节,实际上跨机房的Couchbase数据同步,我们也是走的MQ。在每个机房接受MQ之后更新Couchbase的数据。 我们的Couchbase定位于缓存,仅保存热数据。从实践中发现,不同地域的人,关注的数据还是不一样的。这导致Couchbase的内容差异不少。

3. 接口拆分,微服务化

有了网关的支持,明确拆分目标和架构后,我们就可以将原项目中庞大的实现类做拆分,按照服务来切分,建立Project。每个Project仅实现不会超过5个接口,这些接口都是高内聚的、同功能的,仅仅是参数略有不同。 拆分之后,每个项目中的实现类都很少,不会超过10个,而且每个类的规模也很小,代码行数不会超过300行。 新员工入职后,都能够立即上手。

4. 完善基础设施

在微服务环境上,我们采用Git做版本控制,GitLab做代码审核, Jenkins来支持自动发布和上线。正在小规模试用Spring Cloud,效果还不错,后续会继续推广。

第二个项目是我当前正在做的。这是一个支付系统,面临的情况比第一个项目复杂多了,也是更典型的一个项目。原系统是SSH框架,很难想象支付系统会采用这个技术选型。不过大部分现存的web系统也都是采用这个框架,这个改造可以为大家提供更相似的实战经验。老系统规模庞大,每个项目都有超过1000个类,最大的一个项目有3000多个类。由于项目正在进行中,可以分享的内容还不多。

项目完成后,争取有机会和大家一些再做交流。 目前可以分享的要点主要有:

  • 这个项目我们采用Spring Cloud来作为微服务的框架。
  • 我们将系统拆分2个大层,不包括前端系统。一层是对外提供的Web服务,采用http/json。 一层是业务逻辑层,供Web服务层调用,采用RPC来实现。
  • Web层采用Spring Boot来实现;
  • RPC层采用Apache Thrift 来实现。
  • 服务网关使用Nginx + Lua实现Load Balance、限流、服务自动发现。
  • 基础设施上,仍然是Git + GitLab + Jenkins。

推荐文章

沪公网安备 31010702002009号