基于支付场景的微服务高可用架构实战

FelHayman 6年前
   <p><img src="https://simg.open-open.com/show/152eb7e7d421566003468cf59555723f.png"></p>    <p>程超</p>    <p>智慧支付首席支付专家</p>    <ul>     <li> <p>12年Java开发经验,对互联网支付、电商业务方向较为了解,擅长分布式、性能调优等技术领域,对高并发、大数据有浓厚兴趣。</p> </li>     <li> <p>《深入分布式缓存》一书联合作者。</p> </li>    </ul>    <p>今天给大家带来的分享是基于支付场景的一个微服务实战,会更偏向于应用层的内容。</p>    <p>分享大纲:</p>    <p>1. SOA与微服务</p>    <p>2. 老支付架构所遇到的一些挑战</p>    <p>3. 基于微服务怎么做的一些改造</p>    <p>4. 未来计划要做的一些事</p>    <h2><strong>一、SOA与微服务</strong></h2>    <p>在我看来,微服务虽是国外传进来的技术,却和咱们中国的一些理论是挂钩的。所以在正式进入主题之前,先给大家简单介绍一下麦田理论。</p>    <p>1.关于麦田理论</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2206f08beedf89125492e5867837853a.jpg"></p>    <p>古代周朝时期,老百姓种地实际是没有任何规划的,也没有任何区域的限制,一般来说在地里一会种水稻,一会种小麦,一会种蔬菜地交叉来种,可收成之后发现庄稼受阳光程度非常低,营养非常不均衡,后期维护成本非常高。 直到战国时期,有一位农业专家把地划分为多个区域,每一个区域种一种庄稼,地跟地隔开,形成最初的微服务理念。</p>    <p>过去我们看到的很多文章都只是讲到SOA和微服务之间的比较,我今天在这个基础上加了一个DDD。下面就DDD、SOA以及微服务的演进过程先做个引子。</p>    <p>2.DDD、SOA与微服务</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/eba7874a3fcfd1bc62e6dcf7cc851e45.jpg"></p>    <ul>     <li> <p>SOA架构</p> </li>    </ul>    <p>SOA是上一个时代的产物,大概是在2010年之前出现的,最早提出时是提供给传统行业计算领域的解决方案,当时Oracle、IBM也提了很多方案,包括出现的很多流程引擎。</p>    <p>它的思想是将紧耦合的系统,划分为面向业务的粗粒度、松耦合、无状态的服务。在这之后,微服务的提出者基于SOA做了一个改进,就把它变成单一职责、独立部署、细小的微服务,是一个相反的概念。</p>    <ul>     <li> <p>微服务与DDD</p> </li>    </ul>    <p>今天我们一说到微服务就会想到DDD,有不少朋友认为DDD就是为微服务而生的。其实不是这样的,我在接触DDD时它最早是用来做UML设计、领域建模的。</p>    <p>DDD讲究充血模型,而J2EE模型以传统的分层架构和Spring架构捆绑在一起形成了以贫血模型为主的架构模式,贫血模型的优点是容易入门、分层清晰,而充血模型要求设计者前期对业务理解较深,不然后期项目会产生混乱。</p>    <p>另外就是DDD思想比较宽泛,导致形成百家争鸣的姿态,没有形成一套固定的方法论。开发者不容易理解,所以后面关注DDD的人变少了,而微服务的提出巧妙地借鉴了DDD里面的限界上下文、子域、领域事件等关键词,在微服务得到越来越多业界认可的情况下,也给DDD带来了重新的焕发。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5bb690c25a70768ff0b8bb363793c385.jpg"></p>    <h2><strong>二、老支付架构遇到的挑战</strong></h2>    <p>1.判断项目好坏的两个角度</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/159acf57759ad7aaba61f9202a725abf.jpg"></p>    <p>我们判断一个优秀项目的好坏,可以从优秀的代码和高可用架构两个方向来讲。我们在设计高可用架构的同时,也不能忽视代码的重要性,优秀的代码指的是冗错能力、 冥等操作、 并发情况、死锁情况等,并不一定是指代码写得多漂亮。</p>    <p>这就好比盖楼一样,楼房的基础架子搭得很好,但盖房的工人不够专业,有很多需要注意的地方忽略了,那么在往里面填砖加瓦的时候出了问题,后果就是房子经常漏雨,墙上有裂缝等各种问题出现,虽然不至于楼房塌陷,但楼房也已经变成了危楼。</p>    <p>从代码和设计的角度来看有:</p>    <ul>     <li> <p>由不合理的代码所引起的项目无扩展性</p> </li>     <li> <p>数据库经常发生死锁</p> </li>     <li> <p>数据库事务乱用,导致事务占用时间过长</p> </li>     <li> <p>代码容错能力很差,经常因为考虑不足引起事故</p> </li>     <li> <p>程序中打印的大量的无用日志,并且引起性能问题</p> </li>     <li> <p>常用配置信息依然从数据库中读取</p> </li>     <li> <p>滥用线程池,造成栈和堆溢出</p> </li>     <li> <p>从库中查询数据,每次全部查出</p> </li>     <li> <p>业务代码研发不考虑冥等操作</p> </li>     <li> <p>使用缓存不合理,存在惊群效应、缓存穿透等情况</p> </li>     <li> <p>代码上下流流程定义混乱</p> </li>     <li> <p>异常处理机制混乱</p> </li>    </ul>    <p>再从整体架构角度来看:</p>    <ul>     <li> <p>整体依然使用单体集群架构</p> </li>     <li> <p>采用单机房服务器布署方式</p> </li>     <li> <p>采用Nginx+hessian的方式实现服务化</p> </li>     <li> <p>业务架构划分不彻底,边界模糊</p> </li>     <li> <p>项目拆分不彻底,一个Tomcat共用多个应用</p> </li>     <li> <p>无故障降级策略</p> </li>     <li> <p>监控系统不合理(网络、系统)</p> </li>     <li> <p>支付运营报表,大数据量查询</p> </li>     <li> <p>运维手动打包,手动上线</p> </li>     <li> <p>系统扩容手动布署</p> </li>    </ul>    <p>基于以上两点,我们可以清晰地看到以前老项目的存在问题,并开始思考新的微服务架构应该怎么去做。</p>    <h2><strong>三、基于微服务怎么做的改造</strong></h2>    <p>想做高可用的微服务架构,必须先确立以下五个点:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d7ffc1d91e7aa0fa291618ce742d0e24.jpg"></p>    <ul>     <li> <p>一是 <strong>产品迭代速度</strong> ,当架构设计完以后一定是对产品有利的,不能设计完了之后反而比以前开发得更慢了。这也是微服务的核心,通过把业务拆迁,将不同的产品一个个进行产品化,而不是项目化。</p> </li>     <li> <p>二是 <strong>系统稳定性</strong> ,单体架构时一个系统报错就全部报错,现在更粒度细一些,同时架构各种监控。</p> </li>     <li> <p>三是 <strong>系统稳定性</strong> 。</p> </li>     <li> <p>四是 <strong>问题快速定位</strong> ,也就是每年给我们几十分钟的故障时间。</p> </li>     <li> <p>五是 <strong>系统耦合度</strong> ,不要把系统都放在一起,要多拆开。</p> </li>    </ul>    <p>1.利用DDD来划分限界上下文</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/68bad46797d4e7a5e6e1ad383c45e2e3.jpg"></p>    <p>这是根据一些业务场景做的业务架构图,中间绿色部分是产品服务层。 用DDD的思想来分析,产品服务层也就是产品服务域,这个域里包含三个子域,一个是收银台子域,一个是商户子域,一个是个人子域。每一个域里都包含有限界上下文,收银台包含两个,商户包含四个,个人包含两个。</p>    <p>有些同学可能不太了解限界上下文概念,可以把它理解为一个系统、一个边界或者一个实体。比如说我们每天上班要倒三次地铁,这里面的关键事件是什么?就是上班,那限界上下文就是坐地铁,中间切换三次。</p>    <p>限界上下文就可以把它理解为一个微服务,也可以把它理解为一个系统、一个模块。</p>    <p>限界上下文的划分可以根据我们的团队规模来定,如果团队规模没有达到一定的程度,可以将边界定的粗一些,如果项目规模和团队规模不断扩大,还可以再把大的领域和限界上下文继续拆分成多个小的。</p>    <p><strong>2.微服务治理架构图</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/97d39d622fafddc512e177a9d9b55c93.jpg"></p>    <p>这是我们大致的一个微服务整体流程图,采用的是Spring Boot+Dubbo的架构。</p>    <p>为什么主张用Dubbo而不是Spring Cloud?有几点原因:</p>    <ul>     <li> <p>一是要看目前这个架构是什么,如果是Dubbo,很多组件的一些设施都要围绕它来做,如果这时把它完全推倒换成别的架构,成本部分我们需要慎重考虑。</p> </li>    </ul>    <ul>     <li> <p>二是Spring Cloud技术虽新但不见得一定比Dubbo好用。目前公司就维护了一个叫Dubbo Cloud,自己研发一套基于Dubbo的微服务体系。</p> </li>    </ul>    <p>上图中间这块的探针也是我们自主研发的,能够实现把整个服务链路的各种信息,比如掉网时间、报错、返回值以及参数全部采集到,采集完之后就把这些信息用把一个开源组件进行改造,把信息全部推给它,透过那个界面展示出我们要的东西。</p>    <p>后面这一套比如Hystrix熔断、Dubbo Admin和Mock Server我们是参考Dubbo的思路做的智能化拦截和服务降级。后面的服务注册、服务发现、服务路由、失败重试和服务监控等是Dubbo本身提供的,也就是图片绿色的部分是我们自研的新功能,未来我们会把这个Dubbo Cloud体系进行开源。</p>    <p><strong>3.通道报警切换系统的演进</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/096269659939b71c5f8ec53054827e4d.jpg"></p>    <p>这是我们通道报警系统的框架演进。为什么叫“通道”呢?因为我们的支付要接银行,但银行本身是相对偏传统的,它们的通道不是很稳定,经常有各种各样的问题,而每个银行都有N个通道,我们无法得知哪个通道近期是稳定的或不稳定,都是会来回变的。</p>    <p>这里我们自研了一个Agent,通过采集它通道里的一些使用数据,比如说这次我们连成功了,获取到了数据,然后放到Kafka里,之后还有一个统计分析的东西,如果这个通道连接成功一次会对它统计加一次,最后把每隔一段时间的结果存到Redis集群里。</p>    <p>图中的路由系统就是做通道选择的。这是一个业务系统,路由系统每次在做通道选择时要先从Redis集群里把这个银行的通道拿出来,选出评分最高的一个。</p>    <p>拿出后再经过自己的一套路由选举的配套做一个清洗或者选择,最后得到一个最优的通道,直接连到银行通道上,这样我们就能知道哪些通道是高可用的。</p>    <p>底下的过程还是通过Kafka,并进行各种各样的统计分析,也非常好用。然后这里会有一个图表,如果当前有问题,在界面上都能可以看到,同时可以给你发短信、发邮件。</p>    <p>为什么我们这里做了两套?第一期的时候我们要做一个数据的比对,因为如果采集的数据不准确,这个通道就会存在问题,所以我们一方面是通过上面这种方式来做评分策略,另一方面是把数据采集过来以后放到一个库里,通过这个库再做一次,最后每次做一个比较,以统计正确率。</p>    <p>当这个通道也发生了问题,比如某一个银行通道发生了问题,我们的监控系统就会直接把银行通道设置为不可用,然后通知研发部门让他们去解决,完了以后再把这个通道变为可用。如果这个过程数据不准确,会造成频繁的通道切换,会产生有很多不必要的问题,所以在第一期时我们先做成半自动化的。</p>    <p><strong>4.双活体系架构的演进</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0cdcc97ed259917eab996479c41c01c2.jpg"></p>    <p>双活机房的演进,也是需要两个阶段。</p>    <p>其中, <strong>第一个阶段是伪双活:</strong></p>    <ol>     <li> <p>两 个机房同时提供服务,但需要设置主备机房;备机房的应用只能通过专线访问主机房的数据库;备机房的Redis也需要通过专线访问主机房的Redis。</p> </li>     <li> <p>当主机房挂了后,需要先将备机房应用的数据库配置改成备库,同时备库停机,修改备库为主库。</p> </li>    </ol>    <p>第二个阶段是泳道双活:</p>    <p>双活体系架构的演进,在ZK做数据同步的时候,采用两种方式Curator的TreeCacheListener监控相应节点的变化从而同步数据 ,另一个是修改ZK源码伪装成Observer接收事务日志数据从而实现数据同步。</p>    <p>ZK的同步最好还是不进行同步、泳道隔离,比如像使用Dubbo这种的时候,完全可以同步二套环境,如果使用当当的Elastic-Job,在做双活的时候就会相对麻烦。</p>    <p><strong>5.微服务架构全景图</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/27b4ef94944a5000a747b6fe3e43b834.jpg"></p>    <p>这个就是我们整个微服务的整体架构。 图中左半部分体现了怎么把服务进行划分,划分了哪些领域,然后有哪些服务,数据库内容怎么划分,网关层怎么做的,是从业务角度来做的一个划分。</p>    <p>右边这块是体现我们如何保障微服务的可靠性。第一层主要是给项目运营人员使用,第二层是我们为了保障微服务都做了什么东西,有统一调度中心、双活管控架构,还有大数据平台、分布式缓存,做了各种各样的组件来保障微服务顺利的开展。</p>    <p>再下面是一些监控,这里我们用了APM分布式调链的监控,包括我们自己也做了一些监控平台。</p>    <p><strong>6.持续集成测试</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/afe4aea4abf2832b61ebd78fcd20efaa.jpg"></p>    <p>接下来讲讲我们的持续测试经验。怎么来保证代码的质量?这里就涉及到了集成测试的概念。</p>    <p>我们分了四个象限,一是单元测试,这是由开发自己来做的,一般覆盖率在60-80%就不错了;二是验收测试和探索测试,这两个实际上是我们的测试人员在做,一个是验证业务的可行性,一个是采取一些非法条件或者是一些破坏性测试,最后是压力测试,通过压测看系统能承受的负载情况。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/125a0216eb897227df668b7f2fe2eac6.jpg"></p>    <p>这是我们的整个测试流程。首先,我们参照了阿里和其它公司的一些编码规范,制定一套自己的编码规范,并跟所有开发人员达成共识。然后我们有自己的静态代码检查,这里也可以用阿里的组件,这是前两步。</p>    <p>第三步就是单元测试,基本上前三部分都是由开发来保障代码的健壮性和正确性。第四是持续集成,我们根据自己的规则和模板对它再进行一次代码的扫描,扫描完后之后就组织一些架构师或是技术专家,对一些关键核心代码再做一个代码重构,大致是分了五步。</p>    <h2><strong>四、未来计划要做的事</strong></h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f4aba96dd3aeb490ec694d9f3790632d.jpg"></p>    <p>上图几点就是未来我们计划要做的一些事情,因为现在业务量越来越大了,而不久后央行会再出一个文件,要考虑异地多活这个情况,这块我觉得是一种趋势,目前也很多公司在做这件事情。</p>    <p>然后我们也会有一个Dubbo Cloud,未来也是会开源的。后面就是大数据平台的持续建设,目前我们的大数据平台还不是特别完善,像数据的挖掘这块还没有做,而现在一般的金融公司还有支付公司的风控都要做得特别好,而我们才刚起步。</p>    <h2>问答环节</h2>    <p><strong>【问题1】 </strong> 老师您这边做的东西特别多,那人员架构是怎么设置的?</p>    <p><strong>答: </strong> 微服务这边是三十多人在做。</p>    <p><strong>【追问】 </strong> 那么Dubbo Cloud这边的一些事,比如监控和下面一块的操作,这都有是吗?</p>    <p><strong>答: </strong> 对,这整个部门都是我在负责,我们有划分了多个不同的部门,每个部门做不同的事,Doorco是我们部门的事,这个监控也是我在做,这个运维就是运维研发我们定位也是一个部门。</p>    <p><strong>【追问】 </strong> 人员比例大概是怎样的呢?</p>    <p><strong>答: </strong> 这里大概有六七个人在做这个事,比如这里有三四个,上面有七八个,上面有四五个,大概是这样。因为现在如果保证每一个模块都是几个人去做也不太现实,因为需要人很多,而且可能每一个模块都会交叉去做,每个人都会负责多个模块。</p>    <p><strong>【问题2】 </strong> 我们也做日志的东西,您刚刚说20-30%的丢失率,这块是怎么优化的?</p>    <p><strong>答: </strong> 这块尤其是ELK,我们最开始用的时候是有一个Flume采集,采集时经常丢失,压力特别 大。而压力特别大时Flume就会出现性能问题,丢一些数据。后来我们改成Logtash,当然ES这块也需要研究,因为ES搞不好的话也会丢数据。</p>    <p><strong>【问题3】 </strong> 老师您好,我们也是做分布式监控的,构建的跟您这个比较相似,也是用Spring Boot+Dubbo,因为我们用了内部研发的新架构,有一个问题就是因为我们在用这个架构时发现如果服务比较多,性能会下降,有可能比较拖累,因为一个代码链路过来之后,短的、中程的还好点,一个大程的项目过来整个服务压力就扛不住了,这一点我们现在比较困惑,您有没有什么建议?</p>    <p><strong>答: </strong> 这个确实是一个问题。我们一开始也是用的这个东西,但在数据采集这块有性能问题,压力特别大时整个探针就有问题,因为探针采集数据是一方面,采集的数据也是有限的,比如一个链路里有一个系统搭错了,但错误信息你是采集不到的。我们的做法是把错误信息采集到,正常情况下链路中的系统都是绿灯,如果报错了系统就会亮红灯,这样就能很快定位到问题根源,同时能看到报错信息。 </p>    <p><strong>【追问】 </strong> 这套东西会开源吗?</p>    <p><strong>答: </strong> 这个现在还没有考虑,后面可以多交流。</p>    <p><strong>【问题4】 </strong> 您好,看到您的探针基本都加在服务上,但有一些服务可能因为服务起调时是在UI界面上发起的,而我们往往JS端可能也要采集一下,才能实现一个真正的闭环,您在JS端有做过这方面的探索吗?</p>    <p><strong>答: </strong> 我们是做第三方支付的,主要是针对后台服务端的,我们只提供API和接口,提供一个收银台,比如京东要对接我们时就直接把数据发过来,因为我们是收单的。</p>    <p><strong>【追问】 </strong> 那么这个探针输出的数据不用落地的吧?</p>    <p><strong>答: </strong> 对,不用落地。</p>    <p><strong>【追问】 </strong> 那您应该了解Egoi是吧?Egoi是落地的,当时我玩这个东西的时候,Egoi整套东西都是在Doorco上部署的,经常出现问题的就是当规划量非常大时并不是写日志写不进去,而是算掉链的时候经常出问题,经常会5个CPU、8个CPU都不够用,往往跟业务系统都是混步的,经常会把业务系统干倒。您这边我没太了解,推特那边算是用Storm还是什么?</p>    <p><strong>答: </strong> 它不是Storm,是自己写的一套东西,但比Storm要强。</p>    <p><strong>【问题5】 </strong> 单元测试用的是什么工具?</p>    <p><strong>答: </strong> 现在是JUnit来做的。</p>    <p><strong>【追问】 </strong> 是自己写程序,自己挂上的吗?</p>    <p><strong>答: </strong> 对,在上线的时候我们是要求写的,而且是能跑通的。</p>    <p><strong>【追问】 </strong> 咱们进行代码检查的时候自己写的规则多吗?通过这块查出问题,效果怎么样?</p>    <p><strong>答: </strong> 一般的、简单的还是效果可以的,但深层次的还是发现不了,比如Redis建立一个连接关闭一个连接这种能检查出来,但说要看看有没有深层溢出这类的,看不出来。</p>    <p><strong>【追问】 </strong> 后面第五步是做代码,这个是有工具吗?</p>    <p><strong>答: </strong> 这个我们用Gerrit这种方式,这个是代码,上线之前要把代码发给不同的人,可以在上面进行各种点评,点评完之后开发者要把所有点评的东西关闭掉以后才能上线。</p>    <p><strong>【问题6】 </strong> 因为您提到会开源,咱们这块开源是说比如您这儿研究了一下然后觉得不错就拿到团队用了还是有什么机制?这块能分享一下吗?对于开源工具的选择。</p>    <p><strong>答: </strong> 首先我们要看需求是什么,根据需求的不同来看是选择特别重的开源组件还是轻量级的,像我们在做分布式定制任务和统一配置中心,这两个我们是用的开源产品,其中统一配置中心我们用了携程的一个组件阿波罗,因为它本身是用Spring Cloud来做的。</p>    <p>彩蛋来了</p>    <p>在本文微信订阅号(dbaplus)评论区留下足以引起共鸣的真知灼见, 小编将在本文发布后的 隔天 中午12点根据留言精彩程度选出1位幸运读者 , 送出以下好书一本 ~</p>    <p>新规说明: 同一个月份里,已获赠者将不可重复拿书。</p>    <p><img src="https://simg.open-open.com/show/ea706ece4f5b16659f1913855303c33e.jpg"></p>    <p>特别鸣谢图灵社区为活动供图书赞助。</p>    <p> </p>    <p>来自:https://mp.weixin.qq.com/s/gzk1ce3-zn5nWJ5VRVOEAQ</p>    <p> </p>