华为 ServiceComb框架
一、ServiceComb 概述
1.背景介绍
ServiceComb 作为Apache 开源组织下的一款微服务框架,其前身为华为云的 微服务引擎 CSE (Cloud Service Engine) 云服务。它意味着国内一款微服务框架在华为和Apache 组织的共同努力下, 随着微服务市场的火爆,一定会让越来越多的开发者所喜欢。
2.首要原则
全球首款进入Apache 的开源微服务项目,中立、开放、标准、无商业Lock-in
开源与商业代码同源,具备零成本平滑迁移商用的能力,社区长足发展有保障
3.技术方案
解决方案级,多语言、多通信协议、标准服务契约、事务最终一致性开源开放,拥抱SpringBoot、SpringCloud、ServiceMesh 等主流生态低门槛准入,业务侵入度低,架构松耦合
4.官方网站介绍
华为将 ServiceComb 贡献给了 Apache 基金组织后,我们就可以通过 Apache 的官方网站提供的资料来学习ServiceComb,下面是官网地址:
英文:http://servicecomb.incubator.apache.org/ 中文:http://servicecomb.incubator.apache.org/cn/
二、ServiceComb 与 SpringCloud 的比较
我们可以从语言框架,编程模型,通信协议,服务治理,服务访问,分布式事务等方面进行比较, 得出结果如下:
通过上图的对比,我们可以得出结论就是 ServiceComb 在微服务开发上更胜一筹。我们有理由
相信 ServiceComb 将会在微服务开发领域成为国人的骄傲。
**
三、ServiceComb 的开放性设计思想**
1.编程模型和通信模型分离,不同的编程模型可以灵活组合不同的通信模型。应用开发者在开发阶 段只关注接口开发,部署阶段灵活切换通信方式;支持 legacy 系统的切换,legacy 系统只需要修改服务发布的配置文件(或者annotation),而不需要修改代码。
现阶段支持SpringMVC、JAX-RS 和透明RPC 三种开发方式。
2.内建 API-first 支持。通过契约规范化微服务开发,实现跨语言的通信,并支持配套的软件工具链
(契约生成代码、代码生成契约等)开发,构建完整的开发生态。
3.定义了常用的微服务运行模型,将微服务从发现到交互过程中的各种容错手段都封装起来。该运 行模型支持自定义和扩展。
四、ServiceComb 微服务解决方案**
五、安装 ServiceComb 开发环境
应用开发环境所需安装的工具包括JDK、Maven、Eclipse 和 IDEA 。
六、服务注册中心 CSE 介绍
1.服务注册中心基本介绍
现在我们介绍如何在开发者本地进行消费者/提供者应用的开发调试。开发服务提供者和消费提供者 均需要连接到在远程的服务中心,为了本地微服务的开发和调试:
启动本地服务中心;
服务中心是微服务框架中的重要组件,用于服务元数据以及服务实例元数据的管理和处理注册、发 现。服务中心与微服务提供/消费者的逻辑关系下图所示:
2.启动本地服务中心
- 下 载 [ 服 务 注 册 中 心 可 执 行 文 件 压 缩 包 ] (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}
以Docker 的方式运行
docker pull servicecomb/service-center
docker run -d -p 30100:30100 servicecomb/service-center:latest
下载后的 CSE 服务注册中心,并打开目录结构如下:
打开 conf/app.conf 文件后,可以找到 CSE 基本配置如下: 服务端配置:
# sever options ###################################################################
# if you want to listen at ipv6 address, then set the httpaddr value like: # httpaddr = 2400:A480:AAAA:200::159 (global scope)
# httpaddr = fe80::f816:3eff:fe17:c38b%eth0 (link-local scope) httpaddr = 127.0.0.1
httpport = 30100read_header_timeout = 60s read_timeout = 60s idle_timeout = 60s write_timeout = 60s max_header_bytes = 32768 # 32K max_body_bytes = 2097152 # 2Menable_pprof = 0
前端配置:
# Frontend Configurations ###################################################################
frontend_host_ip = 127.0.0.1
frontend_host_port = 30103
2 .启动本地服务中心后,在服务提供/消费者的 microservice.yaml 文件中配置 ServerCenter 的地址和端口,示例代码:
servicecomb: service: registry: address:
http://127.0.0.1:30100
#服务中心地址及端口
3.开发服务提供/消费者,启动微服务进行本地测试。
通过设置环境信息方便本地调试
通过 microservice.yaml 配置文件来指定
service_description:
environment: development
七、使用官方提供的脚手架快速开发 ServiceComb
为了能够使开发者可以快速构建 ServiceComb 应用程序,它同样也为我们提供了一套脚手架,这样
能够方便学习者及应用开发者快速入门,同时极大的提高了效率。
1.访问快速开发引导页:
http://start.servicecomb.io/
页面如下:
后面我们就可以填写工程相关内容,最后就可以生成代码了。
下载后的工程
解压工程,导入到 Idea 工具中。
八、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.服务程序基本结构
我们所构建的 servicecomb 入门程序的基本结构,如下图所示:
工程之间的结构关系,如下图所示:
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>cn.itcast.servicecomb</groupId><artifactId>servicecomb-rest</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>serviceprovider</module><module>serviceconsumer</module><module>service-inerface</module></modules><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><fastjson.version>1.2.47</fastjson.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.12.RELEASE</version><relativePath/> <!-- lookup parent from repository
<version>1.5.12.RELEASE</version>--></parent><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><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
3.子模块-服务接口 serviceinterface
打开 serviceinterface 子模块,并进入 src/main/java 目录下,创建 RestService 类
具体代码如下所示:
package cn.itcast.service;
public interface RestService {public String restHello(String name);
}
4.子模块-服务提供者 serviceprovider
打开模块后,模块结构图如下所示:
进入子模块 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-rest</artifactId><groupId>cn.itcast.servicecomb</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-provider</artifactId><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties>
<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><dependency><groupId>cn.itcast.servicecomb</groupId><artifactId>service-inerface</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><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
</project>
编写 microservice.yaml 文件,具体配置如下:
APPLICATION_ID: start.servicecomb.io
service_description:name: providerversion: 0.0.1
servicecomb:
circuitBreaker:Provider:provider:requestVolumeThreshold: 8fallbackpolicy:provider:policy: returnnullflowcontrol:Provider:qps:limit:gateway: 100handler:chain:Provider:default: qps-flowcontrol-provider,bizkeeper-provider,tracing-providerrest:address: 0.0.0.0:9080service:registry:address: http://192.168.229.133:30100autodiscovery: false
编写服务端 RestService 接口的实现类 RestProviderServiceImpl,如下所示:
package cn.itcast.service.impl;
import cn.itcast.service.RestService;
import org.apache.servicecomb.provider.rest.common.RestSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 以 rest 形式发布服务
*/
@RestSchema(schemaId = "hello")
@RequestMapping(path = "/hello")
public class RestProviderServiceImpl implements RestService {@Override@GetMapping(path = "/hello")public String restHello(String name){System.out.println(name);return "Hello World!";} }
编写 springboot 的服务启动类,代码如下:
package cn.itcast;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/*
* microservice.yaml 名称不得修改
*/
@SpringBootApplication
@EnableServiceComb
public class RestProviderSpringBootApplication {public static void main(String[] args) {SpringApplication.run(RestProviderSpringBootApplication.class, args);} }
完成后,就可以启动 ServiceComb 的服务提供者程序。
5.子模块-服务消费者 serviceconsumer
进入服务消费方,打开子模块 serviceconsumer 工程,打开它下面的 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-rest</artifactId><groupId>cn.itcast.servicecomb</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-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><dependency><groupId>cn.itcast.servicecomb</groupId><artifactId>service-inerface</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><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
</project>
5.1 服务消费者 serviceconsumer 模块
目录结构如下:
5.2 编写 RestService 接口的实现类
package cn.itcast.service.impl;
import cn.itcast.service.RestService;
import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class RestConsumerServiceImpl implements RestService {private final RestTemplate restTemplate = RestTemplateBuilder.create();public String restHello(String name) {//service url is : cse://serviceName/operation//provider 是 serviceprovider 项目中的 microservice.yaml 里面的 name 微服务名称String serviceName = "provider";String value = restTemplate.getForObject("cse://" + serviceName + "/hello/hello",
String.class);System.out.println(value);return value;} }
5.3 编写 Controller 类
package cn.itcast.controller;
import cn.itcast.service.RestService;
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;
import org.springframework.web.bind.annotation.RestController;
@RestSchema(schemaId="test")
@RequestMapping("/test")
public class RestConsumerController {@Autowiredprivate RestService restService;@GetMapping(path="/test")public String restHello(){return restService.restHello("aa");} }
5.4 编写 Springboot 启动类
package cn.itcast;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableServiceComb
@SpringBootApplication
public class RestConsumerSrpingBootApplication {public static void main(String[] args) {SpringApplication.run(RestConsumerSrpingBootApplication.class, args);} }
6.服务运行测试
- 打开 CSE 服务注册中心
- 启动微服务的服务提供者
- 启动服务消费者
十、开发 RPC 方式微服务入门程序
通过以 REST 方式入门程序的介绍,我们基本理解了 ServiceComb 中服务的发布和消费。那么现在
我们以 RPC 方式同样介绍一下 ServiceComb 的服务发布与消费。它们不一样的就是服务的开发方式,
但最终效果都是一样的
1.服务程序基本结构
我们所构建的 servicecomb 入门程序的基本结构,如下图所示:
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>cn.itcast</groupId><artifactId>servic-rpc</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>service-rpc-provider</module><module>service-rpc-interface</module><module>service-rpc-consumer</module></modules><name>servic-rpc</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent>
</project>
3.子模块-服务接口 service-rpc-interface
打开 service-rpc-interface 子模块,并进入 src/main/java 目录下,创建 RpcService 类
具体代码如下所示:
package cn.itcast.service;
public interface RpcService {public String sayHello(String name);
}
4.子模块-服务提供者 service-rpc-provider
打开模块后,模块结构图如下所示:
进入子模块 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>servic-rpc</artifactId><groupId>cn.itcast</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-rpc-provider</artifactId><name>service-rpc-provider</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.3.5.Final</version></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><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--transport 根据 microservice.yaml 中 endpoint 发布需求选择,本例中两者都引入,也可以二选
一--><dependency><groupId>org.apache.servicecomb</groupId><artifactId>transport-rest-vertx</artifactId></dependency><dependency><groupId>org.apache.servicecomb</groupId><artifactId>transport-highway</artifactId></dependency><dependency><groupId>org.apache.servicecomb</groupId><artifactId>provider-pojo</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency><dependency><groupId>cn.itcast</groupId><artifactId>service-rpc-interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.apache.servicecomb</groupId><artifactId>java-chassis-dependencies</artifactId><version>1.0.0-m1</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>1.5.12.RELEASE</version><executions><execution><goals><goal>repackage</goal></goals><configuration><outputDirectory>target/bin</outputDirectory><classifier>exec</classifier></configuration></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.6</version><configuration><archive><manifestEntries><Class-Path>.</Class-Path></manifestEntries></archive></configuration></plugin></plugins></build>
</project>
编写 microservice.yaml 文件,具体配置如下:
APPLICATION_ID: start.servicecomb.io
service_description:name: serviceprovider-rpcversion: 0.0.1properties:allowCrossApp: true
servicecomb:handler:chain:Provider: {}highway:address: 0.0.0.0:9090service:registry:address: http://127.0.0.1:30100autodiscovery: false
编写服务端 RpcService 接口的实现类 RpcServiceImpl,如下所示:
package cn.itcast.service;
import org.apache.servicecomb.provider.pojo.RpcSchema;
@RpcSchema(schemaId = "sayHello") public class RpcServiceImpl implements RpcService {@Overridepublic String sayHello(String name) {return "hello " + name;} }
编写 springboot 的服务启动类,代码如下:
package cn.itcast;
import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableServiceComb
public class RpcProviderSpringBootApplication {public static void main(String[] args) {SpringApplication.run(RpcProviderSpringBootApplication.class, args);} }
完成后,就可以启动 ServiceComb 的服务提供者程序。
5.子模块-服务消费者 service-rpc-consumer**
进入服务消费方,打开子模块 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>servic-rpc</artifactId><groupId>cn.itcast</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-rpc-consumer</artifactId><name>service-rpc-consumer</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.3.5.Final</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.servicecomb</groupId><artifactId>spring-boot-starter-provider</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--transport 根据 microservice.yaml 中 endpoint 发布需求选择,本例中两者都引入,也可以
二选一--><dependency><groupId>org.apache.servicecomb</groupId><artifactId>transport-rest-vertx</artifactId></dependency><dependency><groupId>org.apache.servicecomb</groupId><artifactId>transport-highway</artifactId></dependency><dependency><groupId>org.apache.servicecomb</groupId><artifactId>provider-pojo</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency><!--添加依赖--><dependency><groupId>cn.itcast</groupId><artifactId>service-rpc-interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.apache.servicecomb</groupId><artifactId>java-chassis-dependencies</artifactId><version>1.0.0-m1</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>1.5.12.RELEASE</version><executions><execution><goals><goal>repackage</goal></goals><configuration><outputDirectory>target/bin</outputDirectory><classifier>exec</classifier></configuration></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>2.6</version><configuration><archive><manifestEntries><Class-Path>.</Class-Path></manifestEntries></archive></configuration></plugin></plugins></build>
</project>
6.服务运行测试
- 打开 CSE 服务注册中心
- 启动微服务的服务提供者
- 启动服务消费者
十一、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: providerversion: 0.0.1
servicecomb:circuitBreaker:#熔断Provider:provider:requestVolumeThreshold: 8fallbackpolicy:provider:policy: returnnullflowcontrol:#限流Provider:qps:limit:gateway: 1handler:chain:Provider:default: qps-flowcontrol-provider,bizkeeper-providerrest:address: 0.0.0.0:9080service:registry:address: http://127.0.0.1:30100autodiscovery: false
ServiceComb 提供了基于 Ribbon 的负载均衡方案,用户可以通过配置文件配置负载均衡策略,当前
支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略。
1.负载均衡策略
作为 ServiceComb 内置策略,我们测试一下执行效果。
首先,将服务提供者的启动类设置为共享(Share)模式。如下图所示:
其次:修改服务提供者的 Service 类,加入一行输出代码
运行 SpringBoot 启 动类。之后再次修改 microservice.yaml 文件,将端口号改为 8082 再次运行启动
类。
rest:
address: 0.0.0.0:9082
再次:运行服务消费者,观察控制台,我们会发现此时不断访问时,控制台上会更替出现输出信息。
2.限流策略
限流是微服务框架基本都可以解决的一个策略,是微服务框架中常见的系统保障措施。通常来说系
统的吞吐量是可以提前预测的,当请求量超过预期的伐值时可以采取一些限制措施来保障系统的稳
定运行,比如延迟处理、拒绝服务等。
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-friendshicifang-qa:serviceId: shicifang-qa
discoveryServer:
ribbon:eureka:enabled: false
servicecomb:tracing:enabled: true
第三步:添加 Zuul 网关的启动类
@SpringBootApplication
@EnableServiceComb
@EnableZuulProxy//新增注
public class ZuulSpringBootApplication {public static void main(String[] args) {SpringApplication.run(ZuulSpringBootApplication.class,args);}@Beanpublic CorsFilter corsFilter() {final UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();final CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true); // 允许 cookies 跨域config.addAllowedOrigin("*");// #允许向该服务器提交请求的 URI,*表示全部允许,在
SpringMVC 中,如果设成*,会自动转成当前请求头中的 Originconfig.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: 1000handler: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.熔断机制
CircuitBreaker 就是熔断的意思。
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问
压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调
用。
服务雪崩效应:
服务熔断过程:
microservice.yaml 文件配置:
circuitBreaker:provider:shicifang-qa:requestVolumeThreshold: 1
fallbackpolicy:provider:policy: returnnull
测试:
后台:
先启动 shicifang-friend,再启动 shgicifang-qa,最后启动 shicifang-gateway-web。
前端:
使用 web 前端访问 test.htm,返回问题列表后,停掉 mysql 数据库,观察 shicifang-friend 控制台日志,
当服务抛出异常后,多次调用就不在输出 22222 了。启动数据库数据库,再次点击关注。服务启动
成功。
十二、ServiceComb 综合案例-十次方交友与问题模块
1.案例需求说明
项目功能是,用户发布问题,客户对自己喜欢的用户点关注。类似粉丝订阅。
本案例很好的使用 ServiceComb 实现了十次方项目中的用户发布问题,客户关注喜欢的
问题。
**
2.案例架构分析**
shicifang-friend:用户关注相关微服务
shicifang-qa:用户发帖相关微服务
shicifang-gateway-web:网关访问微服务
**3.案例数据库分析
CREATE TABLE `tb_friend` (`userid` varchar(20) NOT NULL COMMENT '用户 ID',`friendid` varchar(20) NOT NULL COMMENT '好友 ID',`islike` varchar(1) DEFAULT NULL COMMENT '是否互相喜欢',PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_friend
-- ----------------------------
INSERT INTO `tb_friend` VALUES ('1', '1222', '0');
INSERT INTO `tb_friend` VALUES ('111', '1222', '0');
INSERT INTO `tb_friend` VALUES ('134732', '1222', '0');
INSERT INTO `tb_friend` VALUES ('13732', '1222', '0');
INSERT INTO `tb_friend` VALUES ('3432', '1222', '0');
INSERT INTO `tb_friend` VALUES ('555', '1222', '0');
INSERT INTO `tb_friend` VALUES ('90', '24105', '0');**
CREATE TABLE `tb_nofriend` (`userid` varchar(20) NOT NULL COMMENT '用户 ID',`friendid` varchar(20) NOT NULL COMMENT '好友 ID',PRIMARY KEY (`userid`,`friendid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `tb_pl`;
CREATE TABLE `tb_pl` (`problemid` varchar(20) NOT NULL COMMENT '问题 ID',`labelid` varchar(20) NOT NULL COMMENT '标签 ID',PRIMARY KEY (`problemid`,`labelid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_pl
-- ----------------------------
INSERT INTO `tb_pl` VALUES ('1', '1');
DROP TABLE IF EXISTS `tb_problem`;
CREATE TABLE `tb_problem` (`id` varchar(20) NOT NULL COMMENT 'ID',`title` varchar(100) DEFAULT NULL COMMENT '标题',`content` text COMMENT '内容',`createtime` datetime DEFAULT NULL COMMENT '创建日期',`updatetime` datetime DEFAULT NULL COMMENT '修改日期',`userid` varchar(20) DEFAULT NULL COMMENT '用户 ID',`nickname` varchar(100) DEFAULT NULL COMMENT '昵称',`visits` bigint(20) DEFAULT NULL COMMENT '浏览量',`thumbup` bigint(20) DEFAULT NULL COMMENT '点赞数',`reply` bigint(20) DEFAULT NULL COMMENT '回复数',`solve` varchar(1) DEFAULT NULL COMMENT '是否解决',`replyname` varchar(100) DEFAULT NULL COMMENT '回复人昵称',`replytime` datetime DEFAULT NULL COMMENT '回复日期',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='问题';
-- ----------------------------
-- Records of tb_problem
-- ----------------------------
INSERT INTO `tb_problem` VALUES ('1', '这是个问题', '代码调试不通咋办?', '2018-01-08
11:50:50', '2018-01-09 11:50:54', '2', null, '101', null, null, null, null, null);
DROP TABLE IF EXISTS `tb_reply`;
CREATE TABLE `tb_reply` (`id` varchar(20) NOT NULL COMMENT '编号',`problemid` varchar(20) DEFAULT NULL COMMENT '问题 ID',`content` text COMMENT '回答内容',`createtime` datetime DEFAULT NULL COMMENT '创建日期',`updatetime` datetime DEFAULT NULL COMMENT '更新日期',`userid` varchar(20) DEFAULT NULL COMMENT '回答人 ID',`nickname` varchar(100) DEFAULT NULL COMMENT '回答人昵称',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='回答';
-- ----------------------------
-- Records of tb_reply
-- ----------------------------
INSERT INTO `tb_reply` VALUES ('', '1', null, null, null, null, null);
INSERT INTO `tb_reply` VALUES ('2', '1', '问老师呗', '2018-01-10 14:14:06', null, '1',
null);
INSERT INTO `tb_reply` VALUES ('3', '2', '明天再调', '2018-01-07 14:14:13', null, '1',
null);
DROP TABLE IF EXISTS `tb_ul`;
CREATE TABLE `tb_ul` (`uid` varchar(20) NOT NULL COMMENT '用户 ID',`lid` varchar(20) NOT NULL COMMENT '标签 ID',PRIMARY KEY (`uid`,`lid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.十次方交友与问答模块结构
Shicifang 父工程的 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>cn.itcast</groupId><artifactId>shicifang</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>shicifang-gateway-web</module><module>shicifang-friend</module><module>shicifang-qa</module><module>shicifang-qa</module><module>shicifang-friend-interface</module><module>shicifang-common</module></modules><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><fastjson.version>1.2.47</fastjson.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.12.RELEASE</version><relativePath/></parent><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><plugins><plugin><artifactId>maven-clean-plugin</artifactId><version>3.0.0</version></plugin><plugin><artifactId>maven-resources-plugin</artifactId><version>3.0.2</version></plugin><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version></plugin><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.20.1</version></plugin><plugin><artifactId>maven-jar-plugin</artifactId><version>3.0.2</version></plugin><plugin><artifactId>maven-install-plugin</artifactId><version>2.5.2</version></plugin><plugin><artifactId>maven-deploy-plugin</artifactId><version>2.8.2</version></plugin></plugins></pluginManagement></build>
</project>
5.定义服务接口
在 shicifang-friend-interface 模块中,添加服务接口,代码如下:
package com.tensquare.friend.service;
public interface FriendService {public int addFriend(String userid,String friendid);
}
6.引入十次方项目的通用模块
十次方的 shicifang-common 通用模块结构如下图:
7.开发十次方的交友微服务
在 shicifang-friend 模块中,开发交友微服务,关键代码如下:
@RestSchema(schemaId="friend")
@RequestMapping("/friend")
public class FriendRestService {@Autowiredprivate FriendService friendService;@GetMapping(path = "/like")public String addFriend(String friendid, String userid){System.out.println(22222);friendService.addFriend(userid, friendid);return "1";} }
在 microservice.yaml 中配置微服务名称为 shicifang-friend.
文件配置如下:
APPLICATION_ID: start.servicecomb.io #应用名称
service_description:name: shicifang-friend #微服务名称version: 0.0.1 #微服务版本号
servicecomb:tracing: #日志收集器配置collector:address: http://127.0.0.1:9411circuitBreaker: #服务熔断Provider:shicifang-friend:requestVolumeThreshold: 8 #10 秒内发生多少次失败后熔断.注意由于 m2 存在一个 BUG,如果设
置为 N,实际上生效的值是 N-1fallbackpolicy:provider:policy: returnnullflowcontrol: #限流配置Provider:qps:limit:gateway: 1000handler: #服务处理方式包括限流、熔断、日志追踪chain:Provider:default: qps-flowcontrol-provider,bizkeeper-provider,tracing-providerrest: #rest 方式方式调用微服务,多个微服务启动注意端口冲突问题address: 0.0.0.0:9081service:registry: #服务注册中心地址,端口默认 30100address: http://127.0.0.1:30100
8.开发十次方的问答微服务
在 shicifang-qa 模块中开发问答微服务,代码如下:
@RestSchema(schemaId = "problem-qa")
@RequestMapping(path = "/problem-qa")
public class ProblemController {@Autowiredprivate FriendService friendService;@Autowiredprivate ProblemService problemService;/*** 查询全部数据* @return*/@RequestMapping(path="/", method =RequestMethod.GET,produces =
APPLICATION_JSON_UTF8_VALUE)@ResponseBodypublic ResponseEntity<List> findAll(String userid,String friendid){System.out.println("微服务 2 调用");return new ResponseEntity<>(problemService.findAll(),null, OK);}/*** 新增用户关注* @return*/@RequestMapping(path="/",method =RequestMethod.POST)@ResponseBodypublic ResponseEntity<String> addFridend(@RequestBody UserVO userVO){//调用微服务关注java.util.Random r=new java.util.Random();int returnState = friendService.addFriend(r.nextInt()+"",userVO.getFriendid());//新增一个问题Problem problem = new Problem();problem.setContent("你好,传智播客.黑马程序员");problemService.add(problem);return new ResponseEntity<String>(String.valueOf(returnState), null, OK);} }
在 microservice.yaml 文件配置如下:
APPLICATION_ID: start.servicecomb.io
service_description:name: shicifang-qaversion: 0.0.1
servicecomb:tracing:collector:address: http://127.0.0.1:9411circuitBreaker:Provider:shicifang-friend:requestVolumeThreshold: 8fallbackpolicy:provider:policy: returnnullflowcontrol:Provider:qps:limit:gateway: 1000handler:chain:Provider:default: qps-flowcontrol-provider,bizkeeper-provider,tracing-providerrest:address: 0.0.0.0:9083service:registry:address: http://127.0.0.1:30100
9.添加允许跨域请求的过滤器
@SpringBootApplication
@EnableServiceComb
@EnableZuulProxy//新增注
public class ZuulSpringBootApplication {public static void main(String[] args) {SpringApplication.run(ZuulSpringBootApplication.class,args);}@Beanpublic CorsFilter corsFilter() {final UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();final CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true); // 允许 cookies 跨域config.addAllowedOrigin("*");// #允许向该服务器提交请求的 URI,*表示全部允许,在
SpringMVC 中,如果设成*,会自动转成当前请求头中的 Originconfig.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);} }
10.开发十次方的服务调用者-前端页面
在前端测试页面 test.html 中,加入 ajax 方式访问微服务。代码如下:
<script type="text/javascript" src="jquery-3.3.1.js"></script>
<script>$.ajax({url:
'http://127.0.0.1:9003/shicifang-qa/problem-qa/?userid=3432&friendid=1222',type: "GET",success: function (data) {$(".div-border").empty();$.each(data,function(i,data){var html = "<div class='content-div'>";html+="<p>"html+="<b>"+data.title+"</b><br>"html+="<b>"+data.content+"</b><br>"html+="<input type='button' value=' 关 注 '
onclick='guanzhu("+data.userid+")'>" html+="</p>"html+="</div>"$(".div-border").append(html)}); },error: function (xhr) {console.log("连接异常")}});function guanzhu(userid){var dataParam = {"userid":userid,"friendid":1234};$.ajax({url: 'http://127.0.0.1:9003/shicifang-qa/problem-qa/',type: "POST",data:JSON.stringify(dataParam),contentType: "application/json; charset=utf-8",success: function (data) {console.log("关注成功")},error: function (xhr) {console.log("关注失败")}});}
</script>
11.测试微服务发布与调用
- 开启 CSE 服务注册中心
- 运行 shicifang-friend 模块
- 运行 shicifang-qa 模块
- 运行 shicifang-gate-web 模块
- 运行十次方前端 test.html,刷新页面可以看到微服务调用成功