-
在上一篇 《ServiceComb + SpringCloud Ribbon使用篇》中介绍了负载均衡的概念和ServiceComb协同SpringCloud Ribbon的使用, 本篇将从源码角度介绍ServiceComb是如何实现与SpringCloud Ribbon协同工作的。一. ServiceComb对接 Spring Cloud Ribbon思路在Ribbon的wiki介绍页(https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers)可以发现这样的描述:ServerList - this can be static or dynamic. If it is dynamic (as used by DynamicServerListLoadBalancer), a background thread will refresh and filter the list at certain interval这段介绍了ServerList接口,该接口既可以是静态获取服务实例列表也可以是动态获取的。如果是动态获取服务列表(被DynamicServerListLoadBalancer使用),会有一个后台线程在特定得时间间隔负责刷新和过滤服务列表。也就是说,我们只要实现了ServerList接口,加上相应的配置让Ribbon获取到,就能向Ribbon提供ServiceComb自己的服务发现逻辑。如下图↓↓↓ServiceComb 在如下的org.apache.servicecomb:spring-boot-starter-discovery项目中实现了ServerList接口和相应的配置。<dependency> <groupId>org.apache.servicecomb</groupId> <artifactId>spring-boot-starter-discovery</artifactId> <version>1.1.0</version></dependency>二. 源码分析项目结构如下图,红色方框内为接入SpringCloud Ribbon组件的相关类。下面我们分别来看看这几个类↓↓↓ScbRibbonConfigurationConfiguration 表示这是一个spring的配置类EnableConfigurationProperties 使@ConfigurationProperties注解生效ConditionalOnBean 只有特定名称或者类型的Bean存在于BeanFactory时才创建某个BeanAutoConfigureAfter 只有在指定类的配置类配置完后才会生效RibbonClients 允许在一个类中声明多个RibbonClient注解注意Ribbon是懒加载的,而该类在RibbonAutoConfiguration初始化配置之后才会执行配置,所以该类也是懒加载ScbRibbonClientConfiguration在ScbRibbonConfiguration类中的RibbonClients注解指定了ScbRibbonClientConfiguration来实例化RibbonClient。 如下,该类实例化了一个ServerList对象,实际类型为ServiceCombServerList,该对象会替换DynamicServerListLoadBalancer类里的ServerList对象。ServiceCombServerList在Ribbon体系中,ServerList接口负责获取服务实例列表。ServiceComb使用ServiceCombServerList实现了该接口。该类使用了ServiceComb内置的服务发现能力。ServiceCombServerList构造器里使用discoveryTree添加了一个过滤器ScbRibbonEndpointDiscoveryFilter。•DiscoveryTree是ServiceComb Registry包的类。ServiceComb Registry包提供了服务注册,服务发现与过滤器等能力。•ScbRibbonEndpointDiscoveryFilter继承了AbstractEndpointDiscoveryFilter,而AbstractEndpointDiscoveryFilter实现了DiscoveryFilter。DiscoveryFilter接口主要管理实例进行分组、缓存getInitialListOfServers方法获取初始的servers;getUpdatedListOfServers方法获取更新的serversScbRibbonEndpointDiscoveryFilterScbRibbonEndpointDiscoveryFilter继承于AbstractEndpointDiscoveryFilter类,观察AbstractEndpointDiscoveryFilter代码可发现有一个discovery方法,这个方法会被DiscoveryTree使用以获取服务列表。此时已进入ServiceComb Registry包内部,具体的细节不展开分析。关于filter类,实际上查看DiscoveryTree的源码可发现一些信息,如下是DiscoveryTree的doDiscovery方法,该方法属于ServiceCombServerList获取服务实例列表的调用链上,而该方法会将这个获取信息的任务交给DiscoveryFilter类去处理。小结本文向社区读者从源码角度阐述了ServiceComb是如何与SpringCloud Ribbon协同工作的。 [单纯使用的用户实际上不必关心这些细节] 非常欢迎爱好者们向社区提问和贡献代码:)下篇将介绍ServiceComb内置的负载均衡的能力,内置的能力可支持定制化重试策略。如在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读 [学习微服务-第6天] 负载均衡之ServiceComb + SpringCloud Ribbon[学习微服务-第5天]ServiceComb+Zipkin源码解读[学习微服务-第4天]ServiceComb+Zipkin[学习微服务-第3天] ServiceComb内置高性能网关服务[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul-----------------------------------------------了解更多信息请访问: 官方网站http://servicecomb.apache.org/ Github代码仓库https://github.com/apache?q=ServiceComb
-
在微服务架构中,客户端负载均衡是指负载均衡器作为客户端软件的一部分,客户端得到可用的服务实例列表然后按照特定的负载均衡策略,分发请求到不同的服务。ServiceComb内置了客户端负载均衡组件,开发者可以非常简单的使用。具体可参考:https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.html 本文将介绍ServiceComb与SpringCloud的Ribbon负载均衡组件协同工作,以构建微服务应用。ServiceComb已适配对应的接口和配置,用户用极简单的方法配置后即可使微服务应用具备负载均衡的能力。示例以下通过一个服务提供者provider-service和消费者consumer-service作为demo演示。provider-service会启动3个微服务实例,消费者端consumer-service使用Ribbon负载均衡调用proveder-service服务的接口。其中consumer-service在调用provider-service提供的接口时会打印出真实调用的URL ↓↓↓完整示例地址:https://github.com/lisenwork/servicecomb-demo/tree/master/servicecomb-ribbon 预置条件: 示例应先安装启动服务与注册中心ServiceCenter,详细步骤请参考官网↓↓↓http://servicecomb.apache.org/cn/users/setup-environment/#%E8%BF%90%E8%A1%8Cservice-center 一开发服务消费者comsumer-service只需三步即可开发拥有负载均衡能力的微服务步骤如下:01添加依赖新建pom文件,引入如下依赖。完整pom文件内容请参考↓↓↓https://github.com/lisenwork/servicecomb-demo/blob/master/servicecomb-ribbon/consumer-service/pom.xml 02配置 在resources目录下新建ServiceComb配置文件microservice.yaml。配置微服务信息↓↓↓03项目入口新建启动类ConsumerApplication.java。如下图,启动类里同时实例化一个RestTemplate对象。该对象用于后面的服务间接口调用。新建ConsumerController.java。在该类的consumer方法里使用Ribbon的API动态获取服务实例,并打印出被选中的实例的真实IP地址和端口。最后调用服务实例的接口,获取结果并返回。04启动项目根目录下执行命令 mvn spring-boot:run二开发服务提供者provider-service01添加依赖新建pom文件,引入如下依赖。完整pom文件内容请参考↓↓↓https://github.com/lisenwork/servicecomb-demo/blob/master/servicecomb-ribbon/provider-service/pom.xml 02配置 在src/main/resources目录下新建microservice.yaml03项目入口新建启动类ProviderApplication.java新建ProviderController.java。只向外提供/provider接口04启动 服务提供者要启动3个微服务实例。打开microservice.yaml文件,分别修改微服务监听端口为8888,8889,8890,在项目根目录下执行3次命令 mvn spring-boot:run演示浏览器访问http://localhost:7777/consumer,重复刷新一定次数,观察控制台,会发现服务消费者会轮询调用服务提供者的三个实例。小结本文向社区读者从读者角度阐述了ServiceComb是如何支持SpringCloud Ribbon的。我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb+SpringCloud Ribbon源码篇。如果在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读[学习微服务-第5天]ServiceComb+Zipkin源码解读[学习微服务-第4天]ServiceComb+Zipkin[学习微服务-第3天] ServiceComb内置高性能网关服务[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul了解更多信息请访问官方网站http://servicecomb.apache.org/ Github代码仓库https://github.com/apache?q=ServiceComb
-
SeviceComb + Zipkin 简介ServiceComb 是Apache的微服务顶级项目,在微服务框架中,微服务之间通过网络进行通信,我们必须处理所有与网络相关的问题,例如延迟,超时和分区。随着部署的微服务越来越多,我们需要系统监控微服务网络延迟和请求流。上篇文章我们介绍了如何使用ServiceComb与Zipkin进行协同定位微服务应用的异常的微服务和具体异常函数。本篇将介绍ServiceComb如何通过自身handler处理链机制支持Zipkin 微服务级别和函数级别的调用链追踪的。▼▼▼ServiceComb 如何支持zipkinServiceComb 提供了处理链机制,消费端和服务端的调用链请求都会经过该处理链,通过扩展handler处理链接口,可以实现负载均衡、熔断容错、流量控制等能力。同样,调用链追踪能力也是通过扩展该接口实现的。关于ServiceComb处理链参考 ↓↓↓https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/intruduction.htmlServiceComb 扩展handler处理链接口,编写了handler-tracing-zipkin 模块。Handler-tracing-zipkin 模块在java-chassis/handler处理链下,模块内容如下。handler-tracing-zipkin模块实现追踪调用链记录数据和上传追踪数据到zipkin服务,即可支持Zipkin。如果读者对于使用ServiceComb对于Zipkin支持的能力还不熟悉,可参考ServiceComb官网相关文档↓↓↓1.http://servicecomb.apache.org/docs/tracing-with-servicecomb/ 2.https://servicecomb.apache.org/cn/docs/customized-tracing-with-servicecomb/ handler-tracing-zipkin模块源码解读每一次接口调用请求都会触发handler链的处理,而在这个handler链当中,ServiceComb专门为Zipkin编写了handler类ZipkinConsumerTracingHandler和ZipkinProviderTracingHandle进行适配。下面我们来看下这两个类。ZipkinConsumerTracingHandler 和ZipkinProviderTracingHandler查看这两个类源码可知,都继承自ZipkinTracingHandler,都只有两个构造器。区别在于分别向父类构造器传递了不同的ZipkinTracingDelegate实现。ZipkinTracingDelegate实现分别为ZipkinConsumerDelegate和ZipkinProviderDelegate。这两个代理类分别封装了对应的Zipkin请求消费和请求生产操作。下面重点看下ZipkinTracingHandler的源码实现。ZipkinTracingHandlerhandler类最重要的方法是handler方法,该方法接收一个Invocation对象和AsyncResponse对象(全是ServiceComb内置对象)。Invocation对象包含当前调用相关信息(包括HttpServletRequest对象)。下面我们看下这个方法做了什么事情。handler方法执行步骤:一调用了tracingDelegate.createSpan(invocation)方法创建了一个span。tracingDelegate是一个ZipkinTracingDelegate对象。二调用当前对象的onResponse方法封装成一个AsyncResponse对象。该对象是是一个函数式对象,在如下图的函数体中可看到最终调用了tracingDelegate.onResponse(span, response, error)上传span到Zipkin服务器。三调用invocation.next()方法将生成的AsyncResponse对象传递给下一个handler处理。四如果在以上操作中发生异常,将调用tracingDelegate.onResponse(span, null, e)方法发送带有异常信息的span到Zipkin服务器。从以上分析我们可以看到tracingDelegate十分重要,下面我们接着看这个ZipkinTracingDelegate接口到底做了什么。ZipkinTracingDelegate接口如下图,该接口定义了4个方法。1.tracer() ,获取对应的追踪器2.createSpan(), 根据Invocation对象携带的信息创建对应的span3.onResponse(),将span对象和对应的响应信息和异常信息上传到Zipkin服务器4.name() , 区分消费操作和生产操作该接口有两个实现类ZipkinConsumerDelegate和ZipkinProviderDelegate,分别对应请求消费操作和请求生产操作。下面我们可以看到两个实现的区别。ZipkinConsumerDelegate和ZipkinProviderDelegate下面我们先上两张图片仔细对比一下,第一张是ZipkinConsumerDelegate类,第二张是ZipkinProviderDelegate类。我们会发现它们都是用handler变量来进行相应的操作,注意这里的handler变量在两个类分别是不一样的类型,ZipkinConsumerDelegate的handler变量是HttpClientHandler对象,而ZipkinProviderDelegate的hanler变量是HttpServerHandler对象。HttpClientHandler和HttpServerHandler类都是final修饰的类,不可继承。前面我们看到创建span和发送span都是由这两个类来负责,那么我们来看下这两个对象怎么生成的。仔细观察可发现↓↓↓ZipkinConsumerDelegate构造器部分代码:this.handler = HttpClientHandler.create(httpTracing, new ConsumerInvocatio**pter());ZipkinProviderDelegate构造器部分代码 : this.handler = HttpServerHandler.create(httpTracing, new ProviderInvocatio**pter());从上面两段构造器代码中可发现HttpClientHandler和HttpServerHandler在创建对象时都分别传入ConsumerInvocatio**pter对象和ProviderInvocatio**pter对象,这两个对象分别继承了Zipkin的HttpClientAdapter和HttpServerAdapter抽象类,提供了属于ServiceComb本身的客户端信息和服务端信息。而Zipkin可以在不改动代码的情况下获取到这些定制信息并用于调用链追踪。至此,ServiceComb如何一步一步去实现zipkin分布式调用链追踪,已经解读完毕。链接参考1.zipkin https://zipkin.io/2.Distributed Tracing with ServiceComb and Zipkin http://servicecomb.apache.org/docs/tracing-with-servicecomb/3.处理链参考https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/intruduction.html4.java-chassiss使用手册——调用参考https://docs.servicecomb.io/java-chassis/zh_CN/文末小结本文向社区读者从源码角度阐述了ServiceComb是如何支持Zipkin的。我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb+SpringCloud Ribbon使用篇。如果在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷
-
分布式调用链追踪能有效地监控服务间的网络延时并可视化微服务中的数据流转。ServiceComb扩展了zipkin的接口提供了服务内部的链路调用信息,能提供更完整的调用链路信息,更容易定位问题和潜在性能问题。本文将介绍ServiceComb 提供的分布式调用链追踪能力及使用指导。一. 异常场景示例我们将使用ServiceComb的入门案例BMI(体质指数应用),展示ServiceComb的调用链追踪和自定义调用链追踪能力。BMI应用程序包含体质指数计算calculator和服务网关webapp两个服务。参见ServiceComb的入门案例BMI指导http://servicecomb.apache.org/cn/docs/quick-start/我们给BMI的体质计算服务增加了异常代码,如下。参见BMI程序使用指导1http://servicecomb.apache.org/cn/docs/quick-start/,运行bmi程序,出现如下异常结果。二. 使用Zipkin定位服务级别异常以上的BMI示例还未开启调用链追踪,下面我们将使用ServiceComb提供的分布式调用链追踪能力定位分析BMI应用的哪个服务发生了异常。首先需要给BMI程序配置zipkin调用链追踪能力,只需添加两个配置即可。可参考分布式追踪2和Distributed Tracing with ServiceComb and Zipkin3。1.添加依赖在 calculator微服务的pom.xml文件中添加依赖项:在 webapp微服务的pom.xml文件中添加依赖项:2 .配置跟踪处理程序在 calculator微服务的microservice.yaml文件中添加分布式追踪的处理链:到此已配置完毕,您只需执行以下几步即可运行↓↓↓使用Docker运行Zipkin分布式追踪服务:重启 calculator 微服务:重启 webapp 微服务:打开浏览器访问 http://localhost:9411 ,查看调用链追踪情况,结果如下。可以看到gateway服务在1.7S时就返回给了用户失败结果,而calculator服务却运行了5S的时间,但calculator为蓝色(并非内部错误),可以确定calculator 服务超时导致gateway超时异常。我们通过在后台服务打印程序调用栈日志可以看到,异常是由于socket读取超时,可以印证我们在Zipkin中看到的结果。三、使用自定义追踪功能定位到函数级别以上已确定导致超时返回的是calculator服务,在服务应用代码较大时,会较难找到具体出现异常的地点,ServiceComb支持可以在服务内部进行函数级别的调用链打点追踪,这将可以帮助我们解决这个问题。配置BMI程序的自定义追踪功能,只需三步即可。↓↓↓参考java-chassis使用手册—自定义调用链打点4https://docs.servicecomb.io/java-chassis/zh_CN/general-development/customized-tracing.html在体质指数计算器的pom.xml文件中添加依赖项:在程序入口或者配置处添加 @EnableZipkinTracing 注解在服务程序中的调用方法处添加 @Span 注解至此,自定义函数级别打点配置完成。运行程序,从Zipkin界面如下:可以看到,调用链中新增加了calculate函数这个Span(上图红圈处),耗时5S。点开该Span,可以查看该函数的详细信息,我们可以根据该信息准确查找到对应的源码进行修正。总结本例子为了最简化读者理解,使用了仅有两个微服务的BMI用例,在实际的生产环境中,微服务数量繁多将导致问题的定位变得复杂,调用链追踪和自定义追踪能力,可以帮助我们高效地解决这个问题。五、参考链接1.ServiceComb的入门案例BMI指导 http://servicecomb.apache.org/cn/docs/quick-start/2.分布式追踪 http://servicecomb.apache.org/docs/quick-start-advance/distributed-tracing/3.Distributed Tracing with ServiceComb and Zipkinhttps://servicecomb.apache.org/docs/tracing-with-servicecomb/4.java-chassis使用手册——自定义调用链打点 https://docs.servicecomb.io/java-chassis/zh_CN/general-development/customized-tracing.html文末小结本文向社区读者从使用角度阐述了ServiceComb是如何支持Zipkin的。我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb+Zipkin源码解读篇。如果在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读:[学习微服务-第3天] ServiceComb内置高性能网关服务[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul------------------------------------------------了解更多信息请访问: 官方网站 http://servicecomb.apache.org/ Github代码仓库https://github.com/apache?q=ServiceComb
-
Edge Service是ServiceComb提供的JAVA网关服务。Edge Service作为整个微服务系统对外的接口,向最终用户提供服务,接入RESTful请求,转发给内部微服务。Edge Service以开发框架的形式提供,开发者可以非常简单的搭建一个Edge Service服务,通过简单的配置就可以定义路由转发规则。同时Edge Service支持强大的扩展能力,服务映射、请求解析、加密解密、鉴权等逻辑都可以通过扩展实现。Edge Service本身也是一个微服务,需遵守所有微服务开发的规则。其本身可以部署为多实例,前端使用负载均衡装置进行负载分发;也可以部署为主备,直接接入用户请求。开发者可以根据Edge Service承载的逻辑和业务访问量、组网情况来规划。开发微服务网关搭建框架使用ServiceComb的内置Edge Service边缘服务3步完成搭建微服务网关↓↓↓•配置依赖关系在项目中加入edge-core的依赖,就可以启动Edge Service的功能。Edge Service在请求转发的时候,会经过处理链,因此还可以加入相关的处理链的模块的依赖,下面的实例增加的负载均衡的处理链,这个是必须的。•定义启动类和开发普通微服务一样,可以通过加载Spring的方式将服务拉起来。•增加配置文件microservie.yamlEdge Service本身也是一个微服务,遵循微服务查找的规则,自己也会进行注册。注意APPLICAIONT_ID与需要转发的微服务相同。在下面的配置中,指定了Edge Service监听的地址,处理链等信息。其中auth处理链是DEMO项目中自定义的处理链,用于实现认证。同时auth服务本身,不经过这个处理链,相当于不鉴权。定制路由规则使用Edge Service的核心工作是配置路由规则。场景不同,规则也不同。 路由规则由一系列AbstractEdgeDispatcher组成。Edge Service提供了几个常见的Dispatcher,通过配置即可启用,如果这些Dispatcher不满足业务场景需要,还可以自定义。•使用DefaultEdgeDispatcherDefaultEdgeDispatcher是一个非常简单、容易管理的Dispatcher,使用这个Dispatcher,用户不用动态管理转发规则,应用于实际的业务场景非常方便,这个也是推荐的一种管理机制。它包含如下几个配置项:常见的这些配置项的示例及含义如下:•[prefix=rest;withVersion=true;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。•[prefix=rest;withVersion=true;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。•[prefix=rest;withVersion=true;prefixSegmentCount=3]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。•[prefix=rest;withVersion=false;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求可能转发到任意微服务实例。•[prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,,请求可能转发到任意微服务实例。•[prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/abc,,请求可能转发到任意微服务实例。withVersion配置项提供了客户端灰度规则,可以让客户端指定访问的服务端版本。Edge Service还包含根据接口兼容性自动路由的功能,请求会转发到包含了该接口的实例。假设某微服务,兼容规划为所有高版本必须兼容低版本,部署了以下版本实例:1.0.0,提供了operation11.1.0,提供了operation1、operation2Edge Service在转发operation1时,会自动使用1.0.0+的规则来过滤实例Edge Service在转发operation2时,会自动使用1.1.0+的规则来过滤实例以上过程用户不必做任何干预,全自动完成,以避免将新版本的operation转发到旧版本的实例中去。•使用URLMappedEdgeDispatcherURLMappedEdgeDispatcher允许用户配置URL和微服务的映射关系。使用它可以非常灵活的定义哪些URL转发到哪些微服务。它包含如下几个配置项:businessV1配置项表示的含义是将请求路径为/usr/business/v1/.的请求,转发到business这个微服务,并且只转发到版本号为1.0.0-2.0.0的实例(不含2.0.0)。转发的时候URL为/business/v1/.。path使用的是JDK的正则表达式,可以查看Pattern类的说明。prefixSegmentCount表示前缀的URL Segment数量,前缀不包含在转发的URL路径中。有三种形式的versionRule可以指定。2.0.0-3.0.0表示版本范围,含2.0.0,但不含3.0.0;2.0.0+表示大于2.0.0的版本,含2.0.0;2.0.0表示只转发到2.0.0版本。2,2.0等价于2.0.0。从上面的配置可以看出,URLMappedEdgeDispatcher也支持客户端灰度。当然配置项会比DefaultEdgeDispatcher多。URLMappedEdgeDispatcher支持通过配置中心动态的修改配置,调整路由规则。•自定义Dispatcher自定义Dispatcher包含两个步骤:1.实现AbstractEdgeDispatcher2.通过SPI发布:增加文件META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,并写入实现类详细的代码细节可以参考下面的章节"DEMO功能说明"。开发者也可以参考DefaultEdgeDispatcher等代码来定义自己的Dispatcher。•进行认证鉴权和其他业务处理通过Edge Servie工作流程可以看出,可以通过多种方式来扩展Edge Service的功能,包括Dispatcher、HttpServerFilter、Handler、HttpClientFilter等。比较常用和简单的是通过Handler来扩展。DEMO里面展示了如何通过Handler扩展来实现鉴权。详细的代码细节可以参考下面的章节"DEMO功能说明"。工作原理工作流程Edge Service的工作流程如下蓝色背景部分在Eventloop线程中执行,黄色背景部分:•如果工作于reactive模式,则直接在Eventloop线程执行•如果工作于线程池模式,则在线程池的线程中执行工作模式reactive (默认)Edge Service默认工作于高性能的reactive模式,此模式要求工作于Edge Service转发流程中的业务代码不能有任何的阻塞操作,包括不限于:•远程同步调用,比如同步查询数据库、同步调用微服务,或是同步查询远程缓存等等•任何的sleep调用•任何的wait调用•超大的循环Edge Service的底层是基于netty的vertx,以上约束即是netty的reactive模式约束。线程池如果业务模型无法满足reactive要求,则需要使用线程池模式。此时需要在Edge Service的microservice.yaml中配置:这里的servicecomb.executor.groupThreadPool是ServiceComb内置的默认线程池对应的spring bean的beanId;业务可以定制自己的线程池,并声明为一个bean,其beanId也可以配置到这里。DEMO功能说明请参考github上的edge service demo:https://github.com/ServiceComb/ServiceComb-Java-Chassis/tree/master/demo/demo-edge该demo包含以下工程:authentication:微服务:鉴权服务器edge-servicehiboard-business-1.0.0微服务:business,1.0.0版本,operation addhiboard-business-1.1.0微服务:business,1.1.0版本,operation add/dechiboard-business-2.0.0微服务:business,2.0.0版本,operation add/dechiboard-consumer作为一个普通的httpclient,而不是servicecomb consumerhiboard-model非微服务,仅仅是一些公共的model通过edge-service访问微服务business的不同版本,并确认是由正确的实例处理的。1.注册Dispatcher实现接口org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,或从org.apache.servicecomb.edge.core.AbstractEdgeDispatcher继承,实现自己的dispatcher功能。实现类通过java标准的SPI机制注册到系统中去。Dispatcher需要实现2个方法:•getOrderDispatcher需要向vertx注入路由规则,路由规则之间是有优先级顺序关系的。系统中所有的Dispatcher按照getOrder的返回值按从小到大的方式排序,按顺序初始化。如果2个Dispatcher的getOrder返回值相同,则2者的顺序不可预知。•initinit方法入参为vertx框架中的io.vertx.ext.web.Router,需要通过该对象实现路由规则的定制。可以指定满足要求的url,是否需要处理cookie、是否需要处理body、使用哪个自定义方法处理收到的请求等等更多路由规则细节请参考vertx官方文档:vertx路由机制https://vertx.io/docs/vertx-web/java/#_routing_by_exact_path提示:多个Dispatcher可以设置路由规则,覆盖到相同的url。假设Dispatcher A和B都可以处理同一个url,并且A优先级更高,则:•如果A处理完,既没应答,也没有调用RoutingContext.next(),则属于bug,本次请求挂死了•如果A处理完,然后调用了RoutingContext.next(),则会将请求转移给B处理2.转发请求注册路由时,指定了使用哪个方法来处理请求(下面使用onRequest来指代该方法),在onRequest中实现转发逻辑。方法原型为:系统封装了org.apache.servicecomb.edge.core.EdgeInvocation来实现转发功能,至少需要准备以下参数:•microserviceName,业务自行制定规则,可以在url传入,或是根据url查找等等•context,即onRequest的入参•path,转发目标的url•httpServerFilters,Dispatcher父类已经初始化好的成员变量edgeInvoke调用内部,会作为ServiceComb标准consumer去转发调用。作为标准consumer,意味着ServiceComb所有标准的治理能力在这里都是生效的。3.设置兼容规则不同的业务可能有不同的兼容规划,servicecomb默认的兼容规则,要求所有新版本兼容旧版本。如果满足这个要求,则不必做任何特殊的设置。还有一种典型的规划:1.0.0-2.0.0内部兼容,url为/microserviceName/v1/….的形式2.0.0-3.0.0内部兼容,url为/microserviceName/v2/….的形式……各大版本之间不兼容此时,开发人员需要针对EdgeInvocation设置兼容规则:versionMapper的作用是将v1或是v2这样的串,转为1.0.0-2.0.0或2.0.0-3.0.0这样的兼容规则。注意:接口不兼容会导致非常多的问题。java chassis要求高版本服务兼容低版本服务,只允许增加接口不允许删除接口。在增加接口后,必须增加微服务的版本号。在开发阶段,接口变更频繁,开发者往往忘记这个规则。当这个约束被打破的时候,需要清理服务中心微服务的信息,并重启微服务和Edge Service(以及依赖于该微服务的其他服务)。否则可能出现请求转发失败等情况。4.鉴权Edge Service是系统的边界,对于很多请求需要执行鉴权逻辑。基于标准的ServiceComb机制,可以通过handler来实现这个功能。最简单的示意代码如下:Auth表示是鉴权微服务提供的接口,Invoker.createProxy("auth", "auth", Auth.class)是透明RPC开发模式中consumer的底层api,与@ReferenceRpc是等效,只不过不需要依赖spring bean机制。Auth接口完全由业务定义,这里只是一个示例。Handler开发完成后,配置到edge service的microservice.yaml中:这个例子,表示转发请求给所有的微服务都必须经过鉴权,但是调用鉴权微服务时不需要鉴权。文末小结本文向社区读者从使用角度阐述了使用Edge Service做边缘服务。我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb+Zipkin使用篇。如果在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读:[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul
-
上一篇文章我们介绍了ServiceComb与SpringCloud的Zuul网关组件协同工作,以构建微服务应用。为了给ServiceComb做贡献的伙伴提供指引,本篇将介绍ServiceComb与SpringCloud Zuul的集成源码。ServiceComb 对接 Spring Cloud Zuul 思路ServiceComb没有修改SpringCloud Zuul的源代码,而是利用了 SpringCloud 提供的可扩展的接口。Spring Cloud Zuul官网有如下两段描述▼▼▼•Zuul starter不包括服务发现客户端, 所以为了实现基于service ID的路由转发,你必须同时在类路径下提供一个服务发现客户端 ( 可以使用 Eureka )•DiscoveryClientRouteLocator 过滤器从一个DiscoveryClient(例如Eureka)和属性文件中加载了路由定义信息。详情参考:https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html从以上的描述看,SpringCloud Zuul允许我们自定义服务发现客户端来实现自己的服务发现逻辑。其中DiscoveryClient接口是Spring Cloud Commons提供的与服务治理相关的抽象接口,Spring Cloud Commons做了一层抽象,很好的解耦了服务治理体系,使得我们可以轻易的替换不同的服务治理设施。在我们的上篇文章[每天5分钟学习微服务-网关]ServiceComb+SpringCloud Zuul中实现的zuulserver项目中,pom文件中有如下依赖↓↓↓以上就是一个自定义discovery client。这个discovery client是专门与ServiceComb的服务与发现注册中心ServiceCenter进行交互的。如下图所示,客户端和各个微服务都与Zuul网关直接通信,而Zuul网关通过ServiceComb Discovery与ServiceCenter获取服务的实例信息(真实IP地址和端口等)ServiceComb Discovery源码分析目录结构源码从github上下载↓↓↓https://github.com/apache/servicecomb-java-chassis/tree/master/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery 很明显这是一个自定义的SpringBoot的starter项目。关于SpringBoot自定义starter可以参考: Creating your own starter(https://docs.spring.io/spring-boot/docs/1.5.12.RELEASE/reference/htmlsingle/#boot-features-custom-starter)springboot的starter项目一般是做自动配置(auto-configure)。那么以下按照starter项目的思路来分析。1. 自动配置入口org.apache.servicecomb.springboot.starter.discovery包下面的ScbDiscoveryClientConfiguration类中和ScbRibbonConfiguration类中找到了AutoConfigureBefore和AutoConfigureAfter注解AutoConfigureBefore:类级别的注解,在指定类初始化配置之前自动执行当前配置类AutoConfigureAfter:类级别的注解,在指定类初始化配置之后自动执行当前配置类tips:查看spring.factories文件是否有org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置或者包下面的类是否有@AutoConfigureBefore,@AutoConfigureAfter注解2. ScbDiscoveryClientConfiguration类这是一个Spring自动配置类,在这个类里只实例化了DiscoveryClient对象这个配置类只实例化了一个DiscoveryClient对象。重点来了,这个DiscoveryClient对象就是给Zuul使用的!!! 最终会被Zuul的 DiscoveryClientRouteLocator 过滤器 用来加载路由定义信息。3. ScbRibbonConfiguration类这是个Spring自动配置类,这个类是为了导入配置类RibbonAutoConfiguration.class代码如上,没有任何实现,注意看注解@RibbonClients ,指定了ScbRibbonClientConfiguration类来配置RibbonClient。下面看这个类。4. ScbRibbonClientConfiguration类这个类是Spring配置类,实例化了Ribbon相关的BeanServerList是Ribbon框架的东西(Ribbon是客户端负载均衡框架)。ServerList是获取服务列表的接口ServiceCombServerList类继承于抽象类AbstractServerList,而AbstractServerList实现了ServerList接口接着看下ServiceCombServerList做了什么事情。5. ServiceCombServerList 类这个类是给Ribbon使用,负责获取服务实例信息(真实IP地址和端口等)。重点在下面这个方法,这个方法使用DiscoveryTree对象真正获取服务实例。最终返回的是可用微服务实例的真实ip地址和端口。DiscoveryTree是ServiceComb的service-registry包的,这个包是负责服务注册的。DiscoveryTree的逻辑比较复杂,可以通过下面的处理流程了解其处理过程。参考官方文档 ↓↓↓https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.html感兴趣的同学可以研究下ServiceComb的service-registry包的实现,这里不展开分析。DiscoveryTree最终会调用到ServiceRegistryClientImpl.findServiceInstances方法▼▼▼ServiceRegistryClientImpl.findServiceInstances在这个方法内直接调用ServiceCenter的rest接口Const.REGISTRY_API.MICROSERVICE_INSTANCES来获取相应的微服务实例信息(http://127.0.0.1:30100/v4/default/registry/instances)文/末/小/结本文向社区读者从源码角度阐述了ServiceComb是如何支持SpringCloud Zuul的。单纯使用的用户实际上不必关心这些细节:)当然,我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb内置的EdgeService网关能力。如果在阅读ServiceComb对Zuul相关支持代码时有任何疑问想交流,欢迎扫码加入进微信群。
-
Hello DevClouder!春节过后,新一年的工作旅程要全新出发啦!金猪年里,各位开发者们也要 好好学习,新年向上哦!新年新气象,我们21天专题活动也要华丽再出发,为大家带来更热门的技术,更专业的课程以及更贴心的服务!21天转型微服务实战营2月26日开启全网招募!这次助手酱努力邀请来三位微服务大神进行直播授课10余位华为云产品、技术骨干同事每日进群答疑课程编排强调实战!实用!在华为云真实环境中实操演练!你,准备好了吗?!课程表仅供参考,课程安排可能会略有调整 21天转型微服务实战营 课程表WEEK1WEEK2WEEK3DAY1微服务架构知识介绍CSE实战之负载均衡基于应用模板快速创建微服务工程DAY2微服务入门之编写HelloWorldCSE实战之服务治理 【直播】ServiceStage实战之微服务应用的容器部署与运维 【直播】DAY3感知微服务和CSE的交互CSE实战之微服务线程模型和性能统计ServiceStage实战之Web应用的虚机部署与运维DAY4微服务实例的生命周期分析CSE实战之使用CSEGoSDK开发微服务ServiceStage实战之快速创建SpringCloud应用DAY5教你如何配置你的微服务CSE实战之异构技术栈相互调用ServiceStage实战之快速创建移动应用DAY6CSE实战之开发网关 【直播】CSE实战之其他服务何如接入CSEServiceStage应用开发之全流程自助式持续交付DAY7CSE实战之框架扩展机制 【礼包】ServiceStage整体介绍 【礼包】ServiceStage应用开发之使用插件快速部署应用 【礼包】
-
使用 Istio 可以很方便地实现微服务间的访问控制。本文演示了使用 Denier 适配器实现拒绝访问,和 Listchecker 适配器实现黑白名单两种方法。使用场景有时需要对微服务间的相互访问进行控制,比如使满足某些条件(比如版本)的微服务能够(或不能)调用特定的微服务。访问控制属于策略范畴,在 Istio 中由 Mixer 组件实现。Mixer拓扑图,来源官方文档如上图所示,服务的外部请求会被 Envoy 拦截,每个经过 Envoy 的请求都会调用 Mixer,为 Mixer 提供一组描述请求和请求周围环境的属性。Mixer 进行前置条件检查和配额检查,调用相应的 adapter 做处理,并返回相应结果。Envoy分析结果,决定是否执行请求或拒绝请求。从而实现了策略控制。环境准备在 Kubernetes 集群上部署 Istio部署 Bookinfo 示例应用配置 Bookinfo 应用各个微服务的 destinationrule 和 virtualservice。其中 reviews 服务的 destinationrule 和 virtualservice 配置如下:按上图配置后,对于 reviews 服务的请求,来自用户 “kokokobe” 的请求会被路由到v2 版本,其他用户的请求会被路由到 v3 版本。使用 Denier 适配器实现简单的访问控制使用 Istio 对微服务进行访问控制时,可以使用 Mixer 中的任何属性。这是一种简单的访问控制,实现基础是通过 Mixer 选择器拒绝某些条件下的请求。比如,上文所述的 Bookinfo 应用中的 ratings 服务会被多个版本的 reviews 服务访问。下面的示例中我们将会切断来自 v3 版本的 reviews 服务对 ratings 服务的调用。1. 用浏览器打开 Bookinfo 的 productpage(http://$GATEWAY_URL/productpage)如上图所示,如果用 “kokokobe” 的用户登录,能看到每条 review 下面的黑色星星,说明此时 ratings 服务被 v2 版本的 reviews 服务调用。从上面两张图可以看出,如果使用其他用户登录(或未登录),能看到每条 review 下面的红色星星,说明此时 ratings 服务被 v3 版本的 reviews 服务调用。 2. 创建 denier 适配器,拒绝来自 v3 版本的 reviews 服务对 ratings 服务的调用编辑 mixer-rule-deny-label.yaml 内容如下:这也是Mixer的adapter的标准配置格式,一般需要配置三种类型的资源:1. 配置一组 handler。Handler是配置好的 adapter 的实例,adapter 封装了 Mixer 和特定基础设施后端之间的接口。2. 基于 template 配置一组 instance。Instance 定义了如何将 Envoy 提供的请求属性映射到 adapter 的输入。3. 配置一组规则。这些规则描述了何时调用特定的 handler 及 instance。在这里其中定义了一条名为 denyreviewsv3 的规则,一个 denier 类型的 handler,一个checknothing 类型的模板的实例。在 denyreviewsv3 规则中,方框内的条件表达式匹配的条件是:来自 reviews 服务,version 为 v3 ,目标为 ratings 服务的请求。这条规则使用 denier 适配器拒绝来自 v3 版本的 reviews 服务的请求。这个 denier 适配器会拒绝符合上述规则的请求。可以预先指定 denier 适配器的状态码和消息,如方框中所示。然后执行如下命令创建上述规则的 denier 适配器:3. 在浏览器中刷新 productpage 页面如果已经登出或者使用不是 “kokokobe” 的用户身份登录,不再看到红色星星,因为v3版本的 reviews 服务对 ratings 服务的访问已经被拒绝了。相反,如果使用 “kokokobe” 用户登录,仍然能够看到黑色星星。因为该用户使用的是 v2 版本的 reviews 服务,不符合拒绝的条件。通过listchecker适配器实现黑白名单Istio 也支持基于属性的黑名单和白名单。下面的白名单配置和上一节的 denier 配置是等价的,拒绝来自 v3 版本的 reviews 服务的请求。 1. 删除上一节配置的 denier 规则2. 在登出状态下浏览 Bookinfo 的 productpage(http://$GATEWAY_URL/productpage)此时能看到红星图标。在完成下述步骤之后,只有在使用 “kokokobe” 的身份登录之后才能看到星形图标。3. 创建包含 v2 版本白名单的 listchecker 适配器编辑 whitelist-handler.yaml 内容如下:通常会在外部维护黑白名单的列表,然后指定 providerUrl 参数进行异步获取。在这个例子中,我们使用 overrides 字段提供一个静态的黑白名单列表。然后运行如下命令创建 listchecker 适配器:4. 创建一个 listentry 模板的实例Listentry 模板可以用来判别一个字符串是否存在于一个列表中,本例中我们使用它来判别版本标签是否存在于白名单中。编辑 appversion-instance.yaml 内容如下:然后运行如下命令:5. 为 ratings 服务启用 whitelist 检查功能编辑 checkversion-rule.yaml 内容如下:然后运行如下命令:6. 在浏览器中刷新 productpage 页面如果已经登出或者使用不是 “kokokobe” 的用户身份登录,看不到星形图标;如果使用 “kokokobe” 用户登录,仍然能够看到黑色星星。总结通过上述示例,可以发现使用 Istio 实现微服务间的访问控制非常方便。既可以使用denier 适配器实现简单的访问控制,也可以通过listchecker 适配器实现较复杂的黑白名单。相关服务请访问https://support.huaweicloud.com/cce/index.html?cce_helpcenter_2019
-
微服务与SOA区别微服务,从本质意义上看,还是 SOA 架构。但内涵有所不同,微服务并不绑定某种特殊的技术,在一个微服务的系统中,可以有 Java 编写的服务,也可以有 Python编写的服务,他们是靠Restful架构风格统一成一个系统的。所以微服务本身与具体技术实现无关,扩展性强。微服务本质微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。微服务的目的是有效的拆分应用,实现敏捷开发和部署 。微服务提倡的理念团队间应该是 inter-operate, not integrate 。inter-operate是定义好系统的边界和接口,在一个团队内全栈,让团队自治,原因就是因为如果团队按照这样的方式组建,将沟通的成本维持在系统内部,每个子系统就会更加内聚,彼此的依赖耦合能变弱,跨系统的沟通成本也就能降低。 什么样的项目适合微服务 微服务可以按照业务功能本身的独立性来划分,如果系统提供的业务是非常底层的,如:操作系统内核、存储系统、网络系统、数据库系统等等,这类系统都偏底层,功能和功能之间有着紧密的配合关系,如果强制拆分为较小的服务单元,会让集成工作量急剧上升,并且这种人为的切割无法带来业务上的真正的隔离,所以无法做到独立部署和运行,也就不适合做成微服务了。能不能做成微服务,取决于四个要素:小:微服务体积小,2 pizza 团队。独:能够独立的部署和运行。轻:使用轻量级的通信机制和架构。松:为服务之间是松耦合的。微服务折分与设计从单体式结构转向微服务架构中会持续碰到服务边界划分的问题:比如,我们有user 服务来提供用户的基础信息,那么用户的头像和图片等是应该单独划分为一个新的service更好还是应该合并到user服务里呢?如果服务的粒度划分的过粗,那就回到了单体式的老路;如果过细,那服务间调用的开销就变得不可忽视了,管理难度也会指数级增加。目前为止还没有一个可以称之为服务边界划分的标准,只能根据不同的业务系统加以调节拆分的大原则是当一块业务不依赖或极少依赖其它服务,有独立的业务语义,为超过2个的其他服务或客户端提供数据,那么它就应该被拆分成一个独立的服务模块。 微服务设计原则单一职责原则意思是每个微服务只需要实现自己的业务逻辑就可以了,比如订单管理模块,它只需要处理订单的业务逻辑就可以了,其它的不必考虑。服务自治原则意思是每个微服务从开发、测试、运维等都是独立的,包括存储的数据库也都是独立的,自己就有一套完整的流程,我们完全可以把它当成一个项目来对待。不必依赖于其它模块。轻量级通信原则首先是通信的语言非常的轻量,第二,该通信方式需要是跨语言、跨平台的,之所以要跨平台、跨语言就是为了让每个微服务都有足够的独立性,可以不受技术的钳制。接口明确原则由于微服务之间可能存在着调用关系,为了尽量避免以后由于某个微服务的接口变化而导致其它微服务都做调整,在设计之初就要考虑到所有情况,让接口尽量做的更通用,更灵活,从而尽量避免其它模块也做调整。
-
什么是微服务 在介绍微服务时,首先得先理解什么是微服务,顾名思义,微服务得从两个方面去理解,什么是"微"、什么是"服务", 微 狭义来讲就是体积小、著名的"2 pizza 团队"很好的诠释了这一解释(2 pizza 团队最早是亚马逊 CEO Bezos提出来的,意思是说单个服务的设计,所有参与人从设计、开发、测试、运维所有人加起来 只需要2个披萨就够了 )。 而所谓服务,一定要区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集。微服务由来 微服务最早由Martin Fowler与James Lewis于2014年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。为什么需要微服务? 在传统的IT行业软件大多都是各种独立系统的堆砌,这些系统的问题总结来说就是扩展性差,可靠性不高,维护成本高。到后面引入了SOA服务化,但是,由于 SOA 早期均使用了总线模式,这种总线模式是与某种技术栈强绑定的,比如:J2EE。这导致很多企业的遗留系统很难对接,切换时间太长,成本太高,新系统稳定性的收敛也需要一些时间。最终 SOA 看起来很美,但却成为了企业级奢侈品,中小公司都望而生畏。 最期的单体架构带来的问题单体架构在规模比较小的情况下工作情况良好,但是随着系统规模的扩大,它暴露出来的问题也越来越多,主要有以下几点:1.复杂性逐渐变高比如有的项目有几十万行代码,各个模块之间区别比较模糊,逻辑比较混乱,代码越多复杂性越高,越难解决遇到的问题。2.技术债务逐渐上升公司的人员流动是再正常不过的事情,有的员工在离职之前,疏于代码质量的自我管束,导致留下来很多坑,由于单体项目代码量庞大的惊人,留下的坑很难被发觉,这就给新来的员工带来很大的烦恼,人员流动越大所留下的坑越多,也就是所谓的技术债务越来越多。3.部署速度逐渐变慢这个就很好理解了,单体架构模块非常多,代码量非常庞大,导致部署项目所花费的时间越来越多,曾经有的项目启动就要一二十分钟,这是多么恐怖的事情啊,启动几次项目一天的时间就过去了,留给开发者开发的时间就非常少了。4.阻碍技术创新比如以前的某个项目使用struts2写的,由于各个模块之间有着千丝万缕的联系,代码量大,逻辑不够清楚,如果现在想用spring mvc来重构这个项目将是非常困难的,付出的成本将非常大,所以更多的时候公司不得不硬着头皮继续使用老的struts架构,这就阻碍了技术的创新。5.无法按需伸缩比如说电影模块是CPU密集型的模块,而订单模块是IO密集型的模块,假如我们要提升订单模块的性能,比如加大内存、增加硬盘,但是由于所有的模块都在一个架构下,因此我们在扩展订单模块的性能时不得不考虑其它模块的因素,因为我们不能因为扩展某个模块的性能而损害其它模块的性能,从而无法按需进行伸缩。
-
【直播课堂】微服务直播系列课合集【直播课堂一】Netty和Vert.x在Apache顶级项目ServiceComb中的应用 直播课程入口:http://zhibo.huaweicloud.com/watch/2578836 【直播议题】1、何为Netty,Vertx,与ServiceComb有何关系?2、ServiceComb支持同步和异步调用,如何实现异步转同步?3、ServiceComb如何实现Reactive机制,与Netty的NIO线程有何关系 vs Netty的Reactor线程模型4、从API接口契约、协议标准化等角度解读ServiceComb同时支持的Highway和私有RPC协议 vs 内部RPC使用HTTPS的进阶之路5、ServiceComb与HTTP/26、ServiceComb实战利器之性能统计,通信队列排队、还是工作线程阻塞,统统帮你搞定 vs 《Netty进阶之路》之性能统计7、Netty本身不支持HTTP连接池,ServiceComb是如何实现连接池【直播课堂二】疑义相与析:听华为大牛分享基于服务的分布式事务解决方案直播课程入口:http://zhibo.huaweicloud.com/watch/2744059 1、传统数据库事务实现原理?2、分布式事务的场景挑战是什么?3、基于补偿的事务实现是怎么样的?4、完美补偿方案和非完美补偿适用的场景是怎么样的?5、ServiceComb分布式事务解决方案是如何实现的?适用场景是怎么样的?6、华为云服务总架构师分享架构师之道【直播课堂三】华为云的微服务治理之道直播课程入口:http://huaweicloud.bugu.mudu.tv/watch/lm60v0m21、多实例部署的优势和需要解决的基本问题2、微服务如何管理服务实例3、提高微服务的可用性的部分策略4、微服务升级不断服的实现策略扫码关注微服务蜂巢关注微服务前沿技术,探索云原生领域热点
-
在前面的文章中,大家都已经熟悉了Istio的故障注入和流量迁移。这两个方面的功能都是Istio流量治理的一部分。今天将继续带大家了解Istio的另一项功能,关于请求超时的管理。首先我们可以通过一个简单的Bookinfo的微服务应用程序来动手实践一下Istio是如何实现请求超时的管理。看过idou老师前面文章的老司机应该都已经对Bookinfo这个实例驾轻就熟了,当然还存在部分被idou老师的文采刚吸引过来的新同学。下面先简单的介绍一下Bookinfo这个样例应用整体架构,以便我们更好地理解Istio是如何实现请求超时,对于老司机可以直接跳过这部分。Bookinfo应用由四个单独的微服务构成,用来演示多种 Istio 特性。这个应用模仿在线书店的一个分类,显示一本书的信息。页面上会显示一本书的描述,书籍的细节,以及关于这本书的一些评论。讲道理,Bookinfo这个实例确实比较轻量级,但是麻雀虽小五脏俱全。了解完样例应用以后,我们就可以动手实践了。当前的实验环境是基于已经提前安装好Kubernetes和Istio。请求超时的管理我们主要可以用来对一些特殊场景进行测试,比如故障注入等。第一步:首先我们到reviews组件中定义一个VirtualService的路由,如下第二步:在对ratings服务的调用中加入四秒钟的延迟,如下第三步:我们需要给productpage配置一个对外访问方式,然后用浏览器打开productpage对应的访问方式即可在页面看到Bookinfo的样例。这时应该能看到 Bookinfo 应用在正常运行(显示了评级的星形符号)。很多同学可能会好奇为什么我们明明设置了四秒钟的延时却没有出现跟自己设想的情况出现,别急让我们再接着往下走。第四步:我们重新再给ratings服务的调用中修改成2秒延时,如下第五步:这个时候我们再重新刷新Bookinfo的应用页面,将会看到出现的情况正如我们预想的那样,页面右侧显示评级的星形符号将会在整个页面异步延时大约2s的时间刷新出来,很多同学可能会思考是不是Istio的延时管理出了bug?莫慌,在本文的最后将会给您揭晓答案。第六步:我们继续尝试在reviews服务的请求加入一秒钟的请求超时,如下第七步:我们继续去刷新Bookinfo的web页面看看即将会发生什么?这时候应该就会看到reviews去调用ratings一秒钟就会返回,而不是之前的两秒钟,但是reviews的显示消失了。通过上面的实践,我们使用Istio为调用reviews的微服务的请求中加入了一秒钟的超时控制,覆盖了本身默认的15秒钟设置。页面刷新时,reviews 服务后面会调用 ratings 服务,使用 Istio 在对 ratings 的调用中注入了两秒钟的延迟,这样就让 reviews 服务要花费超过一秒钟的时间来调用 ratings 服务,从而触发了我们加入的超时控制。这样就会看到 Bookinfo 中由reviews生产的页面上没有出现 reviews 服务的显示内容,并且出现一串异常信息,出现这一信息的原因就是因为来自 reviews 服务的超时错误,如下:到这里,今天的请求超时管理是不是就结束了?当然没有,idou老师还记得第三步中的问题还没有给大家解答。这是因为Istio内部的服务中设置了更为严格的超时要求,如果有同学看了之前的文章测试了故障注入,就会发现 productpage 微服务在调用 reviews 微服务时,还有自己的应用级超时设置(三秒钟)。而我们这里用路由规则设置了一秒钟的超时。如果把超时设置为超过三秒钟(例如四秒钟)会毫无效果(正如我们第三步中设置了四秒)。
-
在微服务架构模式中后端服务的实例数一般是动态的,于客户端而言很难发现动态改变的服务实例的访问地址信息,服务网关能对用户提供统一的入口。 ServiceComb Java-Chassis 内置了网关服务EdgeService,开发者可以非常简单的搭建一个EdgeService服务。具体可参考:https://docs.servicecomb.io/java-chassis/zh_CN/edge/by-servicecomb-sdk.html 本文将介绍ServiceComb与SpringCloud的Zuul网关组件协同工作,以构建微服务应用。ServiceComb在自身的处理链HandlerTrain中已完成Zuul的对接,用户用极简单的方法配置后即可使微服务应用具备网关服务的能力。为使读者更好地理解,本文将编写一个简单的Hello微服务,并启动2个实例来进行演示。Hello微服务提供hello/{name}接口,只需从前端输入参数name就可从后端微服务获取到程序员百看不厌的Hello world结果。微服务模式下的Hello应用模型技术准备ServiceComb 作为后端微服务核心框架ServiceCenter 作为服务发现与注册中心SpringCloud Zuul 组件做服务网关环境准备以下环境为Windows 64位系统●安装git,详情可参考git安装教程https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git●安装JDK 1.8,详情可参考JDK安装教程。https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html●安装Maven 3.x,详情可参考Maven安装教程https://maven.apache.org/install.htmlServiceCenter安装下载地址:http://mirrors.hust.edu.cn/apache/servicecomb/servicecomb-service-center/1.1.0/下载后解压如下▼在该目录下双击service-center.exe即可启动,命令窗口中出现如下信息基本代表ServiceCenter启动成功,从这个信息也可以得知ServiceCenter监听的是30100端口,等下配置文件要用到。问题点:有可能会有如下信息,这个一般是端口被占用,很可能你打开了两个ServiceCenter,都关闭后再打开就可以了。↓↓↓示例一、后端微服务 HelloService01添加依赖新建maven项目HelloService,pom文件如下02配置新建ServiceComb配置文件src/main/resources/microservice.yaml,内容如下▼03项目入口新建启动类HelloApplication.java,内容如下▼新建Controller类HelloController.java (这里我习惯SpringMvc的叫法,重点看注解)04启动到此,Hello微服务就写完了。这里要启动2个实例。1.先打包,执行mvn clean package2.在项目根目录下target目录下将lib目录和生成的jar包复制到另一个目录中 3.复制jar包,修改其中一个jar包微服务启动端口号为8888(通过WinRar解压缩软件打开jar包并打开microservice.yaml文件修改里面的rest端口号) 4.在当前目录打开两个cmd命令窗口,分别执行命令java -jar HelloService-7777.jar和java -jar HelloService-8888.jar 。此时已经启动了2个微服务实例。二、编写Zuul网关服务01 添加依赖新建maven项目 zuulserver,pom文件如下02配置文件新建springboot配置文件src/main/resources/application.yaml,内容如下新建ServiceComb配置文件src/main/resources/microservice.yaml,内容如下03项目入口新建启动类 ZuulApplication.java新建静态文件 src/main/resources/static/index.html,内容如下 (static目录是按springboot项目规范,属于应用静态文件根目录)04启动到此,网关服务器写完,如下在IDEA里面直接启动应用三. 演示效果浏览器访问http://localhost:8080/ ,如下图。 在输入框中输入姓名,就可以在下面看到打招呼的信息连续点击几次打招呼按钮,可以在启动的2个Hello微服务实例的控制台中看到被调用的信息,如下图(由于这里使用的ServiceComb默认的负载均衡策略 轮询,可见到两个实例都均被调用,关于负载均衡,我们将在后续的文章中解读)。此时用户并不需要关心具体哪个实例被调用了,访问的是哪个后端的实例地址,它只要访问网关就可以了:)总结从以上的示例可以看出,通过 ServiceComb 结合SpringCloud Zuul 实现服务网关功能只需一些简单的配置。后续可以在网关服务上实现统一的鉴权,日志记录,和自定义过滤器等。参考[1] SpringCloud Zuulhttps://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html [2] ServiceCombhttp://servicecomb.apache.org/cn/docs/quick-start/
-
Q:用Postman测试接口可以调通过,swagger-ui页面测试我的接口经常出现connect: connection timed out.A:确认下frontend跟你的应用网络是否通,servicecomb的swagger-ui现在是proxy模式,不是直连Q:准备使用servercomb,下载了center和demo项目,demo项目一直提示ERROR 9868 --- [ntloop-thread-0] o.a.s.s.client.http.RestUtils ......message: Connection timed out求指点A:1.httpaddr/httpport of your service center conf2.service registry address in your microservice.yamlQ:restschema与rpcschema两种方式在性能上有区别吗?A:@RestSchema 注解用于 SpringMVC 和 JAX-RS 两种服务开发风格,而 @RpcSchema 注解用于透明RPC开发风格,这两种注解的差异主要体现在服务端代码开发风格和契约生成模式上。Java-Chassis有一个隐式契约功能,可以让框架根据服务端接口代码自动生成服务契约。由于 SpringMVC 和 JAX-RS 开发风格会在REST接口上打上各种注解,有利于框架生成更符合REST风格的契约;而透明RPC模式由于接口上没有注解,Java-Chassis框架无法确定接口语义以及各个参数在HTTP请求中的位置,因此所有的接口都会作为 POST 接口处理,请求参数都会包装到HTTP请求的body中。这样的契约不太符合REST风格。因此,Java-Chassis更推荐用户使用 @RestSchema 注解开发服务端接口,这样用户只需要写代码,就能让框架自动生成符合REST风格的服务契约。Java-Chassis的传输模型和编程模型是解耦合的。传输模型方面,Java-Chassis支持REST和highway,其中REST又分为以Vert.x作为底层通信框架的REST over Vertx和以Tomcat之类的servlet容器为底层通信框架的REST over Servlet。Java-Chassis的性能主要受传输模型的影响。当用户选择了一个确定的传输模型后,无论他在服务端选择的是哪种编程模型性能都是差不多的。最后,Java-Chassis在客户端代码开发风格上提供了RPC开发模式和RestTemplate开发模式,在其他条件完全相同的情况下,RPC开发模式的性能比RestTemplate高,因此更推荐使用RPC模式编写consumer端代码。http://zhibo.huaweicloud.com/?referVisitorId=oiOYo0XLXIVOMO-ACc9q2cKXGOFQ&c=activity&a=live&id=151108&from=timeline&isappinstalled=0这里视频有说明性能比较数据Q:Caused by: java.lang.IllegalStateException: The schema(id=[calculatorRestEndpoint]) content held by this instance and the service center is different. You need to increment microservice version before deploying. Or you can configure service_description.environment=development to work in development environment and ignore this error 在bmi例子上做修改,报上面这个错,怎么解决啊?A:这通常是因为你修改了REST接口定义,但是既没有升级微服务版本号,也没有把环境配置成开发环境,所以ServiceComb启动实例检查契约的时候发现契约内容不一致,就报错了。可以考虑升级一下微服务版本号,或者在microservice.yaml文件里面配置一下service_description.environment=development,或者等sc里面的服务实例下线后,把微服务信息删掉重新注册。Q:有谁知道吗?除了注解方式@RequestHeader,还有什么方法可以在Controller中拿到request中的header参数?目前测试发现HttpServletRequest没法拿到A:如果这个Header参数定义在了你的接口契约里,那你的REST接口方法能直接拿到header参数。否则可以扩展一个HttpServerFilter从requestEx参数里面拿header,也可以在你的REST接口里面加上HttpServletRequest参数,从里面拿到headerQ:如何将一个服务部署多个,实现自动减压的?是在配置文件上设置,还是使用其他工具实现。给个链接谢谢。A:https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.htmlQ:The Service pv-web's instance 62d30daeed5011e8af2f00e081ba3ef7 has been isolated for a while, give a single test opportunity. org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter.allowVisit(IsolationDiscoveryFilter.java:119)?A:你贴出来的日志表示pv-web服务的某个实例被隔离了,现在已经经过了一段时间,Java-Chassis框架在尝试将一个请求路由到该实例,看看它能否被调通,如果调通了的话,这个实例就会从隔离状态恢复过来。https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.html 请参考这篇文档的“实例隔离功能”。Q:启动ServiceComb-java-chassis项目 sample/codefirst-sample 目录里的 CodeFirstProviderMain,例子程序怎么启动不起来?Caused by: java.lang.NoSuchMethodError: org.apache.commons.lang3.reflect.MethodUtils.getMethodsWithAnnotation(Ljava/lang/Class;Ljava/lang/Class;ZZ)[Ljava/lang/reflect/Method; at org.apache.servicecomb.foundation.common.event.SimpleEventBus.collectSubscribers(SimpleEventBus.java:41) at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) at org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx.computeIfAbsent(ConcurrentHashMapEx.java:56) at org.apache.servicecomb.foundation.common.event.SimpleEventBus.register(SimpleEventBus.java:51) at org.apache.servicecomb.serviceregistry.task.AbstractTask.<init>(AbstractTask.java:38) at org.apache.servicecomb.serviceregistry.task.AbstractRegisterTask.<init>(AbstractRegisterTask.java:28) at org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.<init>(MicroserviceRegisterTask.java:47) at org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask.<init>(MicroserviceServiceCenterTask.java:28) at org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry.createServiceCenterTask(AbstractServiceRegistry.java:201) at org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry.init(AbstractServiceRegistry.java:106) at org.apache.servicecomb.serviceregistry.registry.RemoteServiceRegistry.init(RemoteServiceRegistry.java:54) at org.apache.servicecomb.serviceregistry.RegistryUtils.init(RegistryUtils.java:66) at org.apache.servicecomb.core.CseApplicationListener.setApplicationContext(CseApplicationListener.java:48) at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:121) at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:97) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1622) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.d**ateBean(AbstractAutowireCapableBeanFactory.java:555) ... 13 moreA:用户本地工程的lang3包没有更新到ServiceComb配套的版本,解决方法:1.在用户本地工程的pom.xml点击鼠标右键,选择执行 maven -> reimport2.在用户本地工程的pom.xml点击鼠标右键,选择执行 maven -> Show effective pom,确认其中的lang3是:<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.6</version> </dependency>Q:ServiceComb配置中心支持“配置更新后自动刷新到服务”,如果服务有多个节点,是如何实现的?想来如果是API调用刷新不能确定刷到每个节点,是否cse client端有消息流和配置中心连接呢?类似于企业总线。如果是消息总线,那么业务服务里,需要配置消息总线的url等信息吗? A:微服务需要配置中心地址。定期pull配置,或者建立websocket链接采用push机制Q:在 ServiceComb-CRM-WorkShop 例子中 边缘服务afterReceiveRequest方法 在调用String userName = template.getForObject("cse://"+USER_SERVICE_NAME + "/validate?token={token}", String.class, token)时候,第一次调用正常后边调用会出现阻塞线程问题,报错:Thread Thread[transport-vert.x-eventloop-thread-4,5,main] has been blocked for 5433 ms, time limit is 2000A:ServiceComb的Edge Service默认工作于高性能的reactive模式,此模式要求工作于Edge Service转发流程中的业务代码不能有任何的阻塞操作。该问题是由于用户业务模型无法满足reactive要求,因此,可以通过修改微服务的配置文件,使用ServiceComb提供的同步线程池模式解决。使用指南可以参考:https://docs.servicecomb.io/java-chassis/zh_CN/edge/by-servicecomb-sdk.htmlQ:spring mvc项目中实现的filter,切换到微服务后,全部不起作用了,是不支持springmvc里边的filter了吗?用户工程同时添加了springboot和provider-springmvc的依赖:<dependency> <groupId>org.apache.servicecomb</groupId> <artifactId>spring-boot-starter-provider</artifactId> </dependency> <!-- springmvc支持 --> <dependency> <groupId>org.apache.servicecomb</groupId> <artifactId>provider-springmvc</artifactId> </dependency>A:问题原因是因为springmvc和ServiceComb REST是两套不同架构,用户将基于springmvc的项目切换到ServiceComb后,还需要基于ServiceComb REST规则对老的filter做微调,ServiceComb提供相关的架构迁移案例,详情可以参考:1.不同框架之间迁移改造可能工作量的评估指南:https://bbs.huaweicloud.com/blogs/ba7b62178cb811e89fc57ca23e93a89f 可以参考下2.在Spring Boot中使用ServiceComb:https://huaweicse.github.io/cse-java-chassis-doc/using-cse-in-spring-boot/using-cse-in-spring-boot.htmlQ:ServiceComb支持thymeleaf吗?A:这个是个web框架,需要在web容器里面运行,其实和servicecomb是两个完全独立的东西了。servicecomb也支持在web容器里面运行,理论上两个都可以放到一起跑,但我们没用过这个框架。 https://docs.servicecomb.io/java-chassis/zh_CN/build-provider/protocol/rest-over-servlet.htmlQ:原来的那些过滤器都失效了,怎么做才可以既保持原有的能力,又可以把需要发布的接口通过@RestSchema申明出去?A:因为是两个不同的运行时,涉及到“框架内部机制”,而不仅仅是“形式”上的东西。 结合功能,一般都有对应的解决方案的。附上一个简单的不同框架之间迁移改造可能工作量的评估指南: https://bbs.huaweicloud.com/blogs/ba7b62178cb811e89fc57ca23e93a89f 可以参考。 Q:群里有人压过 servicecomb 同步restful 和 spring boot的restful的差距吗?A:网上有很多对比分析,我们也有测试过。一般标准的虚拟机4u8g,差不多分别是5万单位和1万单位。servicecomb restful和其它rpc框架,比如grpc,dubbo,tars等在一个差不多的水准,即5万单位。和调优方式,测试方法不同,会有一些偏差。Q:蓝云上安装了mysql,启动alpha的jar包,直接跑saga源码里的saga-servicecomb-demo,能成功体验事务,照着saga源码里的saga-servicecomb-demo写了个一模一样的工程,是springboot接入servicecomb,调用却出了问题,子事务那边报空指针异常,globalTxId,parentTxId都为null, localTxId有值;自己没找出原因,谁了解这块的帮个忙看下吧,代码地址是:https://github.com/weichao666/sagademoA:saga demo的那个问题解决了,如果使用java chassis1.0.0版本,需要引入guava20.0版本,否则启动报错,注解和调用链正确配置的情况下,使用java chassis1.1.0-SNAPSHOT版本是没问题的,java chassis1.0.0版本使用的guava是19.0Q:ServiceComb中的同步 restful 需要特殊配置吗?A:除edge service之外,ServiceComb的restful默认都是同步的,不需要特殊配置。今天的FAQ精选问题总计20个,可以手动收藏一下哦~And小蜜蜂欢迎来我们社区提问笔芯关注我们~
-
调用链原理和场景正如Service Mesh的诞生是为了解决大规模分布式服务访问的治理问题,调用链的出现也是为了对应于大规模的复杂的分布式系统运行中碰到的故障定位定界问题。大量的服务调用、跨进程、跨服务器,可能还会跨多个物理机房。无论是服务自身问题还是网络环境的问题导致调用上链路上出现问题都比较复杂,如何定位就比单进程的一个服务打印一个异常栈来找出某个方法要困难的多。需要有一个类似的调用链路的跟踪,经一次请求的逻辑规矩完整的表达出来,可以观察到每个阶段的调用关系,并能看到每个阶段的耗时和调用详细情况。Dapper, a Large-Scale Distributed Systems Tracing Infrastructure 描述了其中的原理和一般性的机制。模型中包含的术语也很多,理解最主要的两个即可:Trace:一次完整的分布式调用跟踪链路。Span:跨服务的一次调用; 多个Span组合成一次Trace追踪记录。上图是Dapper论文中的经典图示,左表示一个分布式调用关系。前端(A),两个中间层(B和C),以及两个后端(D和E)。用户发起一个请求时,先到达前端,再发送两个服务B和C。B直接应答,C服务调用后端D和E交互之后给A应答,A进而返回最终应答。要使用调用链跟踪,就是给每次调用添加TraceId、SpanId这样的跟踪标识和时间戳。右表示对应Span的管理关系。每个节点是一个Span,表示一个调用。至少包含Span的名、父SpanId和SpanId。节点间的连线下表示Span和父Span的关系。所有的Span属于一个跟踪,共用一个TraceId。从图上可以看到对前端A的调用Span的两个子Span分别是对B和C调用的Span,D和E两个后端服务调用的Span则都是C的子Span。调用链系统有很多实现,用的比较多的如zipkin,还有已经加入CNCF基金会并且的用的越来越多的Jaeger,满足Opentracing语义标准的就有这么多。一个完整的调用链跟踪系统,包括调用链埋点,调用链数据收集,调用链数据存储和处理,调用链数据检索(除了提供检索的APIServer,一般还要包含一个非常酷炫的调用链前端)等若干重要组件。上图是Jaeger的一个完整实现。这里我们仅关注与应用相关的内容,即调用链埋点的部分,看下在Istio中是否能做到”无侵入“的调用链埋点。当然在最后也会看下Istio机制下提供的不同的调用链数据收集方式。Istio标准BookInfo例子简单期间,我们以Istio最经典的Bookinfo为例来说明。Bookinfo模拟在线书店的一个分类,显示一本书的信息。本身是一个异构应用,几个服务分别由不同的语言编写的。各个服务的模拟作用和调用关系是:productpage :productpage 服务会调用 details 和 reviews 两个服务,用来生成页面。details :这个微服务包含了书籍的信息。reviews :这个微服务包含了书籍相关的评论。并调用 ratings 微服务。ratings :ratings 微服务中包含了由书籍评价组成的评级信息。调用链输出在Istio上运行这个典型例子,不用做任何的代码修改,自带的Zipkin上就能看到如下的调用链输出。可以看到展示给我们的调用链和Boookinfo这个场景设计的调用关系一致:productpage 服务会调用 details 和 reviews 两个服务,reviews调用了ratings 微服务。除了显示调用关系外,还显示了每个中间调用的耗时和调用详情。基于这个视图,服务的运维人员比较直观的定界到慢的或者有问题的服务,并钻取当时的调用细节,进而定位到问题。我们就要关注下调用链埋点到底是在哪里做的,怎么做的?在Istio中,所有的治理逻辑的执行体都是和业务容器一起部署的Envoy这个Sidecar,不管是负载均衡、熔断、流量路由还是安全、可观察性的数据生成都是在Envoy上。Sidecar拦截了所有的流入和流出业务程序的流量,根据收到的规则执行执行各种动作。实际使用中一般是基于K8S提供的InitContainer机制,用于在Pod中执行一些初始化任务. InitContainer中执行了一段iptables的脚本。正是通过这些Iptables规则拦截pod中流量,并发送到Envoy上。Envoy拦截到Inbound和Outbound的流量会分别作不同操作,执行上面配置的操作,另外再把请求往下发,对于Outbound就是根据服务发现找到对应的目标服务后端上;对于Inbound流量则直接发到本地的服务实例上。我们今天的重点是看下拦截到流量后Sidecar在调用链埋点怎么做的。 Istio调用链埋点逻辑Envoy的埋点规则和在其他服务调用方和被调用方的对应埋点逻辑没有太大差别。Inbound流量:对于经过Sidecar流入应用程序的流量,如果经过Sidecar时Header中没有任何跟踪相关的信息,则会在创建一个根Span,TraceId就是这个SpanId,然后再将请求传递给业务容器的服务;如果请求中包含Trace相关的信息,则Sidecar从中提取Trace的上下文信息并发给应用程序。Outbound流量:对于经过Sidecar流出的流量,如果经过Sidecar时Header中没有任何跟踪相关的信息,则会创建根Span,并将该跟Span相关上下文信息放在请求头中传递给下一个调用的服务;当存在Trace信息时,Sidecar从Header中提取Span相关信息,并基于这个Span创建子Span,并将新的Span信息加在请求头中传递。特别是Outbound部分的调用链埋点逻辑,通过一段伪代码描述如图:调用链详细解析如图是对前面Zipkin上输出的一个Trace一个透视图,观察下每个调用的细节。可以看到每个阶段四个服务与部署在它旁边上的Sidecar是怎么配合的。在图上只标记了Sidecar生成的Span主要信息。因为Sidecar 处理 Inbound和Outbound的逻辑有所不同,在图上表也分开两个框图分开表达。如productpage,接收外部请求是一个处理,给details发出请求是一个处理,给reviews发出请求是另外一个处理,因此围绕productpage这个app有三个黑色的处理块,其实是一个Sidecar在做事。同时,为了不使的图上箭头太多,最终的Response都没有表达出来,其实图上每个请求的箭头都有一个反方向的Response。在服务发起方的Sidecar会收到Response时,会记录一个CR(client Received)表示收到响应的时间并计算整个Span的持续时间。下面通过解析下具体数据来找出埋点逻辑: 首先从调用入口的Gateway开始,Gateway作为一个独立部署在一个pod中的Envoy进程,当有请求过来时,它会将请求转给入口服务productpage。Gateway这个Envoy在发出请求时里面没有Trace信息,会生成一个根Span:SpanId和TraceId都是f79a31352fe7cae9,因为是第一个调用链上的第一个Span,也就是一般说的根Span,所有ParentId为空,在这个时候会记录CS(Client Send);请求从入口Gateway这个Envoy进入productpage的app业务进程其Inbound流量被productpage Pod内的Envoy拦截,Envoy处理请求头中带着Trace信息,记录SR(Server Received),并将请求发送给productpage业务容器处理,productpage在处理请求的业务方法中在接受调用的参数时,除了接受一般的业务参数外,同时解析请求中的调用链Header信息,并把Header中的Trace信息传递给了调用的Details和Reviews的微服务。从productpage出去的请求到达reviews服务前,其Oubtbound流量又一次通过同Pod的Envoy,Envoy埋点逻辑检查Header中包含了Trace相关信息,在将请求发出前会做客户端的调用链埋点,即以当前Span为parent Span,生成一个子Span:新的SpanId cb4c86fb667f3114,TraceId保持一致9a31352fe7cae9,ParentId就是上个Span的Id: f79a31352fe7cae9。从prodcutepage到review的请求经过productpage的Sidecar走LB后,发给一个review的实例。请求在到达Review业务容器前,同样也被Review的Envoy拦截,Envoy检查从Header中解析出Trace信息存在,则发送Trace信息给reviews。reviews处理请求的服务端代码中同样接收和解析出这些包含Trace的Header信息,发送给下一个Ratings服务。在这里我们只是理了一遍请求从入口Gateway,访问productpage服务,再访问reviews服务的流程。可以看到期间每个访问阶段,对服务的Inbound和Outbound流量都会被Envoy拦截并执行对应的调用链埋点逻辑。图示的Reviews访问Ratings和productpage访问Details逻辑与以上类似,这里不做复述。以上过程也印证了前面我们提出的Envoy的埋点逻辑。可以看到过程中除了Envoy再处理Inbound和Outbound流量时要执行对应的埋点逻辑外。每一步的调用要串起来,应用程序其实做了些事情。就是在将请求发给下一个服务时,需要将调用链相关的信息同样传下去,尽管这些Trace和Span的标识并不是它生成的。这样在出流量的proxy向下一跳服务发起请求前才能判断并生成子Span并和原Span进行关联,进而形成一个完整的调用链。否则,如果在应用容器未处理Header中的Trace,则Sidecar在处理请求时会创建根Span,最终会形成若干个割裂的Span,并不能被关联到一个Trace上,就会出现我们开始提到的问题。不断被问到两个问题来试图说明这个业务代码配合修改来实现调用链逻辑可能不必要:问题一、既然传入的请求上已经带了这些Header信息了,直接往下一直传不就好了吗?Sidecar请求APP的时候带着这些Header,APP请求Sidecar时也带着这些Header不就完了吗?问题二、既然TraceId和SpanId是Sidecar生成的,为什么要再费劲让App收到请求的时候解析下,发出请求时候再带着发出来传回给Sidecar呢?回答问题一,只需理解一点,这里的App业务代码是处理请求不是转发请求,即图上左边的Request to Productpage 到prodcutpage中请求就截止了,要怎么处理完全是productpage的服务接口的内容了,可以是调用本地处理逻辑直接返回,也可以是如示例中的场景构造新的请求调用其他的服务。右边的Request from productpage 完全是服务构造的发出的另外一个请求;回答问题二,需要理解当前Envoy是独立的Listener来处理Inbound和Outbound的请求。Inbound只会处理入的流量并将流量转发到本地的服务实例上。而Outbound就是根据服务发现找到对应的目标服务后端上。除了实在一个进程里外两个之间可以说没有任何关系。 另外如问题一描述,因为到Outbound已经是一个新构造的请求了,使得想维护一个map来记录这些Trace信息这种方案也变得不可行。这样基于一个例子来打开看一个调用链的主要过程就介绍到这里。附加productpage访问reviews的Span详细,删减掉一些数据只保留主要信息大致是这样:Productpage的Proxy上报了个CS,CR, reviews的那个proxy上报了个SS,SR。分别表示Productpage作为client什么时候发出请求,什么时候最终收到请求,reviews的proxy什么时候收到了客户端的请求,什么时候发出了response。另外还包括这次访问的其他信息如Response Code、Response Size等。根据前面的分析我们可以得到结论:埋点逻辑是在Sidecar代理中完成,应用程序不用处理复杂的埋点逻辑,但应用程序需要配合在请求头上传递生成的Trace相关信息。服务代码修改示例前面通过一个典型例子详细解析了Istio的调用链埋点过程中Envoy作为Sidecar和应用程序的配合关系。分析的结论是调用链埋点由Envoy来执行,但是业务程序要有适当修改。下面抽取服务代码来印证下。Python写的 productpage在服务端处理请求时,先从Request中提取接收到的Header。然后再构造请求调用details获取服务接口,并将Header转发出去。首先处理productpage请问的rest方法中从Request中提取Trace相关的Header。然后重新构造一个请求发出去,请求reviews服务接口。可以看到请求中包含收到的Header。reviews服务中Java的Rest代码类似,在服务端接收请求时,除了接收Request中的业务参数外,还要提取Header信息,调用Ratings服务时再传递下去。其他的productpage调用details,reviews调用ratings逻辑类似。当然这里只是个demo,示意下要在那个位置修改代码。实际项目中我们不会这样在每个业务方法上作这样的修改,这样对代码的侵入,甚至说污染太严重。根据语言的特点会尽力把这段逻辑提取成一段通用逻辑。Istio调用链数据收集:by Envoy一个完整的埋点过程,除了inject、extract这种处理Span信息,创建Span外,还要将Span report到一个调用链的服务端,进行存储并支持检索。在Isito中这些都是在Envoy这个Sidecar中处理,业务程序不用关心。在proxy自动注入到业务pod时,会自动刷这个后端地址.即Envoy会连接zipkin的服务端上报调用链数据,这些业务容器完全不用关心。当然这个调 用链收集的后端地址配置成jaeger也是ok的,因为Jaeger在接收数据是兼容zipkin格式的。Istio调用链数据收集:by Mixer除了直接从Envoy上报调用链到zipkin后端外,Istio提供了Mixer这个统一的面板来对接不同的后端来收集遥测数据,当然Trace数据也可以采用同样的方式。即如TraceSpan中描述,创建一个TraceSpan的模板,来描述从mixer的一次访问中提取哪些数据,可以看到Trace相关的几个ID从请求的Header中提取。除了基础数据外,基于Mixer和kubernetes的继承能力,有些对象的元数据,如Pod上的相关信息Mixr可以补充,背后其实是Mixer连了kubeapiserver获取对应的pod资源,从而较之直接从Envoy上收集的原始数据,可以有更多的业务上的扩张,如namespace、cluster等信息APM数据要用到,但是Envoy本身不会生成,通过这种方式就可以从Kubernetes中自动补充完整,非常方便。这也是Istio的核心组件Mixer在可观察性上的一个优秀实践。Istio官方说明更新最近一直在和社区沟通,督促在更显著的位置明确的告诉使用者用Istio作治理并不是所有场景下都不需要修改代码,比如调用链,虽然用户不用业务代码埋点,但还是需要修改些代码。尤其是避免首页“without any change”对大家的误导。得到回应是1.1中社区首页what-is-istio已经修改了这部分说明,不再是1.0中说without any changes in service code,而是改为with few or no code changes in service code。提示大家在使用Isito进行调用链埋点时,应用程序需要进行适当的修改。当然了解了其中原理,做起来也不会太麻烦。改了个程度轻一点的否定词,很少几乎不用修改,还是基本不用改的意思。这也是社区一贯的观点。结合对Istio调用链的原理的分析和一个典型例子中细节字段、流程包括代码的额解析,再加上和社区沟通的观点。得到以下结论:Istio的绝大多数治理能力都是在Sidecar而非应用程序中实现,因此是非侵入的;Istio的调用链埋点逻辑也是在Sidecar代理中完成,对应用程序非侵入,但应用程序需做适当的修改,即配合在请求头上传递生成的Trace相关信息。华为云Istio服务网格公测中在腾讯的场子上只讲干货的技术,尽量少做广告。在这里只是用一页PPT来简单介绍下华为云当前正在公测的Istio服务网格服务。华为云容器引擎CCE的深度集成,一键启用后,即可享受Istio服务网格的全部治理能力;基于应用运行的全景视图配置管理熔断、故障注入、负载均衡等多种智能流量治理功能;内置金丝雀、A/B Testing典型灰度发布流程灰度版本一键部署,流量切换一键生效;配置式基于流量比例、请求内容灰度策略配置,一站式健康、性能、流量监控,实现灰度发布过程量化、智能化、可视化;集成华为云APM,使用调用链、应用拓扑等多种手段对应用运行进行透视、诊断和管理。华为云Istio社区贡献华为作为CNCF 基金会的初创会员、白金会员,CNCF / Kubernetes TOC 成员。在Kubernetes社区贡献国内第一,全球第三,全球贡献3000+ PR,先后贡献了集群联邦、高级调度策略、IPVS负载均衡,容器存储快照等重要项目。随着Istio项目的深入产品化,团队也积极投入到Istio的社区贡献。当前社区贡献国内第一,全球第三。Approver 3席,Member 6席,Contributor 若干。通过Pilot agent转发实现HTTP协议的健康检查: 针对mTLS enabled环境,传统的kubernetes http健康检查不能工作,实现 sidecar转发功能,以及injector的自动注入。Istioctl debug功能增强:针对istioctl缺失查询sidecar中endpoint的能力,增加proxy-config endpoint、proxy-status endpoint命令,提高debug效率。HTTPRetry API增强: 增加HTTPRetry 配置项RetryOn策略,可以通过此控制sidecar重试。MCP 配置实现: Pilot支持mesh configuration, 可以与galley等多个实现了MCP协议的server端交互获取配置。以此解耦后端注册中心。Pilot CPU异常问题解决:1.0.0-snapshot.0 pilot free 状态CPU 利用率超过20%,降低到1%以下。Pilot 服务数据下发优化:缓存service,避免每次push时进行重复的转换。Pilot服务实例查询优化:根据label selector查询endpoints(涵盖95%以上的场景),避免遍历所有namespace的endpoints。Pilot 数据Push性能优化:将原有的串行顺序推送配置,更新为并行push,降低配置下发时延。
推荐直播
-
华为云码道-玩转OpenClaw,在线养虾2026/03/11 周三 19:00-21:00
刘昱,华为云高级工程师/谈心,华为云技术专家/李海仑,上海圭卓智能科技有限公司CEO
OpenClaw 火爆开发者圈,华为云码道最新推出 Skill ——开发者只需输入一句口令,即可部署一个功能完整的「小龙虾」智能体。直播带你玩转华为云码道,玩转OpenClaw
回顾中 -
华为云码道-AI时代应用开发利器2026/03/18 周三 19:00-20:00
童得力,华为云开发者生态运营总监/姚圣伟,华为云HCDE开发者专家
本次直播由华为专家带你实战应用开发,看华为云码道(CodeArts)代码智能体如何在AI时代让你的创意应用快速落地。更有华为云HCDE开发者专家带你用码道玩转JiuwenClaw,让小艺成为你的AI助理。
回顾中 -
Skill 构建 × 智能创作:基于华为云码道的 AI 内容生产提效方案2026/03/25 周三 19:00-20:00
余伟,华为云软件研发工程师/万邵业(万少),华为云HCDE开发者专家
本次直播带来两大实战:华为云码道 Skill-Creator 手把手搭建专属知识库 Skill;如何用码道提效 OpenClaw 小说文本,打造从大纲到成稿的 AI 原创小说全链路。技术干货 + OPC创作思路,一次讲透!
回顾中
热门标签