1 概述
1.1 背景介绍
微服务引擎CSE,是用于微服务应用的云中间件,支持华为云贡献到Apache社区的注册配置中心Servicecomb引擎和开源增强的注册配置中心Nacos引擎。用户可结合其他云服务,快速构建云原生微服务体系,实现微服务应用的快速开发和高可用运维。
1.2 适用对象
- 企业
- 个人开发者
- 高校学生
1.3 案例时间
本案例总时长预计30分钟。
1.4 案例流程
说明: ① 在云主机上搭建CSE本地开发工具; ② 改造E-Commerce-one代码,并启动E-Commerce-one服务,注册到CSE; ③ 改造E-Commerce-two代码,并启动E-Commerce-two服务,注册到CSE; ④ 改造E-Commerce-three代码,并启动E-Commerce-three服务,注册到CSE; ⑤ 改造E-Commerce-consumer代码,并启动E-Commerce-consumer服务,注册到CSE; ⑥ 修改consumer配置切换负载均衡模式。
1.5 资源总览
本案例预计花费总计0元。 |资源名称 |规格| 单价(元)| 时长(h)| |-|-|-|-| |CSE本地开发工具包| ServiceComb引擎2.x,单个微服务数量100,微服务版本数量10000 |0| 0.5| |开发者空间-云主机| 免费版 |0 |0.5|
2 改造项目代码并注册到CSE平台
2.1 下载CSE本地开发工具包并启动服务
参考“云主机CSE环境搭建和服务接入”文档完成本地CSE环境的搭建和启动,在云主机的CodeArts IDE上运行自己的项目,确认项目成功注册到本地CSE。 参考“微服务体验-使用配置中心”文档完成了配置中心相关设置。 为了保证案例数据的准确性,检查CSE平台的配置中心数据是否清空,如果还存在上个案例的变量,需要清除。 
2.2 改造项目代码
由于要实现负载均衡的测试效果,所以需要创建多个微服务,包含三个provider服务和一个consumer服务。 首先修改bootstrap.yml文件,完整的文件内容如下:
1spring: 2 application: 3 name: E-Commerce 4 5 cloud: 6 servicecomb: 7 # 注册发现相关配置 8 discovery: 9 appName: basic-application 10 11 serviceName: ${spring.application.name} 12 13 address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} 14 15 healthCheckInterval: 10 16 17 pollInterval: 15000 18 19 waitTimeForShutDownInMillis: 15000 20 config: 21 22 serverAddr: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} 23 serverType: kie 24 25 kie: 26 customLabel: ${spring.application.name} 27 customLabelValue: ${INSTANCE_TAG:default} 28 29 fileSource: governance.yaml,application.yaml 30 31
然后修改E-Commerce的pom文件,除了按照2.1步骤引入依赖包以外,还要修改 标签中的项目名,从“E-Commerce”改成“E-Commerce-one”。
完整的pom.xml文件内容如下:
1<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>org.springframework.boot</groupId> 6 <artifactId>spring-boot-starter-parent</artifactId> 7 <version>2.6.7</version> 8 <relativePath/> 9 </parent> 10 11 <groupId>org.example</groupId> 12 <artifactId>E-Commerce-one</artifactId> 13 <version>1.0-SNAPSHOT</version> 14 <packaging>jar</packaging> 15 16 <name>E-Commerce-Java</name> 17 <url>http://maven.apache.org</url> 18 19 <properties> 20 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 21 </properties> 22 23 <dependencies> 24 <dependency> 25 <groupId>com.huaweicloud</groupId> 26 <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> 27 <version>1.11.9-2021.0.x</version> 28 <exclusions> 29 <exclusion> 30 <groupId>com.huaweicloud</groupId> 31 <artifactId>spring-cloud-starter-huawei-swagger</artifactId> 32 </exclusion> 33 </exclusions> 34 </dependency> 35 <dependency> 36 <groupId>org.springframework.boot</groupId> 37 <artifactId>spring-boot-starter-web</artifactId> 38 </dependency> 39 <!-- JWT --> 40 <dependency> 41 <groupId>com.auth0</groupId> 42 <artifactId>java-jwt</artifactId> 43 <version>4.4.0</version> 44 </dependency> 45 <!--redis--> 46 <dependency> 47 <groupId>org.springframework.boot</groupId> 48 <artifactId>spring-boot-starter-data-redis</artifactId> 49 </dependency> 50 <!--MyBatis--> 51 <dependency> 52 <groupId>org.mybatis.spring.boot</groupId> 53 <artifactId>mybatis-spring-boot-starter</artifactId> 54 <version>2.2.0</version> 55 </dependency> 56 <dependency> 57 <groupId>mysql</groupId> 58 <artifactId>mysql-connector-java</artifactId> 59 <version>8.0.32</version> 60 </dependency> 61 <!--GaussDB连接驱动--> 62 <!--<dependency> 63 <groupId>com.huawei.opengauss.jdbc</groupId> 64 <artifactId>opengaussjdbc</artifactId> 65 <version>2.0.5</version> 66 <scope>runtime</scope> 67 </dependency>--> 68 <!-- commons-codec依赖 --> 69 <dependency> 70 <groupId>org.apache.commons</groupId> 71 <artifactId>commons-lang3</artifactId> 72 <version>3.3.2</version> 73 </dependency> 74 <dependency> 75 <groupId>commons-codec</groupId> 76 <artifactId>commons-codec</artifactId> 77 <version>1.3</version> 78 </dependency> 79 <dependency> 80 <groupId>javax.validation</groupId> 81 <artifactId>validation-api</artifactId> 82 <version>2.0.1.Final</version> 83 </dependency> 84 <!--Gson 依赖--> 85 <dependency> 86 <groupId>com.google.code.gson</groupId> 87 <artifactId>gson</artifactId> 88 <version>2.8.9</version> 89 </dependency> 90 <!-- lombok --> 91 <dependency> 92 <groupId>org.projectlombok</groupId> 93 <artifactId>lombok</artifactId> 94 </dependency> 95 </dependencies> 96 <build> 97 <plugins> 98 <plugin> 99 <groupId>org.springframework.boot</groupId> 100 <artifactId>spring-boot-maven-plugin</artifactId> 101 <version>2.2.6.RELEASE</version> 102 <configuration> 103 <mainClass>org.example.CommerceApplication</mainClass> 104 </configuration> 105 <executions> 106 <execution> 107 <goals> 108 <goal>repackage</goal> 109 </goals> 110 </execution> 111 </executions> 112 </plugin> 113 </plugins> 114 </build> 115</project> 116
然后找到./src/main/resources目录下的application.yml文件,将服务端口改为8881
在项目代码中找到./src/main/java/org/example/controller目录,打开CommodityController.java文件,将“price”属性的默认值设置为1:
复制三份E-Commerce项目代码,文件夹名称分别命名为E-Commerce-one, E-Commerce-two,E-Commerce-three,E-Commerce-consumer。 按照上面的步骤修改E-Commerce-two和E-Commerce-three,E-Commerce-two的pom文件的项目名改为E-Commerce-two,application.yml文件中端口改为8882,CommodityController文件中price属性默认值改为2;E-Commerce-three的pom文件的项目名改为E-Commerce-three,application.yml文件中端口改为8883,CommodityController文件中price属性默认值改为3。 接下来修改E-Commerce-consumer项目,首先修改pom文件,项目名改为E-Commerce-consumer,application.yml文件中端口改为8090,然后修改同目录下的bootstrap.yml文件:
完整的内容如下:
1spring: 2 application: 3 name: E-Commerce-consumer 4 5 cloud: 6 servicecomb: 7 # 注册发现相关配置 8 discovery: 9 appName: basic-application 10 11 serviceName: ${spring.application.name} 12 13 address: ${PAAS_CSE_SC_ENDPOINT:http://127.0.0.1:30100} 14 15 healthCheckInterval: 10 16 17 pollInterval: 15000 18 19 waitTimeForShutDownInMillis: 15000 20 config: 21 22 serverAddr: ${PAAS_CSE_CC_ENDPOINT:http://127.0.0.1:30110} 23 serverType: kie 24 25 kie: 26 customLabel: ${spring.application.name} 27 customLabelValue: ${INSTANCE_TAG:default} 28 29 fileSource: governance.yaml,application.yaml 30 loadbalance: 31 AllOperation: | 32 rule: RoundRobin 33
修改E-Commerce-consumer项目的WebConfig文件,内容如下:
1package org.example.config; 2 3import org.example.interceptor.LoginInterceptor; 4import org.springframework.beans.factory.annotation.Autowired; 5import org.springframework.context.annotation.Bean; 6import org.springframework.context.annotation.Configuration; 7import org.springframework.web.client.RestTemplate; 8import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 9import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10import org.springframework.cloud.client.loadbalancer.LoadBalanced; 11 12@Configuration 13public class WebConfig implements WebMvcConfigurer { 14 15 @Autowired 16 private LoginInterceptor loginInterceptor; 17 18 @Override 19 public void addInterceptors(InterceptorRegistry registry) { 20 //放行登录接口和注册接口 21 registry.addInterceptor(loginInterceptor) 22 .excludePathPatterns("/api/auth/login","/api/auth/register","/api/commodity/*"); 23 } 24 25 @Bean 26 @LoadBalanced 27 public RestTemplate restTemplate() 28 { 29 return new RestTemplate(); 30 } 31} 32 33
最后修改E-Commerce-consumer项目的CommodityController文件,内容如下:
1package org.example.controller; 2 3import ch.qos.logback.core.util.InvocationGate; 4import org.example.Entity.Commodity; 5import org.example.Entity.Result; 6import org.example.service.CommodityService; 7import org.example.utils.GsonUtil; 8import org.example.utils.JwtUtil; 9import org.springframework.beans.factory.annotation.Autowired; 10import org.springframework.beans.factory.annotation.Value; 11import org.springframework.cloud.context.config.annotation.RefreshScope; 12import org.springframework.validation.annotation.Validated; 13import org.springframework.web.bind.annotation.*; 14import org.springframework.web.client.RestTemplate; 15 16import java.util.List; 17import java.util.Map; 18 19/** 20 * 商品API 21 */ 22@Validated 23@RestController 24@RequestMapping("/api/commodity") 25@RefreshScope 26public class CommodityController { 27 28 @Autowired 29 private CommodityService commodityService; 30 31 @Autowired 32 private RestTemplate restTemplate; 33 34 @Value("${test.price:3}") 35 private float price; 36 37 @GetMapping("/list") 38 public Result<List> list(@RequestBody String paramStr){ 39 Map<String, Object> paramMap = GsonUtil.jsonToMap(paramStr); 40 //1.分页查询商品列表 41 List<Commodity> list = commodityService.list((String) paramMap.get("keyword"), (Integer) paramMap.get("page_number"), (Integer) paramMap.get("page_size")); 42 43 //2.返回结果 44 return Result.success(list); 45 } 46 47 48 public Result<Commodity> info(@PathVariable("id")Integer id){ 49 Commodity commodity = commodityService.findCommodityById(id); 50 float oldprice = commodity.getPrice(); 51 commodity.setPrice(price*oldprice); 52 return Result.success(commodity); 53 } 54 55 @GetMapping("/{id}") 56 public Result getBalance(@PathVariable("id")Integer id) { 57 return restTemplate.getForObject("http://E-Commerce/api/commodity/"+id, Result.class); 58 } 59 60} 61
2.3 启动测试微服务
改造好代码,进入四个项目的主目录,执行如下命令将示例代码打成jar包:
1mvn clean package 2
如果提示找不到mvn命令,就需要先安装maven工具,执行如下命令安装maven:
1sudo apt install -y maven 2
进入目录E-Commerce-one/target/,右键点击空白处,在弹出的菜单中选择“在终端打开”,在打开的命令行执行如下命令启动服务,注意不要关闭命令行窗口。
1java -jar E-Commerce-one-1.0-SNAPSHOT.jar 2
进入目录E-Commerce-two/target/,右键点击空白处,在弹出的菜单中选择“在终端打开”,在打开的命令行执行如下命令启动服务,注意不要关闭命令行窗口。
1java -jar E-Commerce-two-1.0-SNAPSHOT.jar 2
进入目录E-Commerce-three/target/,右键点击空白处,在弹出的菜单中选择“在终端打开”,在打开的命令行执行如下命令启动服务,注意不要关闭命令行窗口。
1java -jar E-Commerce-three-1.0-SNAPSHOT.jar 2
进入目录E-Commerce-consumer /target/,右键点击空白处,在弹出的菜单中选择“在终端打开”,在打开的命令行执行如下命令启动服务,注意不要关闭命令行窗口。
1java -jar E-Commerce-consumer-1.0-SNAPSHOT.jar 2

2.4 测试负载均衡轮询模式
上面步骤执行完成后,四个微服务已经启动,在浏览器输入如下地址调用接口: http://localhost:8090/api/commodity/1
注意商品价格的数据,继续调用接口会获得如下信息: 
price会有规律的从3.5到7,再到10.5循环出现,也就是商品价格的1到3倍,证明接口循环调用E-Commerce-one、E-Commerce-two、E-Commerce-three三个微服务,这种模式就是轮询模式。
2.5 修改配置文件测试随机模式
进入E-Commerce-consumer 项目的/src/main/resources目录,找到配置文件bootstrap.yml,将下图所示的“RoundRobin”修改为“Random”并保存文件。 
关闭2.3步骤中启动E-Commerce-consumer服务的命令行窗口,停止服务,然后回到E-Commerce-consumer项目根目录,右键点击空白处,在弹出的菜单中选择“在终端打开”,在命令行中输入如下命令重新打包E-Commerce-consumer服务jar包:
1mvn clean package 2
打好包后,执行如下命令启动consumer服务,注意不要关闭窗口。
1cd target 2java -jar E-Commerce-consumer-1.0-SNAPSHOT.jar 3
服务启动完成后,在浏览器继续输入如下地址调用接口: http://localhost:8090/api/commodity/1 price会无规律的从3.5到7,再到10.5随机出现,也就是商品价格的1到3倍,证明接口随机调用E-Commerce-one、E-Commerce-two、E-Commerce-three三个微服务,这种模式就是随机模式。
2.6 总结
本案例复制了几份项目代码模拟多个微服务场景,使用consumer服务,通过 RestTemplate 调用几个微服务的接口,通过服务名而不是硬编码的IP地址和端口来调用服务。 负载均衡作用在客户端,是高并发、高可用系统必不可少的关键组件,目标是尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性。
《CSE服务治理实践:负载均衡》 是转载文章,点击查看原文。

