ServiceComb+Etcd

ServiceComb+Etcd

一、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 = 30100

read_header_timeout = 60s read_timeout = 60s idle_timeout = 60s write_timeout = 60s max_header_bytes = 32768 # 32K max_body_bytes = 2097152 # 2M

enable_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: provider version: 0.0.1 servicecomb: circuitBreaker: Provider: provider: requestVolumeThreshold: 8 fallbackpolicy: provider: policy: returnnull flowcontrol: Provider: qps: limit: gateway: 100 handler: chain: Provider: default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider rest: address: 0.0.0.0:9080 service: registry: address: http://192.168.229.133:30100 autodiscovery: 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 { @Autowired private 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-rpc 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

编写服务端 RpcService 接口的实现类 RpcServiceImpl,如下所示:

package cn.itcast.service; import org.apache.servicecomb.provider.pojo.RpcSchema; @RpcSchema(schemaId = "sayHello") public class RpcServiceImpl implements RpcService { @Override public 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: provider version: 0.0.1 servicecomb: circuitBreaker:#熔断 Provider: provider: requestVolumeThreshold: 8 fallbackpolicy: provider: policy: returnnull flowcontrol:#限流 Provider: qps: limit: gateway: 1 handler: chain: Provider: default: qps-flowcontrol-provider,bizkeeper-provider rest: address: 0.0.0.0:9080 service: registry: address: http://127.0.0.1:30100 autodiscovery: 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-friend shicifang-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); } @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.熔断机制 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 { @Autowired private 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:9411 circuitBreaker: #服务熔断 Provider: shicifang-friend: requestVolumeThreshold: 8 #10 秒内发生多少次失败后熔断.注意由于 m2 存在一个 BUG,如果设 置为 N,实际上生效的值是 N-1 fallbackpolicy: provider: policy: returnnull flowcontrol: #限流配置 Provider: qps: limit: gateway: 1000 handler: #服务处理方式包括限流、熔断、日志追踪 chain: Provider: default: qps-flowcontrol-provider,bizkeeper-provider,tracing-provider rest: #rest 方式方式调用微服务,多个微服务启动注意端口冲突问题 address: 0.0.0.0:9081 service: registry: #服务注册中心地址,端口默认 30100 address: http://127.0.0.1:30100

8.开发十次方的问答微服务 在 shicifang-qa 模块中开发问答微服务,代码如下:

@RestSchema(schemaId = "problem-qa") @RequestMapping(path = "/problem-qa") public class ProblemController { @Autowired private FriendService friendService; @Autowired private ProblemService problemService; /**

  • 查询全部数据

  • @return */ @RequestMapping(path="/", method =RequestMethod.GET,produces = APPLICATION_JSON_UTF8_VALUE) @ResponseBody public ResponseEntity<List> findAll(String userid,String friendid){ System.out.println("微服务 2 调用"); return new ResponseEntity<>(problemService.findAll(),null, OK); } /**

  • 新增用户关注

  • @return */ @RequestMapping(path="/",method =RequestMethod.POST) @ResponseBody public 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-qa version: 0.0.1 servicecomb: tracing: collector: address: http://127.0.0.1:9411 circuitBreaker: Provider: shicifang-friend: requestVolumeThreshold: 8 fallbackpolicy: provider: policy: returnnull flowcontrol: Provider: qps: limit: gateway: 1000 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

9.添加允许跨域请求的过滤器

@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); } }

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,刷新页面可以看到微服务调用成功

posted on 2023-03-22 17:24  末末随笔  阅读(256)  评论(0编辑  收藏  举报

导航