<< 返回文章列表

基于支付场景下的微服务改造与性能优化(三)

2019年6月17日
程超等
1580


4.2 从整体架构的角度看


1)采用单体集群的部署模式


当团队和项目发展到一定规模后,就需要根据业务和团队人数进行适当拆分。如果依然使用单体项目做整体部署,则项目之间互相影响极大,再加上团队人员达到一定规模后,没有办法进行项目的维护和升级。


2)采用单机房的部署方式


现在互联网项目对稳定性的要求越来越高,采用单机房部署的风险性也越来越高,像黑客恶意攻击、机房断电、网线损坏等不可预知的故障发生时,单机房是无法提供稳定性保障的,这就需要互联网企业开始建设同城双活、异步多活等确保机房的稳定性。


3)采用Nginx+Hessian的方式实现服务化


Hessian是一个轻量级的Remoting on HTTP框架,采用的是Binary RPC协议。因为其易用性等特点,直到现在依然有很多企业还在使用Hessian作为远程通信工具,但Hessian并不具备微服务的特点,只作为远程通信工具使用,而且Hessian多偏重于数据如何打包、传输与解包,所以很多时候需要借助Nginx来做服务路由、负载和重试等,而且还需要在Nginx中进行配置,也不能动态对服务进行加载和卸载,所以在业务越来越复杂,请求量越来越多的情况下,Hessian不太适合作为微服务的服务治理框架,这时就需要Spring Cloud或Dubbo了。


4)项目拆分不彻底,一个Tomcat共用多个应用(见图11-12)
 

微信图片_20190617112203.jpg


图11-12


注:一个Tomcat中部署多个应用war包,彼此之间互相牵制,在并发量非常大的情况下性能降低非常明显,如图11-13所示。


微信图片_20190617112206.jpg


图11-13

注:拆分前的这种情况其实还是挺普遍的,之前一直认为项目中不会存在这种情况,但事实上还是存在了。解决的方法很简单,每一个应用war只部署在一个Tomcat中,这样应用程序之间就不会存在资源和连接数的竞争情况,性能和并发能力提升较为明显。


5)无服务降级策略


举个例子来说明什么是服务降级,我们要出门旅游但只有一只箱子,我们想带的东西太多了把箱子都塞满了,结果发现还有很多东西没有放,于是只能把所有东西全部再拿出来做对比和分类,找到哪些是必须要带的,哪些是非必需的,最终箱子里面放满了必需品,为了防止这种情况再次发生,下次再旅游的时候就可以提前多准备几只箱子。其实服务降级也是类似的思路,在资源有限的情况下舍弃一些东西以保证更重要的事情能够进行下去。


服务降级的主要应用场景就是当微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计超过预设的阈值时,为了保证重要的服务能正常运行,将一些不重要、不紧急的服务延迟或暂停使用。


6)支付运营报表,大数据量查询


我们先来回顾一下微服务的数据去中心化核心要点:

每个微服务有自己私有的数据库。
每个微服务只能访问自己的数据库,而不能访问其他服务的数据库。
某些业务场景下,请求除了要操作自己的数据库,还要对其他服务的数据库进行添加、删除和修改等操作。在这种情况下不建议直接访问其他服务的数据库,而是通过调用每个服务提供的接口完成操作。
数据的去中心化进一步降低了微服务之间的耦合度。

通过上述核心要点可以看到,微服务中关于数据的描述是去中心化,也就是说要根据业务属性独立拆分数据库,使其业务领域与数据库的关系是一一对应的。我们还是以支付业务场景为例,单体支付项目进行微服务改造后,业务架构如图11-14所示。


微信图片_20190617112208.jpg


图11-14


可以看到将单体支付项目进行微服务改造后增加了多个服务项目,我们可以把每个服务项目都理解为一个限界上下文,每个服务项目又对应一个数据库,这样数据库由原来适应单体支付系统的大库拆分成了多个独立的数据库。问题来了,对于后台运营统计来说这就是噩梦的开始,因为运营报表经常会跨业务进行统计和汇总,在原有运营系统上面做报表会给运营人员额外增加巨大的工作量,需要逐库进行统计,然后进行汇总。


凡事都有两面性,微服务给我们带来去中心化高度解耦的同时,也会带来报表数据及历史数据无法统一汇总和查询的问题,这时我们就需要从各个服务数据库中抽取数据到大数据平台做数据集中化,如图11-15所示。


微信图片_20190617112210.jpg


图11-15


通常大数据平台也会和每个服务的读库配合使用,大数据平台存放的往往是大而全的数据。可以把大数据平台理解为一个数据仓库里面存放若干年的数据,研发人员可以根据数据量的大小及业务情况合理利用服务的读库,这样也可以减轻查询大数据平台的压力。比如用户要查询某个服务一周内的订单情况,则可以直接从读库中进行查询,这样既可以查询到最新的订单详细信息,也可以充分发挥读库的作用。如果用户要查询半年以上的数据,因为数据量大的原因历史数据早已经被迁移走,这时可以在大数据平台进行查询。


7)运维手动打包和上线


微服务架构的顺利实施还需要强有力的运维做支撑,这就相当于一辆宝马车表面看上去特别豪华,但里面装的却是老旧的发动机。这时就需要将DevOps在全公司推广,让自动化运维和部署成为微服务的“发动机”。


五、微服务架构中常见的一些故障分析技巧



1)开发者的自测利器——hprof命令


微信图片_20190617112212.jpg



示例程序如下所示。


注:这是一段测试代码,通过sleep方法进行延时。


如何分析程序中哪块代码出现延时故障呢?


在程序中加上如下运行参数:
 

微信图片_20190617112214.jpg


再次运行程序,发现在工程目录里面多了一个文本文件java.hprof.txt,打开文件,内容如下所示。


微信图片_20190617112216.jpg



注:通过上面内容可以看到是哪个类的方法执行时间长,耗费了CPU时间,一目了然,方便我们快速定位问题


hprof不是独立的监控工具,它只是一个Java Agent工具,它监控Java应用程序在运行时的CPU信息和堆内容,使用Java -agentlib:hprof=help命令可以查看hprof的使用文档。


上面的例子统计的是CPU时间,同样我们还可以统计内存占用的dump信息。例如:-agentlib:hprof=heap,format=b,file=/test.hprof。


我们在用JUnit自测代码的时候结合hprof,既可以解决业务上的bug,又能够在一定程度上解决可发现的性能问题,非常实用。


2)性能排查工具——pidstat


示例代码如下所示。


微信图片_20190617112218.jpg


将示例代码运行起来后,在命令行中输入:
 

pidstat -p 843 1 3 -u -t
/*
-u:代表对CPU使用率的监控
参数1 3代表每秒采样一次,一共三次
-t:将监控级别细化到线程

*/


结果如图11-16所示。


微信图片_20190617112220.jpg 

 图11-16

注:其中TID就是线程ID,%usr表示用户线程使用率,从图中可以看到855这个线程的CPU占用率非常高。


再次在命令行中输入命令: 


      jstack -l 843 > /tmp/testlog.txt 


查看testlog.txt,显示如下所示的内容。

 
注:我们关注的是日志文件的NID字段,它对应的就是上面说的TID,NID是TID的16进制表示,将上面的十进制855转换成十六进制为357,在日志中进行搜索看到如下内容。
 
以此可以推断出有性能瓶颈的问题点。



出处:架构文摘(ID:ArchDigest)