分布式调用其他服务的service_分布式调用链系统

        在以前单体或者集群架构,用户一个请求过来或者经过反向代理,直接到web服务器,操作数据库,返回用户请求结果。在这种情况,请求的调用链,我们可以通过函数之间的调用,打日志,系统如果出现异常,可以通过分析日志去找bug;如果系统遇到性能瓶颈,想知道从请求进来到返回,是业务哪一步出了问题,可以通过调用链路间请求时长分析出耗时的操作,针对具体的去优化。

        但是随着系统架构的改进,微服务分层架构实施,上层会调用下层服务(如最上层的站点业务服务,会调用基础的通用业务服务,通用业务服务又会去调用数据访问层服务),此时你的日志只能打在自己的服务上,其他的服务日志由其他人去打印。这样就出现几个问题

一,定位故障的过程非常痛苦

        如果一个用户请求你的A服务,可能timeout or error。此时你就要去分析自己的日志,发现是你调用的一个B服务出现了问题,你就要通知B业务线,去找问题,B检查后会发现,是他自己调用的C服务出问题了,然后就这样剥洋葱一层层的反馈,可能最终问题只需要五分钟解决,但是找问题就花费了两个小时。

二,定位系统瓶颈很困难

        如果你的服务在用户调用时候耗时很慢,比如1s,你想要分析出具体是哪一步耗时严重,此时由于是分层的,你只能在自己系统打日志,比如查到了是调用B,但是B也是存在调用,所以一层层找,很难分析出瓶颈的原因所在。

三, 不合理的调用,和弹性扩缩容困难

         不合理的调用:我们微服务架构,要做到调用远端的服务就像是调用本地函数一样,但是很多人有误解就会觉得和调用本地的方法一样消耗性能,就往往会不考虑后果在循环中调用,此时你分析你的日志,无法分析出这是一个请求调用了几十次服务。

        弹性扩缩容:由于现在的分层调用B服务作为下游服务,只知道上层有人调用,此时B 根本不知道有多少在调用自己,当B系统瓶颈加一台机器要通知所有人的时候,可能要去各个的产品线去询问有没有调用自己,自己加了机器,你们要做一下同步,让流量打到新服务节点。

解决上面的痛点需要用到分布式调用链追踪系统,这也是这篇文章的重点

分布式调用链追踪系统有什么特点?

1 全链路

        日志的记录是全链路的,从请求进来,到web层,业务service,基础service,db,cache 等,一整条链路每一步的调用都有记录。

2 跨进程

        跨站点,跨服务,跨存储等都是不同的进程。

3 全流量

        不仅仅要做到描述清楚服务与服务之间的依赖关系,还要做到精确,精确到每一步的调用,每个数据库语句的执行时间等。

实现分布式调用链追踪系统有什么难点?

1 跨进程串联标识问题,

        刚刚说了跨站点,跨服务,跨存储就是跨进程,我们如何把这些请求到达各个节点给串联起来呢,也就是一个请求进来,如何知道A->B->C,他们是同一个请求造成的这些依赖请求调用;

2 跨进程时序问题

        因为是跨节点,不同的机器,机器本地时间也不同,你如何做到时间的一个偏序性,如果是单机系统,所有的时间都是同一台机器,先后的请求时间肯定是有偏序性,但是现在可能记录的时间在A机器是10点,请求调用B后,B服务记录的是9:59分。

3 跨进程调用深度的问题

9c1dc8078ee197ba6b3c07fe656203d6.png

        如上图,左边调用深度是2层,a先调用服务b在调用服务c,右边调用深度是3层,a->b->c;此时通过时序判断调用层级肯定不行,因为现在在三台机器的时序肯定是一样的,都是先a 再b 再c。

分析了痛点,我们要知道改哪些地方?

6821d0a9cbf261f42a6e3da712750856.png

        分析一下上面的图片,是一个http请求的全链路,从开始到结束。我们如何做才能做到一个请求在各个系统造成的记录日志能标识出来是来自于同一个请求,如何做到在各个系统记录的日志有偏序性,如何做到,每一个调用的层级关系。

        1 改框架,要记录请求开始和结束的点。

        2 改rpc ,rpc-client要记录调用service的开始和结束的点,service要记录接到请求和请求结束的点

        3 改db-client, 要在数据访问层封装一层,记录请求的sql,请求db开始和结束的点。

        4 改cache-client  原理同db-client.

知道了要改哪些地方,我们如何去改呢,也就是如何解决上面的三个难题?

        我们可以通过定长header的tranceid+spanid 去解决上面的两个维度的问题。

tranceid:表示一个请求链路,跨进程跨服务调用,由请求进来时候最上层web-service生成,全局唯一,整个请求调用链路一直不变,表示是同一个请求。

spanid: 用来表示每一层的rpc调用。表示深度和时序性

dc1c9a9d327526d256d2b6c08362c530.png

ps:主要解决在webservice中,我们想从另外一个项目调用webservice项目的接口,也就是跨项目调用接口 这里主要用到了xfire wsdl 废话不说了 直接上东西 1. 首先新建一个项目 2. 在src下创建两个文件: a) 第一个是你想要访问的webservice的接口,比如我想访问的接口是 ReleaseService 那就在当前项目创建一个ReleaseService接口(接口中的方法必须和你想要访问的webservice的接口中的方法相同) b) 第二个是你的调用类 3. 导入相应的jar包,这些包不能引用,一定要复制到lib文件夹下面在引用 4. 具体的实现代码 TestWebService方法的代码: package com.isanta.webServiceTest; import java.io.InputStream; import java.net.MalformedURLException; import java.util.Properties; import java.util.Scanner; import org.codehaus.xfire.XFireFactory; import org.codehaus.xfire.client.XFireProxyFactory; import org.codehaus.xfire.service.Service; import org.codehaus.xfire.service.binding.ObjectServiceFactory; public class TestWebService { /** * @param args */ public static void testWebService() throws MalformedURLException, Exception{ // TODO Auto-generated method stub /** *这里是我的参数放在了properties文件中,我在读取里面的参数,这里我们也可以通过方法传参数 *如 : testWebService(String url,String xMlStr)() 那么在调用的时候就可以直接传进来了 *url 是你访问的webservice 的tomcat 的服务器地址 */ Properties pro = new Properties(); InputStream in = null; in = TestWebService.class.getResourceAsStream("/request.properties"); pro.load(in); String url = pro.getProperty("url"); String xMLstr = pro.getProperty("xMLstr"); Service s=new ObjectServiceFactory().create(ReleaseService.class); XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire()); System.out.println("url="+url); try { //这里就是获取webservice的接口的实例对象 ReleaseService seleaseService=(ReleaseService) xf.create(s,url); System.out.println("进入接口----------------->请求报文:"+xMLstr); //这里就是调用你需要的接口的方法 String st=seleaseService.queryReceiptDatas(xMLstr); System.out.print(st); } catch(Exception e) { e.printStackTrace(); } } } 5. 将整个项目打包成jar 6. 将打好的jar包引入到你想要调用的项目中,然后就想 正常的代码一样来调用,如: import java.net.MalformedURLException; import com.isanta.webServiceTest.TestWebService; public class Test { public static void main(String[] args) throws MalformedURLException, Exception { TestWebService.testWebService(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值