一、 ServiceComb 概述
1.背景介绍
ServiceComb 作为 Apache 开源组织下的一款微服务框架,其前身为华为云的 微服务引擎CSE(Cloud Service Engine) 云服务。 它意味着国内一款微服务框架在华为和 Apache 组织的共同努力下,随着微服务市场的火爆,一定会让越来越多的开发者所喜欢。
2.技术方案
解决方案级,多语言、多通信协议、标准服务契约、事务最终一致性
开源开放,拥抱 SpringBoot、 SpringCloud、 ServiceMesh 等主流生态
低门槛准入,业务侵入度低,架构松耦合
3.官方网站介绍
华为将 ServiceComb 贡献给了 Apache 基金组织后,我们就可以通过 Apache 的官方网站提供的资料来学习 ServiceComb,下面是官网地址:
英文: http://servicecomb.incubator.apache.org/
中文: http://servicecomb.incubator.apache.org/cn/
4. ServiceComb 的开放性设计思想
1.编程模型和通信模型分离,不同的编程模型可以灵活组合不同的通信模型。应用开发者在开发阶
段只关注接口开发,部署阶段灵活切换通信方式;支持 legacy 系统的切换, legacy 系统只需要修改服务发布的配置文件(或者 annotation),而不需要修改代码。现阶段支持 SpringMVC、 JAX-RS 和透明 RPC 三种开发方式。
2.内建 API-first 支持。通过契约规范化微服务开发,实现跨语言的通信,并支持配套的软件工具链
(契约生成代码、代码生成契约等)开发,构建完整的开发生态。
3.定义了常用的微服务运行模型,将微服务从发现到交互过程中的各种容错手段都封装起来。该运
行模型支持自定义和扩展。
5.ServiceComb 与 SpringCloud 的比较
ServiceComb微服务解决方案
二、服务注册中心 CSE 介绍
1.服务注册中心 CSE 介绍
现在我们介绍如何在开发者本地进行消费者/提供者应用的开发调试。开发服务提供者和消费提供者
均需要连接到在远程的服务中心,为了本地微服务的开发和调试:
启动本地服务中心;
服务中心是微服务框架中的重要组件,用于服务元数据以及服务实例元数据的管理和处理注册、发
现。服务中心与微服务提供/消费者的逻辑关系下图所示:
2.启动本地服务中心
1.下 载 [ 服 务 注 册 中 心 可 执 行 文 件 压 缩 包 ]
(http://apache.org/dyn/closer.cgi/incubator/servicecomb/incubator-servicecomb-service-center/1.0.0-m1/ap
ache-servicecomb-incubating-service-center-1.0.0-m1-windows-amd64.tar.gz)
2. 解压缩到当前文件夹
3. 进入解压缩后的目录,然后双击运行start-service-center.bat文件
注意: Window 和 Linux 版本均只支持 64 位系统。 {: .notice–warning}
打开 conf/app.conf 文件后,可以找到 CSE 基本配置如下:服务端配置:
前端配置:
2 .启动本地服务中心后,在服务提供/消费者的 microservice.yaml 文件中配置 ServerCenter 的地址和端口,示例代码:
使用官方提供的脚手架快速开发 ServiceComb
官网地址:http://start.servicecomb.io/ (已经暂停维护了,尴尬了)
github链接:https://github.com/apache/servicecomb-samples
三、 ServiceComb 服务的线程模型与通信协议
ServiceComb 实现了两种网络通道,包括 REST 和 Highway,均支持 TLS 加密传输。其中, REST 网络通道将服务以标准 RESTful 形式发布,调用端兼容直接使用 http client 使用标准 RESTful 形式进行调用。
1.线程模型
我们一起来了解 serviceComb 微服务的完整线程模型, IO 线程和业务线程之间的关系。
servicecComb 微服务的完整线程模型如下图所示:
2.通信协议
通过上面的线程模型的分析,我们发现最终业务线程和服务端线程通信的关键就在于他们的网络连
接和网络通信的过程,所以我们现在一起来学习一下 ServiceComb 中常用的通信协议有哪些?
我们通过下面的图可以看出有三种协议方式:
第一种 : HighWay 方式,这种方式其实就是我们常说的 RPC 方式。
第二种: Vertx REST 方式,这种方式也可以实现 WEB 开发,但我们一起用的少。
第三种: Servlet REST 方式,这种方式是我们现在用的最多的一种方式。
四、开发 RESTFUL 方式微服务入门程序
首先我们以 rest 方式来开发 servicecomb 的入门程序,通过该程序我们能够掌握 servicecomb 微
服务框架的 restful 方式开发基本步骤。
该程序的基本技术架构: springboot+servicecomb
1.服务程序基本结构
工程之间的结构关系,如下图所示:
2.父工程 servicecombrest 坐标引入
在父工程中 servicecombrest 的 pom.xml 文件中添加相关的坐标。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.sinosun.com</groupId>
<artifactId>servicecomb</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>servicecomb-interface</module>
<module>servicecomb-provider</module>
<module>servicecomb-consumer</module>
</modules>
<packaging>pom</packaging>
<url>http://www.example.com</url>
<distributionManagement>
<site>
<id>website</id>
<url>scp://webhost.company.com/www/website</url>
</site>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--1.实现pom文件导入-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>java-chassis-dependencies</artifactId>
<version>1.0.0-m2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
<!--<reporting>
<plugins>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
</plugin>
</plugins>
</reporting>-->
</project>
3.子模块-服务接口 serviceinterface
打开 serviceinterface 子模块,并进入 src/main/java 目录下,创建 RestService 类
具体代码如下所示:
package com.sinosun.service.interfaces;
public interface RestInterface {
String sayRest(String name);
}
4.子模块-服务提供者 serviceprovider
如果需要依赖servicecomb-interface,需要先将该模块达成jar包。然后在pom中依赖
进入子模块 serviceprovider,打开 pom.xml 文件,添加如下坐标:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>servicecomb</artifactId>
<groupId>org.sinosun.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>servicecomb-provider</artifactId>
<dependencies>
<!--hibernate校验规则-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!--rest支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<!--ServiceComb提供的支持-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-boot-starter-provider</artifactId>
</dependency>
<!--Springboot-junit整合进行单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.3</version>
</dependency>
<!--1.先将servicecomb-interface模块通过maven的install插件编译到maven仓库
2.导入包
-->
<dependency>
<groupId>org.sinosun.com</groupId>
<artifactId>servicecomb-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
编写 microservice.yaml 文件,具体配置如下:(名称不能修改)
APPLICATION_ID: start.servicecomb.io
service_description:
name: provider
version: 0.0.1
servicecomb:
handler:
chain:
Provider: {}
rest:
address: 0.0.0.0:9080
service:
registry:
address: http://127.0.0.1:30100
autodiscovery: false
实现类
package com.sinosun.service.impl;
import com.sinosun.service.interfaces.RestInterface;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
// schemaId需要确保唯一
// rest形式发布服务
@RestSchema(schemaId = "hello")
@RequestMapping("/hello")
public class RestServiceImpl implements RestInterface {
private static final String INFO = "ServiceComb-Provide,Hello ->";
@GetMapping("hello")
@Override
public String sayRest(String name) {
return INFO + name;
}
}
启动类
package com.sinosun.service.impl;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
// 向注册中心进行注册
@EnableServiceComb
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5.子模块-服务消费者 serviceconsumer
目录结果
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>servicecomb</artifactId>
<groupId>org.sinosun.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>servicecomb-consumer</artifactId>
<dependencies>
<!--hibernate校验规则-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!--rest支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<!--ServiceComb提供的支持-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-boot-starter-provider</artifactId>
</dependency>
<!--Springboot-junit整合进行单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.sinosun.com</groupId>
<artifactId>servicecomb-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
实现类
package com.sinosun.service.impl;
import com.sinosun.service.interfaces.RestInterface;
import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* 服务消费者
*
*/
@Service
public class RestConsumerImpl implements RestInterface {
private static final String SERVICENAME = "provider";
private final RestTemplate restTemplate = RestTemplateBuilder.create();
@Override
public String sayRest(String name) {
// URL格式: CSE + 微服务名称 + 路径 (CSE是注册中心提供的协议)
String responce = restTemplate.getForObject("cse://" + SERVICENAME + "/hello/hello?name=" + name, String.class);
return responce;
}
}
controller
package com.sinosun.service.controller;
import com.sinosun.service.interfaces.RestInterface;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@RestSchema(schemaId = "test")
@RequestMapping("/")
public class RestConsumerController {
@Autowired
RestInterface restInterface;
@GetMapping("/test")
public String sayRest(String name) {
return restInterface.sayRest(name);
}
}
microservice.yaml
APPLICATION_ID: start.servicecomb.io
service_description:
name: consumer
version: 0.0.1
servicecomb:
handler:
chain:
Provider: {}
rest:
address: 0.0.0.0:9081
service:
registry:
address: http://127.0.0.1:30100
autodiscovery: false
启动类和服务提供者一样
6.服务运行测试
- 打开 CSE 服务注册中心
- 启动微服务的服务提供者
- 启动服务消费者
五、 开发 RPC 方式微服务入门程序
1.服务程序基本结构
2.父工程 service-rpc 坐标引入
在父工程中 service-rpc 的 pom.xml 文件中添加相关的坐标。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sinosun.rpc</groupId>
<artifactId>servicecomb-rpc</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>rpc-provide</module>
<module>rpc-consumer</module>
<module>servicecomb-interface</module>
</modules>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!--限流-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-flowcontrol-qps</artifactId>
</dependency>
<!--熔断包-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-bizkeeper</artifactId>
</dependency>
<!--日志追踪-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-tracing-zipkin</artifactId>
</dependency>
</dependencies>
<!--1.实现pom文件导入-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>java-chassis-dependencies</artifactId>
<version>1.0.0-m2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.子模块-服务接口 service-rpc-interface
打开 service-rpc-interface 子模块,并进入 src/main/java 目录下,创建 RpcService 类
具体代码如下所示:
package com.sinosun.service;
public interface ServiceInterface {
String sayRPC(String name);
}
4.子模块-服务提供者 service-rpc-provider
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>servicecomb-rpc</artifactId>
<groupId>com.sinosun.rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rpc-provide</artifactId>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-boot-starter-provider</artifactId>
</dependency>
<!--rpc通信模型-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>transport-highway</artifactId>
</dependency>
<!--rpc编程模型-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>provider-pojo</artifactId>
</dependency>
<!--引入服务接口-->
<dependency>
<groupId>com.sinosun</groupId>
<artifactId>servicecomb-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sinosun.rpc</groupId>
<artifactId>servicecomb-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
microservice.yaml
APPLICATION_ID: start.servicecomb.io
service_description:
name: rpcproviderservice
version: 0.0.1
properties:
allowCrossApp: true
servicecomb:
handler:
chain:
Provider: {}
highway:
address: 0.0.0.0:9090
service:
registry:
address: http://127.0.0.1:30100
autodiscovery: false
ProviderApplication .java
package com.sinosun.service;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableServiceComb
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
RpcProviderServiceImpl .java
package com.sinosun.service;
import org.apache.servicecomb.provider.pojo.RpcSchema;
@RpcSchema(schemaId = "helloRpc")
public class RpcProviderServiceImpl implements ServiceInterface {
@Override
public String sayRPC(String name) {
return "RpcProviderServiceImpl---->>" + name;
}
}
5.子模块-服务消费者 service-rpc-consumer
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>servicecomb-rpc</artifactId>
<groupId>com.sinosun.rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rpc-consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-boot-starter-provider</artifactId>
</dependency>
<!--web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--rpc通信模型-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>transport-highway</artifactId>
</dependency>
<!--rpc编程模型-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>provider-pojo</artifactId>
</dependency>
<!--引入服务接口-->
<dependency>
<groupId>com.sinosun.rpc</groupId>
<artifactId>servicecomb-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--限流-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-flowcontrol-qps</artifactId>
</dependency>
<!--熔断包-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-bizkeeper</artifactId>
</dependency>
<!--日志追踪-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-tracing-zipkin</artifactId>
</dependency>
</dependencies>
</project>
microservice.yaml
APPLICATION_ID: start.servicecomb.io
service_description:
name: rpcconsumerservice
version: 0.0.1
properties:
allowCrossApp: true
servicecomb:
handler:
chain:
Provider: {}
highway:
address: 0.0.0.0:9091
service:
registry:
address: http://127.0.0.1:30100
autodiscovery: false
application.properties
server.port=8088
ConsumerApplication.java
package com.sinosun.business;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableServiceComb
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
RpcConsumerController.java
package com.sinosun.business;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RpcConsumerController {
@Autowired
private RpcServiceConsumer rpcServiceConsumer;
@RequestMapping("/rpc")
public void rpcInvoke() {
System.out.println( rpcServiceConsumer.sayRPC("ServiceComb RPC Test"));
}
}
RpcServiceConsumer.java
package com.sinosun.business;
import com.sinosun.service.ServiceInterface;
import org.apache.servicecomb.provider.pojo.RpcReference;
import org.springframework.stereotype.Component;
/**
* @author wanglang
* @Copyright: Copyright (c) 兆日科技股份有限公司 2021
* @date 2021/3/2,16:51
*/
@Component
public class RpcServiceConsumer implements ServiceInterface {
//从注册中心找,找哪个应用程序下面的哪个微服务
//microserviceName :代表了哪个应用程序编号:下面的哪个应用名
//schemaId="",它的值来自于服务提供者中用@RpcSchema(schemaId = "helloRpc")
//@RpcReference(microserviceName = "start.servicecomb.io:rpcproviderservice", schemaId = "helloRpc")
@RpcReference(microserviceName = "start.servicecomb.io:rpcproviderservice",schemaId = "helloRpc")
private ServiceInterface serviceInterface;
@Override
public String sayRPC(String name) {
return serviceInterface.sayRPC(name);
}
}
六、 ServiceComb 服务治理方案
为了引入 ServiceComb 的服务治理策略,我们可以加入相关配置。
首先,需要在 pom.xml 文件中加入相关的坐标
<!--限流-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-flowcontrol-qps</artifactId>
</dependency>
<!--熔断包-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-bizkeeper</artifactId>
</dependency>
<!--日志追踪-->
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>handler-tracing-zipkin</artifactId>
</dependency>
其次,需要在 microservice.yaml 配置文件中加入相关的治理策略,如下所示
APPLICATION_ID: start.servicecomb.io
service_description:
name: shicifang-qa
version: 0.0.2
servicecomb:
tracing:
collector:
address: http://127.0.0.1:9411
#熔断
circuitBreaker:
Provider:
shicifang-friend:
requestVolumeThreshold: 1
fallbackpolicy:
provider:
policy: returnnull
#限流
flowcontrol:
Provider:
qps:
limit:
gateway: 1
handler:
chain:
Provider:
default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider
rest:
address: 0.0.0.0:9083
service:
registry:
address: http://127.0.0.1:30100
ServiceComb 提供了基于 Ribbon 的负载均衡方案,用户可以通过配置文件配置负载均衡策略,当前支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略。
1.负载均衡策略
官方配置文档:
https://docs.servicecomb.io/java-chassis/1.x/zh_CN/references-handlers/loadbalance.html
作为 ServiceComb 内置策略,我们测试一下执行效果。
首先,将服务提供者的启动类设置为共享( Share)模式。如下图所示:
其次:修改服务提供者的 Service 类,加入一行输出代码。
运行 SpringBoot 启 动类。之后再次修改 microservice.yaml 文件,将端口号改为 8082 再次运行启动类。
rest:
address: 0.0.0.0:9082
再次:运行服务消费者,观察控制台,我们会发现此时不断访问时,控制台上会更替出现输出信息。
ServiceComb提供了非常强大的负载均衡能力。它的核心包括两部分,第一部分是DiscoveryTree,通过将微服务实例根据接口兼容性、数据中心、实例状态等分组,DiscoveryFilter是其主要组成部分;第二部分是基于Ribbon的负载均衡方案,支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略IRule,以及可以支持Invocation状态的ServerListFilterExt。默认策略为RoundRobin,可通过以下配置进行修改
servicecomb:
loadbalance:
strategy:
name: RoundRobin # Support RoundRobin,Random,WeightedResponse,SessionStickiness
2.限流策略
官方文档:
https://docs.servicecomb.io/java-chassis/1.x/zh_CN/build-provider/configuration/ratelimite-strategy.html
限流是微服务框架基本都可以解决的一个策略,是微服务框架中常见的系统保障措施。 通常来说系
统的吞吐量是可以提前预测的,当请求量超过预期的伐值时可以采取一些限制措施来保障系统的稳
定运行,比如延迟处理、拒绝服务等。
ServiceComb 微服务框架限流主要是基于 zuul 网关来实现限流的。通常需要先配置好 zuul 网关。
本次实验:我们再次添加一个 gate 网关模块。
第一步:添加 pom.xml 文件中的 Zuul 网关依赖:
<!-- zuul proxy 需要的包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>spring-cloud-zuul-zipkin</artifactId>
</dependency>
第二步: 添加 application.yml 文件,配置如下:
server:
port: 9003
zuul:
routes:
shicifang-friend:
serviceId: shicifang-friend
shicifang-qa:
serviceId: shicifang-qa
discoveryServer:
ribbon:
eureka:
enabled: false
servicecomb:
tracing:
enabled: true
第三步:添加 Zuul 网关的启动类
package cn.itcast;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@SpringBootApplication
@EnableServiceComb
@EnableZuulProxy//新增注
public class ZuulSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulSpringBootApplication.class,args);
}
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");// 允许Get的请求方法
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
第四步:在 ServiceComb 的配置文件 mircoservice.yaml 中添加如下配置:
servicecomb:
flowcontrol:
Provider:
qps:
limit:
gateway: 1000
handler:
chain:
Provider:
default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider
WEBUI 测试频繁刷新 10 次观看查询次数查看调用次数, 有部分服务调用没有成功
System.out.println(“微服务 1 调用”);
把 1 修改为 1000, 频繁访问 WEBUI 测试地址。查看调用次数
System.out.println(“微服务 1 调用”); http:状态码 429 太多访问
3. 服务降级
微服务架构中,一个服务可能会调用很多的其他微服务应用,虽然做了多集群部署,但可能还会存在诸如网络原因或者服务提供者自身处理的原因,或多或少都会出现请求失败或者请求延迟问题,若服务提供者长期未对请求做出回应,服务消费者又不断的请求下,可能就会造成服务提供者服务崩溃,进而服务消费者也一起跟着不可用,严重的时候就发生了系统雪崩了。
降级策略就是当服务请求异常时,微服务所采用的异常处理策略。降级策略有三个相关的技术概念:“隔离”、“熔断”、“容错”。ServiceComb的服务降级是通过对hystrix的封装实现的。
3.1 隔离
通常情况下,当一个服务有多个接口,在提供服务时,使用了线程池,多个接口共用这一个线程池,如下图所示。
那么当某个接口处理效率缓慢,当对该接口的请求量上升时,由于该接口处理效率慢,对于该接口的请求就会占用公用的连接池,并且如果长时间没有释放连接,就会造成其他接口没有线程池来处理请求,于是就会出现因为一个接口的问题,导致整个服务的多个接口都不可用。
为了解决这种问题,Hystrix提供了线程池和信号量两种隔离机制
线程池隔离
为每个接口设置单独的线程池,当该接口的线程池被占满时,只是该接口收到影响,而不会对其他接口造成影响。
优点:
1.可以设置coreSize和MaxQueueSize,也就是说,支持排队;
2.可以设置调用超时时间;
3.支持异步调用;
缺点:
1.创建线程池会产生额外的开销,且开销比信号量大;
信号量隔离
设置一个信号量值(计数器),当一个接收到一个请求后,信号量减1;当请求处理完后,信号量加1;当信号量减为0的时候,表示不能再接受请求,则会拒绝处理。
优点:
1.轻量,开销可以忽略不计;
缺点:
1.不支持任务排队,只要信号量减为0,立即就会被拒绝;
2.不支持设置超时,在执行过程中,只能等待调用拿到结果或者抛出异常,操作才会继续;
3.不支持异步调用;
3.2 容错
一种异常处理机制,“容错”依赖于“熔断”。熔断以后,会调用“容错”的方法。
servicecomb:
isolation:
Consumer:
timeout:
enabled: false # 是否启用超时检测
timeoutInMilliseconds: 30000 # 超时时间阈值
maxConcurentReqeusts: 1000 # 最大并发数阈值
circuitBreaker:
Consumer:
enabled: true # 是否启用熔断措施
forceOpen: false # 不管失败多少次,都进行熔断
forceClosed: false # 任何时候都不熔断
sleepWindowInMilliseconds: 15000 # 熔断后,拒绝请求的时间量,每隔一段时间(sleepWindowInMilliseconds,单位是毫秒)允许再次尝试(也就是放行一个请求)确定是否应该关闭断路器。
requestVolumeThreshold: 10 # 滑动窗口内(10s)内最小的请求数量。如果值是10,那么如果在滑动窗口中只接收到9个请求,即使所有9个请求都失败了,也不会熔断
errorThresholdPercentage: 10 # 错误率阈值,表示在一个统计窗口内有10%的请求处理失败,会触发熔断
fallback:
Consumer:
enabled: true # 是否启用出错后的故障处理措施
maxConcurrentRequests: 10 # 并发调用容错处理措施的请求数,超过这个值则不再调用处理措施,直接返回异常
fallbackpolicy:
Consumer:
policy: throwexception # 抛出异常
3.3 熔断机制
CircuitBreaker 就是熔断的意思。
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问
压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调
用。
服务雪崩效应:
服务熔断过程:
microservice.yaml 文件增加如下配置:
circuitBreaker:
Provider:
shicifang-friend:
requestVolumeThreshold: 1
fallbackpolicy:
provider:
policy: returnnull
测试:
后台:
先启动 shicifang-friend,再启动 shgicifang-qa,最后启动 shicifang-gateway-web。
前端:
使用 web 前端访问 test.htm,返回问题列表后,停掉 mysql 数据库,观察 shicifang-friend 控制台日志,当服务抛出异常后,多次调用就不在输出 22222 了。启动数据库数据库,再次点击关注。服务启动成功。