Spring Cloud应用接入华为云微服务CSE
概述
Cloud应用可以方便的接入CSE提供的基础服务。接入CSE服务有如下好处:
开发者可以专注于业务系统的开发,把精力从中间件的可靠性评估、集群部署、运维监控等复杂的事情中解放出来。
实现业务快速交付和敏捷开发。利用PaaS平台,根据业务规模,动态的调整资源使用,降低业务风险。
下图展现了CSE基础服务、PaaS平台服务和第三方服务的关系:
CSE官方支持微服务框架接入和 Cloud微服务框架接入。两个框架接入的步骤基本类似。在本文中,主要介绍 Cloud应用接入CSE的原理,然后通过一个 Cloud应用改造的案例,说明改造步骤。
为了使用CSE基础服务,还需要开发者拥有华为云账号,可以登路华为云免费注册。建议开发者先通过CSE提供的“快速体验微服务能力”了解CSE,在下面的章节中,会省略体验过程中涉及到的一些公共操作,比如如何获取AK/SK认证信息等。
演进路线图
CSE提供了非常丰富的开箱即用的微服务管控能力,这些能力通过CSE的RPC框架集成。如果使用 Cloud,开发者需要组合非常多的三方组件来完成这些功能,下面列举了部分功能:
CSE功能 Cloud实现方式
负载均衡策略
使用组件
实例故障隔离和失败重试
使用/组件
微服务隔离、熔断、容错
使用组件
微服务方法级别隔离、熔断、容错
使用组件,定义复杂的配置规则
流量控制
实现流量控制算法,定义复杂的配置规则
故障注入
实现动态配置,定义故障规则
灰度发布
实现灰度发布算法,定义灰度发布规则
微服务监控,包括调用链等
使用组件
Cloud 自带,没有集中监控能力,或者集成
CSE还提供了非常友好的管理界面,帮助开发者在运行时管理和监控微服务。 Cloud开发者在使用CSE的过程中有非常多灵活的选择,下面是一个可选的技术路线:
Cloud开发者通过修改pom文件,就可以接入CSE提供的公共服务中心和配置中心服务,使用公共服务作为注册发现、动态配置功能,节省了开发、部署、git等 Cloud提供的服务的时间和购买部署公共服务的机器成本。
这个步骤一般在1小时内就可以完成开发和部署测试,提供了快速上云的通道。
这个步骤完成后,业务原有的功能基本不受任何影响(一些严重依赖于服务发现中间件的功能除外)。接入也给用户提供了一个可以直观感受CSE提供的功能的机会,用户可以根据实际的运维感受,作出更加理性的选择是否使用CSE进行下一步的演进。
这个步骤会在 Boot框架中集成CSE的REST框架。通过这个步骤,CSE提供的所有微服务管理功能都可以开箱即用,业务可以专注于逻辑的开发。完成这个步骤,用户需要对CSE的设计原理,与 Boot集成原理和关系有一定初步了解,这样才能够快速解决文档中未提到的一些技术问题。开始之前,建议开发者先进行如下准备工作,以更好的解决开发过程中可能遇到的问题。
完成第一步,并体验CSE阅读CSE的设计原理,了解CSE框架的设计思路和组件组成体验在 Boot中使用CSE,理解在 Boot框架下使用CSE的基本原理。
对于多数后台服务,对外只提供REST接口,不提供WEB页面。这些服务运行于J2EE容器(比如)会额外多出很多性能损耗。CSE提供了轻量级的HTTP服务器来提供REST服务,可以极大的提高性能和减少资源占用。Edge 是CSE提供的和CSE微服务完美配合的网关服务,除了高性能,还支持强大的灰度版本管理能力、异步编程扩展能力和治理能力。
遗留系统快速接入
本章节通过一个实际的案例,说明 Cloud应用如何经过少量的配置修改,快速接入CSE。Demo下载地址:码云Gitee
-提供了3个项目:
修改后的--2-cse具备如下能力和变化:
接入步骤说明
CSE为 Cloud应用提供了非常简单的接入方式,开发者只需要修改依赖关系和少量的配置,就可以启用服务中心和配置中心客户端连接功能,将 Cloud应用作为一个CSE的微服务注册到服务中心和使用动态配置能力。
删除如下依赖,以-为例,修改-/pom.xml,-/pom.xml:
org.springframework.cloud spring-cloud-starter-eureka
删除如下依赖,以-为例,修改父pom.xml:
org.springframework.cloud spring-cloud-starter-eureka-server
增加如下依赖,以-为例,修改父pom.xml:
com.huawei.paas.cse cse-solution-spring-cloud 2.3.20
[可选]-已不再需要,可以删除,以-为例,修改父pom.xml,只保留-和-:
springcloud-provider springcloud-consumer
-的-模块使用的默认对接,需要在-的.yml中增如下配置:
helloprovider:ribbon:NIWSServerListClassName: org.apache.servicecomb.springboot.starter.discovery.ServiceCombServerList
其中:
经过上面步骤,就完成了 Cloud应用接入CSE的全部整改。开发者可以将应用打包为容器镜像,在公有云上进行部署。另外,--2-cse项目已提供和start.sh,可以直接拷贝以便在微服务云应用平台快速构建镜像。
体验改造后的服务
本地调试时,需要参照“补充说明”第2点,在.yml中增加认证信息。
访问服务::7211/hello?name=World
说明:部署在华为云上时,请将:7211替换为实际的访问地址。您可以在应用详情页面中,从“概览”中获取“外部访问地址”。
服务目录
登录华为云,访问微服务引擎,可以在"微服务管理" > "服务目录" 查看到注册成功的两个服务以及实例信息。
动态配置
为了演示,在中增加了如下接口
@Value(value = "${cse.dynamic.property:null}")String value;@RequestMapping(method = RequestMethod.GET)public String dynamicProperty() {String dynamicProperty = DynamicPropertyFactory.getInstance().getStringProperty("cse.dynamic.property", "").get();return "@Value is " + value + "; Api read is " + dynamicProperty;}
并通过微服务引擎的"动态配置"增加配置项,访问:7211/hello/,得到如下結果:
@Value is property; Api read is property
修改配置项的值为其他值,得到
@Value is property; Api read is propertyChanged
@Value注入的值不会动态变化,通过API获取的值会动态变化。 Cloud使用的大量组件,包括, 等都是通过API读取的配置,这些配置项都能够动态读取到。
Cloud还提供了@ies简化配置,但它的工作原理和@Value以及API都不同,只能够读取到.yml配置文件中的配置项,不支持动态配置。
其他功能
该接入步骤完成了上云的第一步,只能使用服务目录和动态配置功能。经过进一步的改造 Cloud应用才能够使用仪表盘、服务治理等功能。
补充说明
不会往程序里面增加依赖关系,但是可以帮助开发者更好的管理依赖关系,对于解决三方软件冲突非常有用。详细原理描述可以参考“使用maven管理复杂依赖关系的技巧"。
com.huawei.paas.cse cse-dependency 2.3.20 pom import
servicecomb:credentials:accessKey: your access keysecretKey: your secret keyakskCustomCipher: default
在上面的步骤中,实际隐含了将服务中心的地址设置为华北区cn-north-1,如果需要使用其他区域的服务中心和配置中心地址,还需要显示的指定地址和区域。
华为云CSE已上线的区域请访问地区和终端节点。此处,以华为云“华东-上海二”区域为例配置如下
servicecomb:service:registry:address: https://cse.cn-east-2.myhuaweicloud.com:443config:client:serverUri: https://cse.cn-east-2.myhuaweicloud.com:443credentials:project: cn-east-2
有些开发者需要通过代理服务器访问华为云,也可以通过设置代理来实现:
servicecomb:proxy:enable: truehost: your proxy serverport: your proxy server portusername: user namepasswd: password for proxy
CSE的配置是分层次的,按照优先级顺序是:
yaml配置文件 < 环境变量 < < 配置中心。
如果开发者不希望将密码信息写入配置文件,也可以通过环境变量或者 的方式设置这些配置信息。比如:
java -Dcse..=$ .jar。
使用CSE作为RPC框架
在上面的章节中,介绍了 Cloud如何使用CSE的服务注册发现、动态配置管理等中间件服务。这些操作的基础是 Web (本质上是一个,即org..web..)。CSE作为一个独立的RPC框架实现,可以非常容易集成到 Cloud中。通过将 Web 替换为CSE,可以给开发者带来如下便利:
本章节仍然基于快速接入的示例,展示改造的步骤,以及改造以后的效果。点击下载地址获取改造后的项目。
集成方式
CSE支持如下几种集成方式,当需要和 Cloud集成的时候,CSE可以作为一个替换org..web..。
改造步骤
通过依赖-boot--,可以引入对于CSE的依赖。为了简单的接入CSE,还引入了cse---。
org.apache.servicecomb spring-boot-starter-transport
com.huawei.paas.cse cse-solution-service-engine
配置启动类和定义REST接口
在启动类里面加入@加载CSE运行时,并通过@n(=.class)关闭 Web 。
然后开发者就可以定义自己的REST接口(对应于 Cloud的)。可以看出和 Cloud 的差异:
其他服务的定义方式和 Cloud保持完全一致。CSE支持客户端以和RPC两种方式访问服务端,也可以通过浏览器使用REST的方式直接访问服务端,所以一个好的开发实践是给每个REST服务都定义一个接口Hello。使用CSE,不需要 Cloud的声明式REST调用(Feign),可以大大简化开发者的工作量。
@RestSchema(schemaId="hello")
@RequestMapping(path = "/hello", produces = MediaType.TEXT_PLAIN)
public class HelloService implements Hello {private static org.slf4j.Logger log = LoggerFactory.getLogger(HelloService.class);@Override@RequestMapping(path = "/sayhi", method = RequestMethod.GET)public String sayHi(@RequestParam(name = "name", required = false) String name) {log.info("Access /hello/sayhi, and name is " + name);return "from provider: Hello " + name;}
}
引入CSE后,不再需要Feign等组件,如下的一些依赖也可以移除。还有标签@t、@等
org.springframework.cloud spring-cloud-starter-feign
定义微服务信息
在.yml中配置基本的微服务信息。
# 应用名称
APPLICATION_ID: spring-cloud-application-cse-rpc
# 微服务名称和版本号,微服务名称使用Spring Cloud的名称
service_description:name: ${spring.application.name}version: 1.0.0
# 服务中心和配置中心的地址
servicecomb:service:registry:address: https://cse.cn-north-1.myhwclouds.cominstance:watch: falseconfig:client:serverUri: https://cse.cn-north-1.myhwclouds.comrefreshMode: 1refresh_interval: 15000
# 对外发布的地址,端口号使用server.portrest:address: 0.0.0.0:${server.port}
# AK/SK认证信息,需要修改为自己的AK/SKcredentials:accessKey: your access keysecretKey: your secret keyakskCustomCipher: default
# 线下开发,关闭监控数据上报monitor:client:enable: false
客户端访问
CSE简化了客户端访问服务端的方式,同时也支持 Cloud使用的方式去访问。
@RpcReference(microserviceName="helloprovider", schemaId="hello")Hello client;client.sayHi(name)
RestTemplate restTemplate = RestTemplateBuilder.create();restTemplate.getForObject("cse://helloprovider/hello/sayHi?name=" + name, String.class);
体验改造后的服务
在构造的过程中,已经体验了开发上的便利:比Feign更好的RPC支持,以及在"快速接入"章节的相关功能。改造后的应用通过::7211/hello?name=3进行访问。然后可以登录CSE,体验更多的治理功能。下面挑选了几个经常使用的功能进行描述。
服务契约
进入微服务引擎,微服务名录查看微服务信息,可以看到包含如下接口定义文件。
swagger: "2.0"
info:version: "1.0.0"title: "swagger definition for io.provider.HelloService"x-java-interface: "cse.gen.spring_cloud_application_cse_rpc.helloprovider.hello.HelloServiceIntf"
basePath: "/hello"
consumes:
- "application/json"
produces:
- "application/json"
paths:/sayhi:get:operationId: "sayHi"parameters:- name: "name"in: "query"required: falsetype: "string"responses:200:description: "response of 200"schema:type: "string"
当需要使用浏览器、等HTTP客户端访问后台接口的时候,契约可以替代接口说明文档。
调用关系
在服务治理界面,通过图形化的方式展现了微服务之间的调用关系。
服务治理
在服务治理页面,对下发一个故障注入,接口调用模拟3秒的时延。
然后访问接口::7211/hello?name=3可以发现这个接口返回时间被延长。
服务监控
将应用部署到华为云以后,微服务会统计和上报自己的监控状态,这样用户就可以通过仪表盘、的性能监控等功能,监控微服务的运行状态、调用链等指标。
注意:本地调试情况下,不会上报监控数据。并且日志可能打印如下错误:
Can not find any instances from service center due to previous errors. service=default/CseMonitoring/latest
如果不期望上报监控数据,可以增加配置项:
servicecomb.monitor.client.enable=false
关闭。
补充说明
除了上述可以直接感受到的功能,切换为CSE RPC后,请求处理流程也发生了变化。调用流程使用了CSE优秀的统一一致的处理流程。
该流程里面的处理链扩展能力和契约能力,是所有治理的基础。
当然,修改后,还会发生其他一些变化,业务代码还会涉及一些修改,这些修改包括REST接口定义的数据类型支持(参考说明),以及 Cloud其他的构建在 Web 之上的能力。修改过程中,也可能会碰到若干jar包冲突或者不兼容的情况。
这些情况都不涉及到业务逻辑代码的修改,本质上只是改变了业务代码发布为服务的表现形式。使用CSE,能够更好的聚焦于业务逻辑开发。
改造过程中的常见问题
是J2EE()协议定义的对象。CSE支持在协议上、HTTP协议以及其他协议上提供REST服务,因此不支持特定技术框架的对象。需要将接口定义修改为平台无关的原型。
以下面接口为例:
@RequestMapping(value = "/auth", method = RequestMethod.POST)public ResultResponse createAuthenticationToken(HttpServletRequest request,@RequestBody JwtAuthenticationRequest authenticationRequest) throws AuthenticationException{String type = authenticationRequest.getType();String appCode = request.getHeader(BaseTypeConstants.HEADER_APP_CODE);String appType = request.getHeader(BaseTypeConstants.HEADER_APP_TYPE);
… …
修改后:
@RequestMapping(value = "/auth", method = RequestMethod.POST)
public ResultResponse createAuthenticationToken(@RequestHeader(name= BaseTypeConstants.HEADER_APP_CODE) String appCode,
@RequestHeader(name= BaseTypeConstants.HEADER_APP_TYPE String appType),@RequestBody JwtAuthenticationRequest authenticationRequest) throws AuthenticationException{String type = authenticationRequest.getType();… …