-
上一篇文章我们介绍了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,降低配置下发时延。
-
微服务运行很长一段时间,日志里面有大量这些信息:[2019-01-11 05:37:31,801/UTC][LoadBalancerStatsTimer][INFO]stats of instance 06b3ec5307b311e9bc86fa163ee9b7d0 removed. org.apache.servicecomb.loadbalance.ServiceCombLoadBalancerStats$2.onRemoval(ServiceCombLoadBalancerStats.java:145)[]打印这个日志的原因是微服务实例在一段时间内(缺省为5分钟)没有被访问,系统将其统计信息自动移除。 日志打印频繁通常由于业务实例很多,实例很久没有被访问。
-
最近刚好在infoq上看到下一代分布式的设计理念,感触颇深,二十年来,整个分布式系统架构的演进,从 C/S 到 B/S,再到分布式系统。今天,微服务,网格,云计算大行其道,虽然二十年前我刚刚上初中!以当前常见的服务架构举例:微服务常见微服务架构,其前端流量入口采用负载。应用层常见是采取一级网络 (通过配置推送的软负载) 或者二级网络 (通过应用网关负载隔离) 模式。阿里是使用前者,百度、新浪使用后者,主要取决于微服务的展现形式 (RPC or Rest-API),差异是是否需要一个专职配置中心。为保证请求无状态地实现迁移,所以使用共享数据节点 (存储各种形式的临时或中间数据) 的形式实现。数据节点往往采用分片的主备模式。而伴随微服务的增长,当前我们的系统作为2.0基于RPC的微服务架构,也衍生出很多问题,例如服务间调用关系由当初的设计自底向上,逐渐变成网状调用依赖。部署上资源限制,效率瓶颈,缺乏总体架构。大量的远程调用。爆炸式增长的碎片化应用。问题定位变得复。另外,远程调用中最大的问题就是性能问题。如何解决以上的问题,同时也是下一代架构目标:流式架构/反应式编程(Reactive Architecture/Programming)作为一种范式在整个业界正在逐步受到认可和落地,是对过往系统的业务需求理解梳理之后对系统技术设计/架构模式的提升总结。 作为JAVA程序员的你应该感到高兴,因为,Java作为一个成熟平台,对于趋势一向有些稳健的接纳和跟进能力,有着令人惊叹的生命活力: 1. Java 7提供了ForkJoinPool,支持了Java 8提供的Stream(Reactive Stream是RP的一个核心组件)。 2. 另外Java 8还提供了Lamda(有效地表达和使用RP需要FP的语言构件和理念)。 3. 有了前面的这些稳健但不失时机的准备,在Java 9中提供了面向RP的Flow API,为Java圈子提供了官方的RP API,标志着RP由集市式的自由探索阶段 向 教堂式的统一使用的转变。 响应式编程就是异步数据流编程 说了这么就,什么是响应式编程(Reactive Programming)?传统的顺序编程采用每条指令依次执行的方式,上一条指令没有执行结束,当前的线程就得等着,任你如何提升机器性能还是代码性能,如果本质不变,始终改变不了响应需要等待的现实。若要响应迅速,就得把顺序执行指令的方式换一换——同步换成异步,方法执行换做消息发送,于是,就有了上边的响应式的定义:响应式编程就是异步数据流编程,这其实是一种编程范式,是编程理念的一种思想转型。因为采用响应式编程,我们就不再将软件要处理的业务视为对象,又或者函数,而是直接透析到本质:数据流(Data Stream)。万事万物皆为流从函数式编程的角度来讲,一连串组合函数的调用,其实就是数据在流动。函数可以抽象地视为一种数据类型到另一种数据类型的转换。将各种形式的转换(map、flatMap、filter)穿起来,同时保证数据的不变性(Immutable),则数据就能非常可靠地在函数链条中流动,或者被分析,或者被转换,或者被过滤。当我们将编程的范式切换为“流(Stream)”时,我们欣喜地发现,这种方式可以在很大程度上确保数据是不变的。这就为并行开发创造了可能。然而,普通的数据流编程范式并不能满足“响应式Reactive”的本初定义。我们需要响应迅速。如何才能做到?那就是要做到没有阻塞,这就是我们通常所说的异步工作方式。因而,响应式编程的设计原则是:保持数据的不变性没有共享阻塞是有害的恰好,这三条特征也是Actor模型拥有的。Actor,这个诞生在1970的产物,遥遥领先于那个时间,知道很久以后,Erlang这种基于Acotr的模型设计的面向并发编程的新语言横空出世,并在并发领域树立一座丰碑,古老的Actor才重见天日,再次成为分布式计算领域的焦点技术之一,目前,几乎所有的主流平台都支持Actor模型:JAVA平台下的Scala的Actor类库jetlan。Actor的理念很简单,Actor是一等公民,一切皆Actor,之间通过消息发送通信,所有都是异步的,不同Actor可以自己处理各自的消息。整个系统获得良好的大规模并发处理能力。在《Scala并发编程》一书中,Aleksandar Prokopec形象地描述了Actor系统:Actor系统模仿了人类的组织,如公司、政府和其他大型机构。在软件公司中,有许多需要以并发方式达成的目标。为了实现这些目标,数百或数千名员工一起努力工作,而且这些员工通常会被组织成一种层次结构。许多员工会为级别比他们低的员工分派工作。为了高效地工作和决策,员工们使用电子邮件进行通信。当员工早上上班时,就会检查他的电子邮箱并对重要的消息做出回应。如果某封电子邮件非常重要,那么这个员工就必须立刻回复这封邮件。当员工忙着回复一封电子邮件时,可能会收到另一封电子邮件,而且后续的电子邮件都会进入他的电子邮箱中。只有当员工处理完成当前的电子邮件后,他才能继续处理下一封电子邮件。软件公司就相当于是一个ActorSystem,每位员工则是一个一个Actor。电子邮件是Actor之间彼此发送的消息(Message),一旦发送了消息,就不必等待收件人的回复,可以继续自己的工作,也就是说这种消息发送的方式是异步非阻塞的。Actor持有的MailBox正好借用了这里所谓的电子邮箱概念。因而对于每个Actor而言:每个Actor都拥有独立的MailBox;接收到的消息皆为不可变对象,且完全独立;不管是tell消息还是ask消息,Actor执行消息的方式都是异步非阻塞的。不得不提的Akka AKKA框架是一个实现Actors模型的Scala或Java平台,实现多线程安全应用。 Actors是一个轻量级的对象,通过发送消息实现交互。每个Actors在同一时间处理最多一个消息,可以发送消息给其他Actors。在同一时间可以于一个Java虚拟机存在数以百万计的参与者,构架是一个分层的父层(管理) - 子层,其中父层监控子层的行为。还可以很容易地扩展Actor运行在集群中各个节点之间 - 无需修改一行代码。每个演员都可以有内部状态(字段/变量) ,但通信只能通过消息传递,不会有共享数据结构(计数器,队列) 。Akka框架支持两种语言Java和Scala,** is cheap,show me the codeAkka actors是轻量,能够平均在一个系统创建数千个。线程是重量的,场景切换相当慢。横向扩展Scale out,Actor能够在代码没有任何修改时在远程运行。失败恢复和错误处理Actor的Java代码就如上面简介中所说的,AKKA把并发操作的各种复杂的东西都统一的做了封装.我们主要关心的是业务逻辑的实现,只需要少量的关心Actor模型的串联即可构建出高可用,高性能,高扩展的应用.我希望在后续的应用的开发中朝着这个方向努力,今天的分享就到这里。最近我对内存相关的内容比较感兴趣,下个blog我会在跟大家分享下关于内存的内容。谢谢! 部分资料来自 infoq & 简书https://www.jianshu.com/p/3bdb8dbaa35c
-
【微服务直播】Netty和Vert.x在Apache顶级项目ServiceComb中的应用 直播时间:11月29日19:30-20:30 【直播介绍】Netty是Java高性能网络编程的明星框架,互联网公司程序员必须掌握的基础组件。Netty将Java NIO接口封装,提供了全异步编程方式,是个大Java项目的网络应用开发必备神器。Vertx,是一个基于JVM、轻量级、高性能的应用平台,非常适用于移动端后台、互联网、企业应用架构。Vert.x框架基于事件和异步,依托于全异步Java服务器Netty,并扩展了很多其他特性,以其轻量、高性能、支持多语言开发而备受开发者青睐。ServiceComb,业界第一个Apache微服务顶级项目, 是一个开源微服务框架,提供了一套包含代码框架生成,服务注册发现,负载均衡,服务可靠性(容错熔断,限流降级,调用链追踪)等功能的微服务框架。华为微服务引擎CSE(Cloud Service Engine)提供ServiceComb商业版。本期直播将为你系统讲解:Netty在Apache顶级微服务项目ServiceComb中的实践!华为软件总工程师指点迷津,让你从一个技术小白成为技术专家!【直播议题】何为Netty,Vertx,与ServiceComb有何关系?ServiceComb支持同步和异步调用,如何实现异步转同步?ServiceComb如何实现Reactive机制,与Netty的NIO线程有何关系 vs Netty的Reactor线程模型从API接口契约、协议标准化等角度解读ServiceComb同时支持的Highway和私有RPC协议 vs 内部RPC使用HTTPS的进阶之路ServiceComb与HTTP/2ServiceComb实战利器之性能统计,通信队列排队、还是工作线程阻塞,统统帮你搞定 vs 《Netty进阶之路》之性能统计Netty本身不支持HTTP连接池,ServiceComb是如何实现连接池【大咖来袭】Netty专家 Mr.李10年Java NIO通信框架、平台中间件架构设计和开发经验,《Netty进阶之路:跟着案例学Netty》《Netty权威指南》、《分布式服务框架原理与实践》作者。目前在华为终端应用市场负责业务微服务化、云化、全球化等相关设计和开发工作。福利环节:观众参与直播提问互动,将有机会获得作者签名版《Netty进阶之路》!华为软件总工程师 Mr.吴华为微服务CSE架构师,Apache全球首个微服务顶级项目ServiceComb社区首席Committer,设计和实现加载框架、通讯协议、服务契约、服务治理等核心能力。直播课程入口:http://zhibo.huaweicloud.com/watch/2578836
-
1 前言前两天有同事发现,通过华为云 ServiceStage 的流水线部署基于模板创建的 CSEJavaSDK demo 服务时,会在容器启动过程中报错。初步排查是由于 JVM 占用的内存超出了 docker 内存配额的上限,导致容器被 kill 掉。于是我们需要排查一下问题出在哪里,为什么以前没有这类问题,而现在却发生了。2 基本定位要确定 docker 容器内存超限问题的直接原因并不难。直接进入docker容器,执行 top 命令,我们发现宿主机是一台8核16G的机器,而且 docker 并不会屏蔽这些信息,也就是 JVM 会认为自己工作于一台 16G 内存的机器上。而查看 demo 服务的 Dockerfile,发现运行服务时并没有对 JVM 的内存进行任何限制,于是 JVM 会根据默认的设置来工作 —— 最大堆内存为物理内存的1/4(这里的描述并不完全准确,因为 JVM 的默认堆内存大小限制比例其实是根据物理内存有所变化的,具体内容请自行搜索资料),而基于模板创建的 ServiceStage 流水线,在部署应用堆栈的时候会把 docker 容器的内存配额默认设置为 512M,于是容器就会在启动的时候内存超限了。至于以前没有碰到过这种问题的原因,只是因为以前没将这么高规格的 ECS 服务器用于流水线部署应用堆栈。在查询过相关资料后,我们找到了两种问题解决方案,一个是直接在 jar 包运行命令里加上 -Xmx 参数来指定最大堆内存,不过这种方式只能将 JVM 堆内存限制为一个固定的值;另一个方法是在执行 jar 包时加上 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 参数,让 JVM 能够感知到docker容器所设置的 cgroup 限制,相应地调整自身的堆内存大小,不过这个特性是 JDK 8u131 以上的版本才具备的。最终,我们提醒 ServiceStage 流水线的同学将 CSEJavaSDK demo 的创建模板做了改进,在 Dockerfile 中将打包的基础镜像版本由原先的 java:8u111-jre-alpine 升级为了 openjdk:8u181-jdk-alpine,并且在运行服务 jar 包的命令中加上了 -Xmx256m参数。问题至此已经解决了。3 进一步的探究虽然问题已经解决,但是在好奇心的驱使下,我还是打算自己找个 demo 实际去触发一下问题,另外看看从网上搜到的解决方法到底好不好用 : )3.1 准备工作3.1.1 创建云上工程首先需要在华为云 ServiceStage 创建一个云上工程。在 ServiceStage -> 应用开发 -> 微服务开发 -> 工程管理 -> 创建云上工程中,选择“基于模板创建”,语言选择 Java, 框架选择 CSE-Java (SpringMVC),部署系统选择“云容器引擎CCE”,给你的云上工程取一个名字,比如test-memo-consuming,最后选择存放代码的仓库,就可以完成云上工程的创建了。之后云上工程会根据你的选项自动地生成脚手架代码,上传到你指定的代码仓库中,并且为你创建一条流水线,完成代码编译、构建、打包、归档镜像包的操作,并且使用打好的 docker 镜像包在 CCE 集群中部署一个应用堆栈。创建云上工程和流水线不是本文的重点,我就不详细讲操作了 : )。同一个应用堆栈的实例可以部署多个,在这里为了实验方便就按照默认值1个来部署。由于云上工程已经改进了脚手架代码的模板,不会再出现内存超限的问题,所以我们现在能看到 demo 服务已经正常的跑起来,微服务实例已经注册到服务中心了。登录到 demo 服务所部署的容器,使用curl命令可以调用 demo 服务的 helloworld 接口,可以看到此时服务已经可以正常工作。3.1.2 增加实验代码为了能够触发微服务实例消耗更多的内存,我在项目代码中增加了如下接口,当调用/allocateMemory接口时,微服务实例会不停申请内存,直到 JVM 抛出 OOM 错误或者容器内存超限被 kill 掉。private HashMap<String, long[]> cacheMap = new HashMap<>(); @GetMapping(value = "/allocateMemory") public String allocateMemory() { LOGGER.info("allocateMemory() is called"); try { for (long i = 0; true; ++i) { cacheMap.put("key" + i, new long[1024 * 1024]); } } catch (Throwable t) { LOGGER.info("allocateMemory() gets error", t); } return "allocated"; }此时用来打镜像包的基础镜像是openjdk:8u181-jdk-alpine,jar 包启动命令中加上了-Xmx256m参数。执行流水线,应用堆栈部署成功后,调用/allocateMemory接口触发微服务实例消耗内存,直到 JVM 抛出 OOM 错误,可以在 ServiceStage -> 应用上线 -> 应用管理中选择相应的应用,点击进入概览页面,查看应用使用内存的情况。应用使用的内存从 800M+ 陡然下降的时间点就是我重新打包部署的时间,而之后由于调用/allocateMemory接口,内存占用量上升到了接近 400M,并且在这个水平稳定了下来,显示-Xmx256m参数发挥了预期的作用。3.2 复现问题现在将 demo 工程中的 Dockerfile 修改一下,将基础镜像改为 java:8u111-jre-alpine,并且删除启动命令中的-Xmx256m参数,将其提交为noLimit_oldBase分支,推送到代码仓库中。然后编辑流水线,将 source 阶段的任务所使用的代码分支改为noLimit_oldBase分支,保存并重新运行流水线,将新的代码打包部署到应用堆栈中。在微服务实例列表中查询到新的微服务实例的 endpoint IP 后,调用`/allocateMemory`接口,观察内存情况,内存从接近 400M 突然掉下去一下,然后又上升到约 450M 的时间点就是修改代码后的微服务实例部署成功的时间点,之后内存占用量突然下跌就是因为调用`/allocateMemory`接口导致容器内存超限被 kill 掉了。如果你事先使用docker logs -f命令查看容器日志的话,那么日志大概是这个样子的2018-11-23 15:40:04,920 INFO SCBEngine:152 - receive MicroserviceInstanceRegisterTask event, check instance Id... 2018-11-23 15:40:04,920 INFO SCBEngine:154 - instance registry succeeds for the first time, will send AFTER_REGISTRY event. 2018-11-23 15:40:04,925 WARN VertxTLSBuilder:116 - keyStore [server.p12] file not exist, please check! 2018-11-23 15:40:04,925 WARN VertxTLSBuilder:136 - trustStore [trust.jks] file not exist, please check! 2018-11-23 15:40:04,928 INFO DataFactory:62 - Monitor data sender started. Configured data providers is {com.huawei.paas.cse.tcc.upload.TransactionMonitorDataProvider,com.huawei.paas.monitor.HealthMonitorDataProvider,} 2018-11-23 15:40:04,929 INFO ServiceCenterTask:51 - read MicroserviceInstanceRegisterTask status is FINISHED 2018-11-23 15:40:04,939 INFO TestmemoconsumingApplication:57 - Started TestmemoconsumingApplication in 34.81 seconds (JVM running for 38.752) 2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:258 - find instances[1] from service center success. service=default/CseMonitoring/latest, old revision=null, new revision=28475010.1 2018-11-23 15:40:14,943 INFO AbstractServiceRegistry:266 - service id=8b09a7085f4011e89f130255ac10470c, instance id=8b160d485f4011e89f130255ac10470c, endpoints=[rest://100.125.0.198:30109?sslEnabled=true] 2018-11-23 15:40:34,937 INFO ServiceCenterTaskMonitor:39 - sc task interval changed from -1 to 30 2018-11-23 15:47:03,823 INFO SPIServiceUtils:76 - Found SPI service javax.ws.rs.core.Response$StatusType, count=0. 2018-11-23 15:47:04,657 INFO TestmemoconsumingImpl:39 - allocateMemory() is called Killed可以看到allocateMemory方法被调用,然后 JVM 还没来得及抛出 OOM 错误,整个容器就被 kill 掉了。这里也给大家提了一个醒:不要以为自己的服务容器能启动起来就万事大吉了,如果没有特定的限制,JVM 会在运行时继续申请堆内存,也有可能造成内存用量超过 docker 容器的配额!3.3 让 JVM 感知cgroup限制前文提到还有另外一种方法解决 JVM 内存超限的问题,这种方法可以让 JVM 自动感知 docker 容器的 cgroup 限制,从而动态的调整堆内存大小,感觉挺不错的。我们也来试一下这种方法,看看效果如何 ; )回到demo项目代码的master分支,将 Dockerfile 中启动命令参数的-Xmx256m替换为-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap,提交为useCGroupMemoryLimitForHeap分支,推送到代码仓库里。再次运行流水线进行构建部署。等 demo 服务部署成功后,再次调用`/allocateMemory`接口,容器的内存占用情况如上图所示(最右边的那一部分连续曲线),内存上升到一定程度后,JVM 抛出了 OOM 错误,没有继续申请堆内存。看来这种方式也是有效果的。不过,仔细观察容器的内存占用情况,可以发现容器所使用的内存仅为不到 300M,而我们对于这个容器的内存配额限制为 512M,也就是还有 200M+ 是闲置的,并不会被 JVM 利用。这个利用率,比起上文中直接设置-Xmx256m的内存利用率要低 : ( 。推测是因为 JVM 并不会感知到自己是部署在一个 docker 容器里的,所以它把当前的环境当成一个物理内存只有 512M 的物理机,按照比例来限制自己的最大堆内存,另一部分就被闲置了。如此看来,如果想要充分利用自己的服务器资源,还是得多花一点功夫,手动调整好-Xmx参数。4 参考资料Java and Docker, the limitationsJava inside docker: What you must know to not FAIL本文转载自Docker容器内部署Java微服务的内存限制问题
-
同一个项目,其他的微服务可以正常注册和启动,就这个注册不了,新人,求解决!!!
推荐直播
-
码道新技能,AI 新生产力——从自动视频生成到开源项目解析2026/04/08 周三 19:00-21:00
童得力-华为云开发者生态运营总监/何文强-无人机企业AI提效负责人
本次华为云码道 Skill 实战活动,聚焦两大 AI 开发场景:通过实战教学,带你打造 AI 编程自动生成视频 Skill,并实现对 GitHub 热门开源项目的智能知识抽取,手把手掌握 Skill 开发全流程,用 AI 提升研发效率与内容生产力。
回顾中 -
华为云码道:零代码股票智能决策平台全功能实战2026/04/18 周六 10:00-12:00
秦拳德-中软国际教育卓越研究院研究员、华为云金牌讲师、云原生技术专家
利用Tushare接口获取实时行情数据,采用Transformer算法进行时序预测与涨跌分析,并集成DeepSeek API提供智能解读。同时,项目深度结合华为云CodeArts(码道)的代码智能体能力,实现代码一键推送至云端代码仓库,建立起高效、可协作的团队开发新范式。开发者可快速上手,从零打造功能完整的个股筛选、智能分析与风险管控产品。
回顾中 -
华为云码道全新升级,多会话并行与多智能体协作2026/05/08 周五 19:00-21:00
王一男-华为云码道产品专家;张嘉冉-华为云码道工程师;胡琦-华为云HCDE;程诗杰-华为云HCDG
华为云码道4月份版本全新升级,此次直播深度解读4月份产品特性,通过“特性解读+实操演示+实战案例+设计创新”的组合,全方位展现码道在多会话并行与多智能体协作方面的能力,赋能开发者提升效率
正在直播
热门标签