ServiceComb Java Chassis 快速入门和复杂系统实践经验总结

快速入门-搭建一个典型的微服务应用

项目介绍

示例微服务应用由 4 个微服务组成。

  1. 应用网关:负责接收前端的请求,并将请求转发给后端服务处理。应用网关还负责简单的认证功能。
  2. 文件服务: 提供一个上传文件接口,和删除文件接口。
  3. 用户管理: 提供登录认证逻辑实现。
  4. 静态页面托管 HTML/JS/CSS等。

本地微服务引擎本是CSE 微服务引擎的简化版本,用于本地开发调试。它包含3个服务。

  1. 服务中心:负责服务注册和发现。
  2. 配置中心:负责集中配置管理。
  3. 控制台:提供前端管理界面。

安装本地微服务引擎

下载本地微服务引擎:https://support.huaweicloud.com/devg-servicestage/ss-devg-0036.html

启动:

start.bat

访问:

http://localhost:30106/#/cse/service/dashboard

运行示例微服务应用

下载示例微服务应用:

git clone https://github.com/apache/servicecomb-samples.git

进入本示例项目:

cd porter_springboot

编译项目:

mvn clean install

初始化数据库:本地安装 mysql 数据库, 并且执行目录user-service\src\main\resources\config下面的脚本 create_db_user.sql 。

启动:数据库使用 root/root 登录, 如果数据库密码为自定义值,需要修改脚本后运行。

start_all.bat

访问:http://localhost:9090/ui/login.html  登录用户为 admin 或者 guest, 密码为 test。登录以后可以上传一个文件、根据文件 ID 删除一个文件。

了解示例微服务应用项目结构和开发过程

Maven: 依赖管理

Java-chassis 采用依赖。 依赖关系管理本身并不复杂,但是在项目升级、集成新的第三方软件的时候,容易出现冲突。开发者需要深刻理解 Maven 依赖管理的一些技巧,才能够快速解决这些冲突。

示例微服务项目通过 maven depdendency management 引入 java-chassis 的依赖管理。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.servicecomb</groupId>
      <artifactId>java-chassis-dependencies</artifactId>
      <version>${servicecomb.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

依赖关系管理并不会在项目中引入三方件,只是告诉项目中,如果引入某个三方件,这个三方件的版本,需要按照 java-chassis-dependencies 里面指定的版本引入。因为 java-chassis-dependencies 引入的三方件经过大量的集成测试,因此能够极少的降低三方件软件冲突的风险。

学习材料:使用maven管理复杂依赖关系的技巧

打包方式

JAVA 项目一般有两种打包方式:Flat 方式和 Spring Boot 方式。

  1. Flat方式:应用编译以后,项目依赖的 jar 包放到一个独立的 lib 目录。
  2. Spring Boot 方式:应用编译以后,将项目的 class, 和依赖的 jar 包都打包在一个 jar 文件中。

Spring Boot方式在分发应用的时候更加简单,所以项目采用 Spring Boot 方式打包。需要在 POM 中引入 Spring Boot 的打包插件。

<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <version>2.1.6.RELEASE</version>
      <executions>
        <execution>
          <goals>
            <goal>repackage</goal>
          </goals>
          <configuration>
            <mainClass>${main.class}</mainClass>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</pluginManagement>

编译选项

Java-chassis 的运行依赖于编译选项中增加 -parameters , 可以通过 maven compiler plugin 指定。

<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerArgument>-parameters</compilerArgument>
      </configuration>
    </plugin>
  </plugins>
</pluginManagement>

运行环境和启动类

Java-chassis 开发非常灵活,支持不同的运行环境。比如打包为 war,运行于 tomcat 中;和 spring boot 集成,运行于 embedded tomcat 中;使用轻量级的 HTTP 服务器独立运行。 示例微服务项目的 user-service、file service、website 都采用和 spring boot 集成,运行于 embedded tomcat 中。gateway-service使用轻量级的 HTTP 服务器独立运行。

user-service、file-service都引入了如下依赖:

<dependency>
  <groupId>org.apache.servicecomb</groupId>
  <artifactId>java-chassis-spring-boot-starter-servlet</artifactId>
</dependency>

学习材料:java-chassis 与 spring boot 集成的原理

学习材料:java-chassis 多样化的通信协议参考

java-chassis可以采用 spring 的方式启动,也可以采用 spring boot方式启动。 示例项目采用 Spring Boot 的方式启动,启用 java-chasiss 框架,需要在启动类上加上 @EnableServiceComb 。

@SpringBootApplication
@EnableServiceComb
public class FileMain {
  public static void main(String[] args) throws Exception {
    try {
      SpringApplication.run(FileMain.class, args);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

gateway-service 运行于轻量级的 HTTP 服务器,启动类有些特殊,不需要启动 spring boot 的 embedded tomcat. WebApplicationType设置为NONE.

@SpringBootApplication
@EnableServiceComb
public class GatewayMain {
  public static void main(String[] args) throws Exception {
    try {
      new SpringApplicationBuilder().web(WebApplicationType.NONE).sources(GatewayMain.class).run(args);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Provider 开发: jaxrs, spring mvc, 透明RPC开发和契约

通过定义一个简单的接口,接口计算 a + b 的返回值并返回。

  1. 不管采用哪种方式开发的接口,都会生成契约。契约采用 Open API 进行描述,如果服务监听的协议是 REST,那么任何一种方式开发的接口,都可以通过浏览器直接访问。每种开发方式生成的契约有差异,意味着访问方式不一样。jaxrs、spring mvc采用了 annotation 描述与 HTTP 的映射关系,访问方式更加简单直接;透明 RPC 方式生成的契约将所有参数包装为一个 POST 的 body 参数,使用起来没有那么直接。
  2. 不管采用哪种方式开发的接口,都可以监听多种协议,比如 REST、HIGHWAY,修改监听协议不需要修改业务代码。监听 HIGHWAY 协议,不能通过浏览器直接访问接口,需要通过 Consumer API 进行访问。
  3. 从契约可以看出,jaxrs 在 REST 语言方面最规范。spring mvc 的 REST 语义存在很多二义性,比如 @RequestParam 既可以表示 query 参数,也可以表示 form 参数,生成的契约只能够采用 query 参数来表达。根据大量的开发实践,建议 Provider 开发采用 jaxrs 。熟悉 spring boot 的开发者可能倾向于选择 spring mvc, java-chassis 允许一个服务里面的不同接口采用不一样的方式定义,这些接口可以并存。
  4. 生成的契约会打印到服务启动日志中,也会注册到服务中心,通过服务中心控制台查看。服务中心控制台还提供了对 REST 接口进行测试的功能,非常方便。

JaxRS 方式定义服务:

@RestSchema(schemaId = "HelloWorldJaxRS")
@Path("/jaxrs")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldJaxRS {
    @Path("/add")
    @POST
    public int add(@FormParam("a") int a, @FormParam("b") int b) {
        return a + b;
    }
}

自动生成的契约:

swagger: "2.0"
info:
  version: "1.0.0"
  title: "swagger definition for org.apache.servicecomb.samples.porter.user.service.HelloWorldJaxRS"
  x-java-interface: "gen.swagger.HelloWorldJaxRSIntf"
basePath: "/jaxrs"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
  /add:
    post:
      operationId: "add"
      parameters:
      - name: "a"
        in: "formData"
        required: false
        type: "integer"
        default: 0
        format: "int32"
      - name: "b"
        in: "formData"
        required: false
        type: "integer"
        default: 0
        format: "int32"
      responses:
        "200":
          description: "response of 200"
          schema:
            type: "integer"
            format: "int32"

Spring MVC 方式定义服务:

@RestSchema(schemaId = "HelloWorldSpringMVC")
@RequestMapping(path = "/springmvc", produces = MediaType.APPLICATION_JSON_VALUE)
public class HelloWorldSpringMVC {
    @PostMapping(path = "/add")
    public int add(@RequestParam("a") int a, @RequestParam("b") int b) {
        return a + b;
    }
}

自动生成的契约:

swagger: "2.0"
info:
  version: "1.0.0"
  title: "swagger definition for org.apache.servicecomb.samples.porter.user.service.HelloWorldSpringMVC"
  x-java-interface: "gen.swagger.HelloWorldSpringMVCIntf"
basePath: "/springmvc"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
  /add:
    post:
      operationId: "add"
      parameters:
      - name: "a"
        in: "query"
        required: true
        type: "integer"
        format: "int32"
      - name: "b"
        in: "query"
        required: true
        type: "integer"
        format: "int32"
      responses:
        "200":
          description: "response of 200"
          schema:
            type: "integer"
            format: "int32"

透明 RPC 方式定义服务:

@RpcSchema(schemaId = "HelloWorldRPC")
public class HelloWorldRPC {
    public int add(int a, int b) {
        return a + b;
    }
}

自动生成的契约:

swagger: "2.0"
info:
  version: "1.0.0"
  title: "swagger definition for org.apache.servicecomb.samples.porter.user.service.HelloWorldRPC"
  x-java-interface: "gen.swagger.HelloWorldRPCIntf"
basePath: "/HelloWorldRPC"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
  /add:
    post:
      operationId: "add"
      parameters:
      - in: "body"
        name: "addBody"
        required: false
        schema:
          $ref: "#/definitions/addBody"
      responses:
        "200":
          description: "response of 200"
          schema:
            type: "integer"
            format: "int32"
definitions:
  addBody:
    type: "object"
    properties:
      a:
        type: "integer"
        format: "int32"
      b:
        type: "integer"
        format: "int32"
    x-java-class: "gen.swagger.addBody"

Consumer开发: RestTemplate,透明RPC开发

Consumer 可以通过三种方式访问 Provider 的接口。

  1. 采用透明 RPC 的方式;
  2. 采用 RestTemplate 的方式;
  3. 采用 InvokerUtils 访问;
  4. 不管服务端监听的是 REST,还是 HIGHWAY,都可以采用这三种方式访问。根据大量的开发经验,建议采用透明 RPC 的方式。因为这种方式代码最简洁,可移植性最好,以后需要对代码进行重构,或者切换新的框架的时候,透明 RPC 的方式都更加容易移植。

采用透明 RPC 的方式:透明 RPC 的方式, Consumer 可以自定义接口,接口不需要包含 Provider 的所有方法,也不要求参数顺序一致,Consumer和 Provider 完全解耦,非常灵活。从下面的 Consumer 代码可以看出,使用透明 RRC 的方式最简洁,不同的 Provider 接口,调用方式都一样;采用 RestTemplate 方式调用,构造参数的时候,需要根据契约来构造,Provider 的契约不同,因此 Consumer 构造的参数也不同;InvokerUtils 的方式,也需要根据契约来构造参数,参数名称和个数需要保持和契约一致。

@RestSchema(schemaId = "HelloworldTest")
@Path("/test")
public class HelloworldTest {
    public static interface Consumer {
        int add(int a, int b);
    }

    @RpcReference(microserviceName = "user-service", schemaId = "HelloWorldJaxRS")
    private Consumer jaxrsConsumer;

    @RpcReference(microserviceName = "user-service", schemaId = "HelloWorldSpringMVC")
    private Consumer springmvcConsumer;

    @RpcReference(microserviceName = "user-service", schemaId = "HelloWorldSpringMVC")
    private Consumer rpcConsumer;

    RestTemplate restTemplate = RestTemplateBuilder.create();

    @Path("/test")
    @GET
    public int test() {
        int total = 0;
        total += jaxrsConsumer.add(1, 1);
        total += springmvcConsumer.add(1, 1);
        total += rpcConsumer.add(1, 1);
        HttpHeaders formHeaders = new HttpHeaders();
        formHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        Map<String, Object> map = new HashMap<>();
        map.put("a", 1);
        map.put("b", 2);
        HttpEntity<Map<String, Object>> formEntiry = new HttpEntity<>(map, formHeaders);
        total += restTemplate.postForEntity("cse://user-service/jaxrs/add", formEntiry, int.class).getBody();
        total += restTemplate.postForEntity("cse://user-service/springmvc/add?a=1&b=1", null, int.class).getBody();
        Map<String, Object> swaggerArguments = new HashMap<>();
        swaggerArguments.put("a", 1);
        swaggerArguments.put("b", 1);
        total += (int) InvokerUtils.syncInvoke("user-service", "HelloWorldJaxRS", "add", swaggerArguments, int.class);
        total += (int) InvokerUtils.syncInvoke("user-service", "HelloWorldSpringMVC", "add", swaggerArguments, int.class);
        return total;
    }
}

使用异步

通过异步,可以提升资源消耗和提高性能。但是使用异步,也给开发者的开发能力提出了一些要求,比如异步执行逻辑里面不能包含阻塞操作。java-chassis 可以在 Provider 和 Consumer 使用 CompletableFuture 来使用异步。Provider 和 Consumer 的异步是完全独立的,即 provider 可以使用异步,Consumer 不使用异步,反之亦然。

Provider定义:

@RestSchema(schemaId = "HelloWorldJaxRS")
@Path("/jaxrs")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldJaxRS {
    @Path("/add")
    @POST
    public CompletableFuture<Integer> add(@FormParam("a") int a, @FormParam("b") int b) {
        return CompletableFuture.completedFuture(a + b);
    }
}

Consumer定义:

public static interface Consumer {
    CompletableFuture<Integer> add(int a, int b);
}

Edge Service 的路由策略

Edge Service 提供了非常多的路由策略,默认的策略使用服务名作为前缀,还提供了采用 URL 进行正则匹配的路由策略。

servicecomb:
  http:
    dispatcher:
      edge:
        url:
          enabled: true
          pattern: /(.*) ## 默认值,一般不需要配置
          mappings:
            businessV1:
              prefixSegmentCount: 1
              path: "/url/business/v1/.*"
              microserviceName: business
              versionRule: 1.0.0-2.0.0
            businessV2:
              prefixSegmentCount: 1
              path: "/url/business/v2/.*"
              microserviceName: business
              versionRule: 2.0.0-3.0.0

理解请求处理流程

从 Consumer 调用 Provider, 会经过下面的处理流程。运行模型对应于 Handler 链。可以开发自定义的 Handler, 来对请求拦截,进行一些列的治理。java-chassis 提供的大部分治理能力,都是通过 Handler 实现。通过Handler还可以实现异常处理、调用链跟踪、认证鉴权等很多功能。进一步打开 REST 处理流程,还有 HttpServerFilter 或者 HttpClientFilter。 当需要使用 HTTP 来做一些控制,比如读取和设置 cookie,需要扩展。下面是微服务A调用微服务B的全部执行过程。 ServiceComb基于事件实现了这些过程的metrics统计,阅读代码也非常便利,可以打开 Invocation , 查看 onXXX 方法被调用的地方,就能够找到各个环节执行的入口。 

  • 开始
  • A 执行 Handler
  • A 执行 HttpClientFilter
  • A 发送请求
  • B 收到请求
  • B 执行 HttpServerFilter
  • B 执行 Handler
  • B 执行 业务逻辑
  • B 执行 Handler
  • B 执行 HttpServerFilter
  • B 发送响应
  • A 收到响应
  • A 执行 HttpClientFilter
  • A 执行 Handler
  • 结束

常见的治理和开发功能

常用的治理能力,使用 java-chassis 都是开箱即用的,不需要开发任何代码,只需要在 microservice.yaml 里面增加配置项,极大的简化了开发者的开发工作量。

处理链配置(Handler)

  1. Provider 和 Consumer 的处理链独立配置。Handler 在处理链的位置,决定了它的执行顺序。
  2. Consumer的处理链,还可以结合实际情况,在访问某个具体的服务的时候,指定不一样的处理链。
servicecomb:
  handler:
    chain:
      Provider:
        default: qps-flowcontrol-provider
      Consumer:
        default: qps-flowcontrol-consumer,loadbalance,fault-injection-consumer

负载均衡

ervicecomb:
  loadbalance:
    strategy:
      name: RoundRobin # Support RoundRobin,Random,WeightedResponse,SessionStickiness

流量控制

servicecomb:
  flowcontrol:
    Provider:
      qps:
        enabled: true
          global:
            limit: 10000

灰度发布

servicecomb:
    routeRule:  
      provider: | #服务名
        - precedence: 2 #优先级
          match:        #匹配策略
            headers:          #header匹配
              region:            
                regex: 'regoin[0-9]*'
                caseInsensitive: false # 是否区分大小写,默认为false,区分大小写
              type:         
                exact: gray
          route: #路由规则
            - weight: 100 #权重值
              tags:
                version: {version1}
                app: {appId}

针对业务的开发部署、参数设置建议

升级到 java chassis 的最新版本

升级到最新版本会存在一些工作量,并解决三方软件冲突等问题。及时升级到最新版本也有很多好处:(1)老版本已知bug得到修复、配置参数调优、在业务中使用新功能(比如下文很多配置项可能在新版本才有);(2)得到更加及时的社区支持。因为老版本时间很长,使用者不多,维护者也多数不能够接触老版本问题,使用新版本,使用的问题会得到更加快速的回复;(3)安全漏洞得到及时修复,三方软件漏洞得到及时升级。

ServiceComb提供了一个很好的说明,讲解为什么升级,及其好处和问题:http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/featured-topics/compatibility.html

升级也会存在一些风险,升级前建议阅读升级指导,识别变化是否和业务应用场景有关,提前应对风险:http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/featured-topics/upgrading.html

合理配置日志文件

(1)使用 log4j2 或者 logback 输出日志。 将日志输出到文件,不要依赖于容器的 stdout。

(2)打开 metrics 日志,将 metrics 日志输出到独立的文件,比如 metrics.log, 而将业务日志输出到另外的文件,比如 servicecomb.log。

(3)打开 access log , 将 access log 输出到独立的日志文件。

(4)格式化打印业务日志,日志里面包含 trace id。可以独立开发一个 Handler,配置在 Provider Handler的最前面,Handler在接收到请求后打印一条日志,处理完成了打印一条日志,对于问题界定,使用AOM快速检索相关日志等非常有帮助。

http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/featured-topics/features/trace-id.html

合理配置线程池参数

建议开始之前通过文章: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/general-development/thread-model.html 了解 java chassis 的线程池设置原理。 下面列出一些常见的配置项和建议。性能优化和业务自身的性能有很大关系,不同的场景参数设置适用于不同的场景,需要具体分析。 为了简单, 下面分两种场景介绍:开始之前,需要对业务的性能做一些基本的摸底,对常见的接口进行测试,看看时延。

  • 业务性能很好的情况

单个接口的时延普遍低于10ms,少量接口低于100ms

业务性能很好的时候,为了让业务系统具备更好的可预测性,防止JVM垃圾回收、网络波动、突发流量等对性能的稳定性造成冲击,需要能够快速丢弃请求,并配合重试等措施,以保障波动情况下系统性能可预测,同时不会出现偶然的业务失败,影响体验。

连接数和超时设置:http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/transports/rest-over-vertx.html

# vertical 实例数,新版本保持默认值即可。建议配置为8~10,一般不需要修改。
servicecomb.rest.server.verticle-count: 10

# 默认值为 Integer.MAX_VALUE, 一般不需要修改
servicecomb.rest.server.connection-limit:

# 默认值60秒,一般不需要修改
servicecomb.rest.server.connection.idleTimeoutInSeconds: 60

# vertical 实例数,新版本保持默认值即可。建议配置为8~10,一般不需要修改。
servicecomb.rest.client.verticle-count: 0

# 一个客户端与服务器建立的最大连接数为 verticle-count * maxPoolSize, 不要超过线程数。 这里是 10*50=500. 实例非常多的场景,要减小单个实例的连接数。
servicecomb.rest.client.connection.maxPoolSize: 50

#默认值30 秒,一般不需要修改. 为服务端的一半
servicecomb.rest.client.connection.idleTimeoutInSeconds

业务线程池配置:http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/build-provider/thread-pool.html

# 线程池组数,建议 2~4
servicecomb.executor.default.group: 2

# 建议 50~200
servicecomb.executor.default.thread-per-group: 100

# 线程池排队队列大小,高性能场景不要使用默认值,以快速丢弃请求
servicecomb.executor.default.maxQueueSize-per-group: 10000

# 高性能场景配置小的排队超时时间,快速丢弃请求
servicecomb.rest.server.requestWaitInPoolTimeout: 100

超时时间:http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/config-reference/rest-transport-client.html

# 设置比较短的超时时间,快速丢弃请求, 但是不建议这个值小于1秒,可能导致很多问题。
servicecomb.request.timeout=5000

  • 业务性能不那么好的情况

单个接口的时延普遍高于100ms,时延高通常是由于业务代码存在IO、资源等等待,CPU利用率上出去导致的。如果是由于计算复杂导致的,调优会变得复杂。

当业务性能不太好的时候,下面几个参数值需要调大,否则业务会大量阻塞。业务性能不好,通过调大参数能够保证系统的吞吐量,应对突发流量来临时带来的业务失败。不过这个是以牺牲用户体验为代价的。需要关注下面的一些配置项:

# 默认值60秒,一般不需要修改
servicecomb.rest.server.connection.idleTimeoutInSeconds: 120000

#默认值30 秒,一般不需要修改. 为服务端的一半
servicecomb.rest.client.connection.idleTimeoutInSeconds: 90000

# 线程池组数,建议 2~4
servicecomb.executor.default.group: 4

# 建议 50~200
servicecomb.executor.default.thread-per-group: 100

# 线程池排队队列大小,性能不好的情况下需要排队
servicecomb.executor.default.maxQueueSize-per-group: 100000

# 高性能场景配置小的排队超时时间,快速丢弃请求
servicecomb.rest.server.requestWaitInPoolTimeout: 100
servicecomb.request.timeout=30000

ServiceComb 2.3.0 提供了更加高级的功能, 可以帮助解决快速失败和全局超时设置,参考: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/references-handlers/fail-retry.html

合理的规划系统架构

一般都会采用一级或者二级网关让系统具备更好的弹性。并且梳理流量、负责重试,使得系统具备更好的应对突发流量的能力。

下面有二级网关的架构建议,这个架构被大型用户使用过,供参考。

合理规划资源

在合理规划线程池参数里面提到了线程池等配置信息。 这个信息还需要结合资源规划进行合理配置。在开发测试环境,资源分配倾向于分配比较小的初始资源,以节省测试成本。但是对于生产环境,需要尽可能保证系统运行的可预期性,避免临时申请大量资源或者释放资源,在整个软件运行生命周期,核心资源池应该保持稳定。 分配较小的资源可能导致系统运行不稳定:比如容器可能将大量微服务分配到一个节点,请求量上来后,部分实例由于资源不足,就会被杀掉,分配到其他节点,系统处于波动和不稳定状态。

资源分配的核心包括 CPU 和 内存,生产环境,可以先给一个规划表,给出每个微服务的资源占用限制,然后一次性申请到稳定运行需要的资源。

线程池设置等会影响资源规划,通常增加一个线程,内存占用会增加1M。比如如果业务线程池设置2000个线程,那么建议至少给这个微服务分配不小于 2G 的初始内存。

合理规划治理参数

建议配置实例隔离参数: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/references-handlers/loadbalance.html

servicecomb:
  loadbalance:
    isolation:
      enabled: true
      errorThresholdPercentage: 0
      enableRequestThreshold: 5
      singleTestTime: 60000
      continuousFailureThreshold: 2
      maxSingleTestWindow: 60000 # 为了保证在并发情况下只有一个实例放通,会锁定放通实例。这个时间表示最大锁定时间。
      minIsolationTime: 3000 # 最短隔离时间。并发情况下,实例隔离后进行中的请求可能快速刷新隔离状态,增加最短隔离时间。
      recoverImmediatelyWhenSuccess:true # 放通实例,如果调用成功,立即清除统计状态,保证后续请求能够使用该实例。

实例隔离能够在一个实例故障的时候,短暂的不往这个实例发送消息,防止产生雪崩效应。

建议对耗时的请求配置独立线程池。系统中可能有一些特别耗时的任务,这些任务如果和其他请求在一个业务线程池处理,偶然的大并发,这些耗时任务可能将系统资源全部占据, 其他请求也得不到处理。

servicecomb.executors.Provider.${schemaId}.${operationId}: custom-executor

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Apache ServiceComb Java Chassis 是一个开箱即用Java语言微服务SDK,含服务契约、编程模型、运行模型与通信模型四个部分,具备负载均衡、容错熔断、限流降级、调用链追踪等全面微服务治理能力,服务治理能力与业务逻辑隔离。 它包含如下特性: 多种开发风格,REST(JAX-RS、Spring MVC)和RPC; 多种通信协议, HTTP over Vert.x、Http Over Servlet、Highway等; 统一一致的服务提供者、服务消费者处理链,以及基于契约的开箱即用的服务治理能力。 软件特点: 高性能 Java Chassis 网络层基于 Vert.x 实现, 支持开发者使用响应式编程, 开发者在使用熟悉的REST风格设计业务接口的时候,也能够获取到非常高性能的吞吐量。同时还提供了Highway协议,满足更高性能场景的要求。 原生支持OpenAPI Java Chassis 的接口开发、服务治理都基于 Swagger ,并通过接口语义检查,使得接口定义符合 OpenAPI 规范。 灵活的开发方式 开发者可以使用 SpringMVC/JAX-RS/transparent RPC 任意一种方式定义服务端接口, 并使用RPC/RestTemplate 等方式访问这些接口. 得益于Java Chassis的通信层与开发方式分离的设计,开发者可以在 Rest over Vertx/Rest over Servlet/Highway等通信模式下自由切换。 开箱即用的服务治理能力 Java Chassis 提供了大量开箱即用的服务治理能力,包括服务发现、熔断容错、负载均衡、流量控制等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值