You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/08/18 10:44:25 UTC
[incubator-servicecomb-docs] branch master updated: 1. 补充错误处理文档。 2 将中英文的内容目录内容刷新到一致状态,方便翻译。 * [异常处理](general-development/error-handling.md) 中英文
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-docs.git
The following commit(s) were added to refs/heads/master by this push:
new 82d911d 1. 补充错误处理文档。 2 将中英文的内容目录内容刷新到一致状态,方便翻译。 * [异常处理](general-development/error-handling.md) 中英文
82d911d is described below
commit 82d911d7557a548903d0dc953a1f3c9c2fdd051f
Author: liubao <ba...@huawei.com>
AuthorDate: Sat Aug 18 18:39:20 2018 +0800
1. 补充错误处理文档。 2 将中英文的内容目录内容刷新到一致状态,方便翻译。
* [异常处理](general-development/error-handling.md) 中英文
---
java-chassis-reference/LANGS.md | 3 +-
java-chassis-reference/en_US/SUMMARY.md | 23 ++-
.../en_US/assets/loadbalance-001.png | Bin 0 -> 39048 bytes
.../en_US/build-consumer/circuit-breaker.md | 2 +
.../en_US/build-consumer/code-first.md | 41 ++---
.../build-consumer/develop-consumer-using-rpc.md | 60 ++++---
.../en_US/build-consumer/instance-isolation.md | 29 ----
.../build-consumer/using-AsyncRestTemplate.md | 61 ++++++++
.../en_US/build-consumer/using-resttemplate.md | 74 ++++++++-
.../en_US/build-consumer/with-contract.md | 2 +
.../build-provider/access-log-configuration.md | 161 +++++++++++++++----
.../en_US/build-provider/code-first.md | 2 +
.../build-provider/configuration/lb-strategy.md | 27 ++--
.../configuration/ratelimite-strategy.md | 3 +-
.../en_US/build-provider/define-contract.md | 18 ++-
.../definition/isolate-relationship.md | 11 +-
.../definition/service-definition.md | 4 -
.../en_US/build-provider/interface-constraints.md | 68 +++++++-
.../en_US/build-provider/jaxrs.md | 118 +++++++++++++-
.../listen-address-and-publish-address.md | 6 +-
.../en_US/build-provider/protocol.md | 11 +-
.../{security => build-provider/protocol}/http2.md | 12 +-
.../build-provider/protocol/rest-over-servlet.md | 11 ++
.../en_US/build-provider/protocol/thread-model.md | 2 +-
.../en_US/build-provider/service-configuration.md | 14 ++
.../en_US/build-provider/springmvc.md | 112 +++++++++++++-
.../en_US/build-provider/swagger-annotation.md | 2 +
.../en_US/build-provider/transparent-rpc.md | 78 ++++++----
.../en_US/catalog/build-consumer.md | 27 ++++
.../en_US/catalog/build-provider.md | 47 ++++++
.../en_US/catalog/general-develop.md | 81 ++++++++++
.../en_US/catalog/open-service.md | 0
java-chassis-reference/en_US/catalog/security.md | 5 +
.../en_US/catalog/service-package-run.md | 6 +
java-chassis-reference/en_US/catalog/start.md | 13 +-
.../en_US/edge/by-servicecomb-sdk.md | 160 +++++++++++++++----
java-chassis-reference/en_US/edge/edge-service.md | 0
java-chassis-reference/en_US/edge/nginx.md | 2 +
java-chassis-reference/en_US/edge/open-service.md | 5 +
java-chassis-reference/en_US/edge/zuul.md | 8 +-
.../en_US/general-development/AlarmEvent.md | 37 +++++
.../en_US/general-development/CORS.md | 36 +++++
.../en_US/general-development/config.md | 53 +++++++
.../en_US/general-development/context.md | 36 +++++
.../general-development/cross-app-invocation.md | 46 ++++++
.../en_US/general-development/error-handling.md | 162 +++++++++++++++++++
.../en_US/general-development/file-download.md | 5 +-
.../en_US/general-development/file-upload.md | 23 ++-
.../general-development/local-develop-test.md | 57 ++++---
.../en_US/general-development/produceprocess.md | 89 +++++++++++
.../{edge => general-development}/secret-field.md | 0
java-chassis-reference/en_US/introduction.md | 1 +
.../question-and-answer/interface-compatibility.md | 7 +-
.../en_US/references-handlers/intruduction.md | 9 ++
.../en_US/references-handlers/loadbalance.md | 172 +++++++++++++++++++++
.../en_US/references-handlers/publickey.md | 59 +++++++
.../en_US/security/shi-yong-rsa-ren-zheng.md | 2 +-
java-chassis-reference/en_US/start/architecture.md | 5 +-
.../en_US/start/development-environment.md | 40 ++++-
java-chassis-reference/en_US/start/first-sample.md | 5 +-
java-chassis-reference/en_US/styles/website.css | 5 +
java-chassis-reference/zh_CN/SUMMARY.md | 1 +
.../zh_CN/general-development/error-handling.md | 163 +++++++++++++++++++
63 files changed, 2043 insertions(+), 279 deletions(-)
diff --git a/java-chassis-reference/LANGS.md b/java-chassis-reference/LANGS.md
index 4b11b96..b9c8e33 100644
--- a/java-chassis-reference/LANGS.md
+++ b/java-chassis-reference/LANGS.md
@@ -1 +1,2 @@
-* [中文](zh_CN/)
\ No newline at end of file
+* [中文](zh_CN/)
+* [English](en_US/)
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/SUMMARY.md b/java-chassis-reference/en_US/SUMMARY.md
index cd45834..39e18b7 100644
--- a/java-chassis-reference/en_US/SUMMARY.md
+++ b/java-chassis-reference/en_US/SUMMARY.md
@@ -14,8 +14,8 @@
* [用SpringMVC开发微服务](build-provider/springmvc.md)
* [用JAX-RS开发微服务](build-provider/jaxrs.md)
* [用透明RPC开发微服务](build-provider/transparent-rpc.md)
+ * [接口定义和数据类型](build-provider/interface-constraints.md)
* [服务监听地址和发布地址](build-provider/listen-address-and-publish-address.md)
- * [支持的数据类型](build-provider/interface-constraints.md)
* [服务配置](build-provider/service-configuration.md)
* [负载均衡策略](build-provider/configuration/lb-strategy.md)
* [限流策略](build-provider/configuration/ratelimite-strategy.md)
@@ -26,24 +26,26 @@
* [REST over Servlet](build-provider/protocol/rest-over-servlet.md)
* [REST over Vertx](build-provider/protocol/rest-over-vertx.md)
* [Highway RPC协议](build-provider/protocol/highway-rpc.md)
+ * [使用HTTP2通信](build-provider/protocol/http2.md)
* [程序启动逻辑](build-provider/bootup.md)
* [微服务实例之间的逻辑隔离关系](build-provider/definition/isolate-relationship.md)
* [Access Log配置](build-provider/access-log-configuration.md)
* [开发服务消费者](catalog/build-consumer.md)
* [使用RestTemplate开发服务消费者](build-consumer/using-resttemplate.md)
+ * [使用AsynRestTemplate开发服务消费者](build-consumer/using-AsyncRestTemplate.md)
* [使用RPC方式开发服务消费者](build-consumer/develop-consumer-using-rpc.md)
* [使用服务契约](build-consumer/with-contract.md)
* [调用控制](build-consumer/invoke-control.md)
- * [实例级故障隔离](build-consumer/instance-isolation.md)
* [熔断策略](build-consumer/circuit-breaker.md)
* [限流策略](build-consumer/flow-control.md)
* [故障注入](build-consumer/fault-injection.md)
* [通用开发](catalog/general-develop.md)
+ * [访问服务中心](general-development/visit-sc.md)
+ * [使用动态配置](general-development/config.md)
* [应用性能监控](general-development/metrics.md)
* [微服务调用链](general-development/microservice-invocation-chain.md)
* [自定义调用链打点](general-development/customized-tracing.md)
* [本地开发和测试](general-development/local-develop-test.md)
- * [访问服务中心](general-development/visit-sc.md)
* [Http Filter](general-development/http-filter.md)
* [文件上传](general-development/file-upload.md)
* [文件下载](general-development/file-download.md)
@@ -51,12 +53,18 @@
* [DNS自定义配置](general-development/dnsconfig.md)
* [代理设置](general-development/dai-li-she-zhi.md)
* [框架上报版本号](general-development/report-framework-version.md)
+ * [跨应用调用](general-development/cross-app-invocation.md)
+ * [定制序列化和反序列化方法](general-development/secret-field.md)
+ * [使用Context传递控制消息](general-development/context.md)
+ * [返回值序列化扩展](general-development/produceprocess.md)
+ * [CORS机制](general-development/CORS.md)
+ * [获取熔断与实例隔离告警事件信息](general-development/AlarmEvent.md)
* [Shutdown gracefully](general-development/shutdown.md)
-* [服务能力开放](catalog/open-service.md)
+ * [Handle exceptions](general-development/error-handling.md)
+* [服务能力开放](edge/open-service.md)
+ * [使用Edge Service做边缘服务](edge/by-servicecomb-sdk.md)
* [使用confd和Nginx做边缘服务](edge/nginx.md)
* [使用zuul做边缘服务](edge/zuul.md)
- * [使用ServiceComb SDK开发边缘服务](edge/by-servicecomb-sdk.md)
- * [定制序列化和反序列化方法](edge/secret-field.md)
* [服务打包和运行](catalog/service-package-run.md)
* [以standalone模式打包](packaging/standalone.md)
* [以WEB容器模式打包](packaging/web-container.md)
@@ -69,5 +77,8 @@
* [Web开发方式开发步骤](using-java-chassis-in-spring-boot/web-application.md)
* [JAVA应用方式和Web开发方式的区别](using-java-chassis-in-spring-boot/diff-between-java-web.md)
* [Spring MVC模式的差异](using-java-chassis-in-spring-boot/diff-spring-mvc.md)
+* [处理链参考](references-handlers/intruduction.md)
+ * [负载均衡](references-handlers/loadbalance.md)
+ * [公钥认证](references-handlers/publickey.md)
* [常见问题](question-and-answer/question_answer.md)
* [微服务接口兼容常见问题](question-and-answer/interface-compatibility.md)
diff --git a/java-chassis-reference/en_US/assets/loadbalance-001.png b/java-chassis-reference/en_US/assets/loadbalance-001.png
new file mode 100644
index 0000000..6852bf7
Binary files /dev/null and b/java-chassis-reference/en_US/assets/loadbalance-001.png differ
diff --git a/java-chassis-reference/en_US/build-consumer/circuit-breaker.md b/java-chassis-reference/en_US/build-consumer/circuit-breaker.md
index 2adad0e..b9c727d 100644
--- a/java-chassis-reference/en_US/build-consumer/circuit-breaker.md
+++ b/java-chassis-reference/en_US/build-consumer/circuit-breaker.md
@@ -1,3 +1,5 @@
+# 熔断策略
+
## 场景描述
熔断策略是对ServiceComb熔断功能的设置,用户通过配置熔断策略可以指定在何种条件下ServiceComb框架将终止发送请求。
diff --git a/java-chassis-reference/en_US/build-consumer/code-first.md b/java-chassis-reference/en_US/build-consumer/code-first.md
index bb6e9a2..d87d7ae 100644
--- a/java-chassis-reference/en_US/build-consumer/code-first.md
+++ b/java-chassis-reference/en_US/build-consumer/code-first.md
@@ -15,26 +15,29 @@
```java
import org.springframework.stereotype.Component;
import org.apache.servicecomb.foundation.common.utils.BeanUtils;
- import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
- import org.apache.servicecomb.provider.pojo.RpcReference;
- import org.apache.servicecomb.samples.common.schema.Hello;
- import org.apache.servicecomb.samples.common.schema.models.Person;
+import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.apache.servicecomb.samples.common.schema.Hello;
+import org.apache.servicecomb.samples.common.schema.models.Person;
+
@Component
- public class CodeFirstConsumerMain {
-@RpcReference(microserviceName = "codefirst", schemaId = "codeFirstHello")
- private static Hello hello;
-public static void main(String[] args) throws Exception {
- init();
- System.out.println(hello.sayHi("Java Chassis"));
- Person person = new Person();
- person.setName("ServiceComb/Java Chassis");
- System.out.println(hello.sayHello(person));
- }
-public static void init() throws Exception {
- Log4jUtils.init();
- BeanUtils.init();
- }
- }
+public class CodeFirstConsumerMain {
+ @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstHello")
+ private static Hello hello;
+
+ public static void main(String[] args) throws Exception {
+ init();
+ System.out.println(hello.sayHi("Java Chassis"));
+ Person person = new Person();
+ person.setName("ServiceComb/Java Chassis");
+ System.out.println(hello.sayHello(person));
+ }
+
+ public static void init() throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
```
在以上代码中,服务消费者已经取得了服务提供者的服务接口Hello,并在代码中声明一个Hello类型的成员。通过在hello上使用RPCReference注解指明微服务名称和schemaId,ServiceComb框架可以在程序启动时从服务中心获取到对应的服务提供者实例信息,并且生成一个代理注入到hello中,用户可以像调用本地类一样调用远程服务。
diff --git a/java-chassis-reference/en_US/build-consumer/develop-consumer-using-rpc.md b/java-chassis-reference/en_US/build-consumer/develop-consumer-using-rpc.md
index 1592bea..b308390 100644
--- a/java-chassis-reference/en_US/build-consumer/develop-consumer-using-rpc.md
+++ b/java-chassis-reference/en_US/build-consumer/develop-consumer-using-rpc.md
@@ -1,31 +1,47 @@
-## 概念阐述
-
-RPC开发方式允许用户通过在服务接口上标注注解来生成服务提供者代理,从而进行服务的调用。
+# 使用透明RPC方式开发服务消费者
-## 示例代码
+## 概念阐述
-只需要声明一个服务接口类型的成员,并且使用@RpcReference标注该成员,声明依赖的微服务及schemaId,即可进行服务调用,示例代码如下:
+透明RPC开发模式允许用户通过简单的java interface像本地调用一样进行服务调用。
+透明RPC仅仅是一种开发模式:
+* 与使用highway还是RESTful传输没有关联
+* 与producer使用透明RPC/Jax-RS还是SpringMVC模式开发没有关联
+* 也与producer代码是否实现这个interface没有关联。
+
+透明RPC开发模式与spring cloud的feign类似,不过更简单,因为不必在这个interface中增加任何RESTful annotation。
+## 在spring bean中通过@RpcReference声明
```java
@Component
-public class CodeFirstConsumerMain {
- @RpcReference(microserviceName = "codefirst", schemaId = "codeFirstHello")
- private static Hello hello;
-
- public static void main(String[] args) throws Exception {
- init();
- System.out.println(hello.sayHi("Java Chassis"));
- Person person = new Person();
- person.setName("ServiceComb/Java Chassis");
- System.out.println(hello.sayHello(person));
- }
-
- public static void init() throws Exception {
- Log4jUtils.init();
- BeanUtils.init();
- }
+public class SomeBean {
+ ......
+
+ @RpcReference(microserviceName = "helloService", schemaId = "helloSchema")
+ private Hello hello;
+
+ ......
}
```
+## 脱离spring bean,直接通过api声明
+```java
+Hello hello = Invoker.createProxy("helloService", "helloSchema", Hello.class);
+```
-在以上代码中,服务消费者已经取得了服务提供者的服务接口`Hello`,并在代码中声明一个`Hello`类型的成员。通过在`hello`上使用`@RPCReference`注解指明微服务名称和schemaId,ServiceComb框架可以在程序启动时从服务中心获取到对应的服务提供者实例信息,并且生成一个代理注入到hello中,用户可以像调用本地类一样调用远程服务。
+## reactive
+只需要使用jdk的CompletableFuture对返回值进行包装即可
+```java
+interface Hello {
+ CompletableFuture<String> sayHi(String name);
+}
+```
+同一个interface中,可以同时声明同一个方法的reactive和同步原型
+因为要求方法名与契约中的operationId一一对应,而仅有返回值类型不同,在java中是非法的,所以需要修改方法名,并通过swagger annotation来声明真正的operationId
+```java
+interface Hello {
+ String sayHi(String name);
+
+ @ApiOperation(nickname = "sayHi", value = "reactive method for sayHi")
+ CompletableFuture<String> asyncSayHi(String name);
+}
+```
diff --git a/java-chassis-reference/en_US/build-consumer/instance-isolation.md b/java-chassis-reference/en_US/build-consumer/instance-isolation.md
deleted file mode 100644
index ef940db..0000000
--- a/java-chassis-reference/en_US/build-consumer/instance-isolation.md
+++ /dev/null
@@ -1,29 +0,0 @@
-## 场景描述
-
-实例级故障隔离功能允许在微服务的部分实例调用失败时,停止向故障实例发送请求,从而达到隔离故障实例的功能。
-
-## 配置说明
-
-实例级故障隔离功能集成在负载均衡功能中,负载均衡策略的配置见[负载均衡策略](/build-provider/configuration/lb-strategy.md)。负载均衡策略中,与实例级故障隔离相关的配置项见下表。
-
-| 配置项 | 默认值 | 取值范围 | 是否必选 | 含义 | 注意 |
-| :--- | :--- | :--- | :--- | :--- | :--- |
-| servicecomb.loadbalance.isolation.enabled | false | Boolean | 否 | 是否开启故障实例隔离功能 | - |
-| servicecomb.loadbalance.isolation.continuousFailureThreshold | - | Integer | 否 | 当请求实例连续出错达到此阈值时触发实例隔离 | 若配置了此项则覆盖实例故障百分比的配置,否则按照实例故障百分比触发隔离。<br/>由于按请求错误率触发实例隔离在请求次数较多时不易触发也不易恢复,因此建议使用此配置项代替实例故障百分比配置。<br/>请求实例成功时会将连续错误次数请零以保证实例快速恢复。 |
-| servicecomb.loadbalance.isolation.enableRequestThreshold | 20 | Integer | 否 | 当实例的调用总次数达到该值时开始进入隔离逻辑门槛 | - |
-| servicecomb.loadbalance.isolation.errorThresholdPercentage | 20 | Integer,区间为\(0,100\] | 否 | 实例故障隔离错误百分比 | - |
-| servicecomb.loadbalance.isolation.singleTestTime | 10000 | Integer | 否 | 故障实例单点测试时间 | - |
-
-## 示例代码
-
-```yaml
-servicecomb:
- # other configuration omitted
- loadbalance:
- isolation:
- enabled: true
- singleTestTime: 5000
- continuousFailureThreshold: 5 # 调用某实例连续5次出错则隔离此实例
- strategy:
- name: RoundRobin
-```
diff --git a/java-chassis-reference/en_US/build-consumer/using-AsyncRestTemplate.md b/java-chassis-reference/en_US/build-consumer/using-AsyncRestTemplate.md
new file mode 100644
index 0000000..2152d81
--- /dev/null
+++ b/java-chassis-reference/en_US/build-consumer/using-AsyncRestTemplate.md
@@ -0,0 +1,61 @@
+# 使用AsynRestTemplate开发服务消费者
+
+## 概念阐述
+
+AsyncRestTemplate 开发方式允许用户异步的进行服务调用。具体的业务流程和 restTemplate 类似,只是这里以异步的形式进行服务的调用。
+
+## 示例代码
+
+AsyncRestTemplate 实例通过 new CseAsyncRestTemplate()来创建和获取,再使用该实例通过自定义的 URL 进行服务调用。
+
+* Spring MVC 客户端代码示例
+
+```java
+
+@Component
+public class SpringmvcConsumerMain {
+ private static final Logger LOG = LoggerFactory.getLogger(SpringmvcConsumerMain.class);
+
+ public static void main(String[] args) throws Exception {
+ init();
+ Person person = new Person();
+ person.setName("ServiceComb/Java Chassis");
+ //AsyncRestTemplate Consumer
+ CseAsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate();
+ ListenableFuture<ResponseEntity<String>> responseEntityListenableFuture = cseAsyncRestTemplate
+ .postForEntity("cse://springmvc/springmvchello/sayhi?name=Java Chassis", null, String.class);
+ ResponseEntity<String> responseEntity = responseEntityListenableFuture.get();
+ System.out.println("AsyncRestTemplate Consumer sayHi services: " + responseEntity.getBody());
+
+ HttpEntity<Person> entity = new HttpEntity<>(person);
+ ListenableFuture<ResponseEntity<String>> listenableFuture = cseAsyncRestTemplate
+ .exchange("cse://springmvc/springmvchello/sayhello", HttpMethod.POST, entity, String.class);
+ // ResponseEntity<String> responseEntity1 = listenableFuture.get();
+ // System.out.println("AsyncRestTemplate Consumer sayHello services: " + responseEntity1.getBody());
+ //设置回调函数
+ listenableFuture.addCallback(
+ new ListenableFutureCallback<ResponseEntity<String>>() {
+ @Override
+ public void onFailure(Throwable ex) {
+ LOG.error("AsyncResTemplate Consumer catched exception when sayHello, ", ex);
+ }
+
+ @Override
+ public void onSuccess(ResponseEntity<String> result) {
+ System.out.println("AsyncRestTemplate Consumer sayHello services: " + result.getBody());
+ }
+ });
+ }
+
+ public static void init() throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
+
+```
+
+> 说明 :
+>
+> * URL 的格式和 RestTemplate 一样,具体可以参考 restTemplate
+> * 这里用自定义的 ListenableFuture 类来作为占位符,获取远程调用结束后可能获取的结果。同时也可以自定义回调函数,对可能返回的结果进行分批处理。
diff --git a/java-chassis-reference/en_US/build-consumer/using-resttemplate.md b/java-chassis-reference/en_US/build-consumer/using-resttemplate.md
index 2b28d36..8f4528b 100644
--- a/java-chassis-reference/en_US/build-consumer/using-resttemplate.md
+++ b/java-chassis-reference/en_US/build-consumer/using-resttemplate.md
@@ -1,3 +1,5 @@
+# 使用RestTemplate开发服务消费者
+
## 概念阐述
RestTemplate是Spring提供的RESTful访问接口,ServiceComb提供该接口的实现类用于服务的调用。
@@ -10,6 +12,8 @@ RestTemplate是Spring提供的RESTful访问接口,ServiceComb提供该接口
RestTemplate实例通过调用`RestTemplateBuilder.create()`方法获取,再使用该实例通过自定义的URL进行服务调用,代码如下:
+* Spring MVC 客户端示例代码:
+
```java
@Component
public class SpringmvcConsumerMain {
@@ -34,10 +38,76 @@ public class SpringmvcConsumerMain {
}
```
+* JAX RS 客户端示例代码:
+
+```java
+
+@Component
+public class JaxrsConsumerMain {
+
+ public static void main(String[] args) throws Exception {
+ init();
+ //其他都类似spring MVC示例的客户端代码,注意如果服务端只接收 GET 请求,要使用方法 getForObject()
+ RestTemplate restTemplate = RestTemplateBuilder.create();
+ String result = restTemplate.getForObject("cse://jaxrs/jaxrshello/saybye", String.class);
+ }
+
+ public static void init() throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
+```
+
> 说明:
>
-> * URL格式为:`cse://microserviceName/path?querystring`。以[用SpringMVC开发微服务](/用SpringMVC开发微服务)中定义的服务提供者为例,其微服务名称是springmvc,basePath是`/springmvchello`,那么URL中的microserviceName=`springmvc`,请求sayhi时的path=`springmvchello/sayhi`,所以示例代码中请求sayhi的URL是`cse://springmvc/springmvchello/sayhi?name=Java Chassis`。
-> * 使用这种URL格式,ServiceComb框架会在内部进行服务发现、熔断容错等处理并最终将请求发送到服务提供者。
+> * URL格式为:`cse://microserviceName/path?querystring`。以[用SpringMVC开发微服务](/用SpringMVC开发微服务)中定义的服务提供者为例,其微服务名称是springmvc,basePath是`/springmvchello`,那么URL中的microserviceName=`springmvc`,请求sayhi时的path=`springmvchello/sayhi`,所以示例代码中请求sayhi的URL是`cse://springmvc/springmvchello/sayhi?name=Java Chassis`。具体代码示例如下 :
+
+
+```java
+@RestSchema(schemaId = "springmvcHello")
+@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON)
+//这里 path = “/springmvchello” 中的 springmvchello 就是 上述的basePath
+public class SpringmvcHelloImpl implements Hello {
+ @Override
+ @RequestMapping(path = "/sayhi", method = RequestMethod.POST)
+ public String sayHi(@RequestParam(name = "name") String name) {
+ return "Hello " + name;
+ }
+
+ @Override
+ @RequestMapping(path = "/sayhello", method = RequestMethod.POST)
+ public String sayHello(@RequestBody Person person) {
+ return "Hello person " + person.getName();
+ }
+}
+```
+> 下述代码是示例项目 [ SpringMVC ](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/springmvc-sample)的 springmvc-provider 模块 中 resources 目录下 microservice.yaml
+
+```yaml
+APPLICATION_ID: springmvc-sample
+service_description:
+ name: springmvc # 这里就是定义的微服务名称
+ version: 0.0.2
+servicecomb:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+ rest:
+ address: 0.0.0.0:8080
+ highway:
+ address: 0.0.0.0:7070
+ handler:
+ chain:
+ Provider:
+ default: bizkeeper-provider
+cse:
+ service:
+ registry:
+ address: http://127.0.0.1:30100 #service center address
+```
+
+> * 使用上述这种URL格式,ServiceComb框架会在内部进行服务发现、熔断容错等处理并最终将请求发送到服务提供者。
diff --git a/java-chassis-reference/en_US/build-consumer/with-contract.md b/java-chassis-reference/en_US/build-consumer/with-contract.md
index 4aec2bf..3cf5eaa 100644
--- a/java-chassis-reference/en_US/build-consumer/with-contract.md
+++ b/java-chassis-reference/en_US/build-consumer/with-contract.md
@@ -1,3 +1,5 @@
+# 使用服务契约
+
## 场景描述
当服务消费者调用服务提供者的服务时,需要注册服务契约。消费者有两种方式获取提供者的服务契约,一种是从服务的提供方离线获取契约文件,手工配置到项目中;另一种是从服务中心自动下载契约。
diff --git a/java-chassis-reference/en_US/build-provider/access-log-configuration.md b/java-chassis-reference/en_US/build-provider/access-log-configuration.md
index 775b945..15f7a64 100644
--- a/java-chassis-reference/en_US/build-provider/access-log-configuration.md
+++ b/java-chassis-reference/en_US/build-provider/access-log-configuration.md
@@ -31,33 +31,39 @@ _**Access log 配置项说明**_
### 日志格式配置
-目前可用的日志元素配置项见_**日志元素说明表**_。
+目前可用的日志元素配置项见 ***日志元素说明表(Apache & W3C)*** 和 ***日志元素说明表(ServiceComb)*** 。
-_**日志元素说明表**_
+_**日志元素说明表 (Apache & W3C)**_
| 元素名称 | Apache日志格式 | W3C日志格式 | 说明 |
| :--- | :--- | :--- | :--- |
-| Method | %m | cs-method | |
-| Status | %s | sc-status | |
-| Duration s | %T | - | |
-| Duration ms | %D | - | |
-| Remote Host | %h | - | |
-| Local Host | %v | - | |
-| Local port | %p | - | |
-| Bytes Written v1 | %B | - | 如果消息体长度为零则打印"0" |
-| Bytes Written v2 | %b | - | 如果消息体长度为零则打印"-" |
+| HTTP method | %m | cs-method | - |
+| HTTP status | %s | sc-status | - |
+| Duration in second | %T | - | - |
+| Duration in millisecond | %D | - | - |
+| Remote hostname | %h | - | - |
+| Local hostname | %v | - | - |
+| Local port | %p | - | - |
+| Size of response | %B | - | 如果消息体长度为零则打印"0" |
+| Size of response | %b | - | 如果消息体长度为零则打印"-" |
| First line of request | %r | - | 包含HTTP Method、Uri、Http版本三部分内容 |
-| URI path only | %U | cs-uri-stem | |
-| Query only | %q | cs-uri-query | |
-| URI path incl query | - | cs-uri | |
-| Version / Protocol | %H | - | |
-| Datetime Apache | %t | - | 按照默认设置打印时间戳,格式为"EEE, dd MMM yyyy HH:mm:ss zzz",语言为英文,时区为GMT |
-| Datetime Apache Configurable v1 | %{PATTERN}t | - | 按照指定的格式打印时间戳,语言为英文,时区为GMT |
-| Datetime Apache Configurable v2 | %{PATTERN|TIMEZONE|LOCALE}t | - | 按照指定的格式、语言、时区打印时间戳。允许省略其中的某部分配置(但两个分隔符号"|"不可省略)。 |
-| Incoming Headers | %{IDENTIFIER}i | - | 如果没有找到指定的header,则打印"-" |
-| Outgoing Response Headers | %{IDENTIFIER}o | - | 如果没有找到指定的header,则打印"-" |
-| Cookie | %{IDENTIFIER}c | - | 如果没有找到指定的cookie,则打印"-" |
-| TraceId | - | - | ServiceComb框架提供的TraceId打印元素,占位符格式为"%SCB-traceId" |
+| URI path | %U | cs-uri-stem | - |
+| Query string | %q | cs-uri-query | - |
+| URI path and query string | - | cs-uri | - |
+| Request protocol | %H | - | - |
+| Datetime the request is received | %t | - | 按照默认设置打印时间戳,格式为"EEE, dd MMM yyyy HH:mm:ss zzz",语言为英文,时区为GMT |
+| Configurable datetime the request is received | %{PATTERN}t | - | 按照指定的格式打印时间戳,语言为英文,时区为GMT |
+| Configurable datetime the request is received | %{PATTERN|TIMEZONE|LOCALE}t | - | 按照指定的格式、语言、时区打印时间戳。允许省略其中的某部分配置(但两个分隔符号"|"不可省略)。 |
+| Request header | %{VARNAME}i | - | 如果没有找到指定的header,则打印"-" |
+| Response header | %{VARNAME}o | - | 如果没有找到指定的header,则打印"-" |
+| Cookie | %{VARNAME}C | - | 如果没有找到指定的cookie,则打印"-" |
+
+_**日志元素说明表(ServiceComb)**_
+
+| Element | Placeholder | Comment |
+| :---- | :---------- | :------ |
+| TraceId | %SCB-traceId | 打印ServiceComb生成的trace id,找不到则打印"-" |
+| Invocation Context | %{VARNAME}SCB-ctx | 打印key为`VARNAME`的invocation context值,找不到则打印"-" |
### 日志输出文件配置
@@ -68,10 +74,10 @@ _**日志文件配置项**_
| 配置项 | 默认值 | 含义 | 说明 |
| :--- | :--- | :--- | :--- |
| paas.logs.accesslog.dir | ${paas.logs.dir} | 日志文件输出目录 | 与普通日志输出到同一个目录中 |
-| paas.logs.accesslog.file | access.log | 日志文件名 | |
-| log4j.appender.access.MaxBackupIndex | 10 | 最大保存的日志滚动文件个数 | |
+| paas.logs.accesslog.file | access.log | 日志文件名 | - |
+| log4j.appender.access.MaxBackupIndex | 10 | 最大保存的日志滚动文件个数 | - |
| log4j.appender.access.MaxFileSize | 20MB | 日志文件最大体积 | 正在记录的文件达到此大小时触发日志滚动存储 |
-| log4j.appender.access.logPermission | rw------- | 日志文件权限 | |
+| log4j.appender.access.logPermission | rw------- | 日志文件权限 | - |
> _**注意:**_
> 由于ServiceComb的日志打印功能只依赖slf4j的接口,因此用户可以选择其他日志打印框架,选择其他日志打印框架时需要用户自行配置日志文件输出选项。
@@ -136,6 +142,108 @@ _**日志文件配置项**_
</configuration>
```
+### 自定义扩展Access Log
+
+用户可以利用ServiceComb提供的AccessLogItem扩展机制,定制自己的AccessLogItem。
+
+#### 相关类说明
+
+1. `AccessLogItem`
+
+ ```java
+ public interface AccessLogItem<T> {
+ /**
+ * 从accessLogParam中获取特定的内容,组装成access log的打印内容并返回
+ */
+ String getFormattedItem(AccessLogParam<T> accessLogParam);
+ }
+ ```
+ `AccessLogItem`的定义如上所示,每一次请求触发Access Log打印时,ServiceComb的Access Log机制都会遍历有效的`AccessLogItem`,调用`getFormattedItem`方法获取此Item生成的Access Log片段,并将全部片段拼接成一条Access Log打印到日志文件中。
+ 参数`AccessLogParam<T>`包含请求开始时间、结束时间以及类型为`T`的请求上下文信息,在REST over Vertx通信方式中,类型`T`为Vert.x的`RoutingContext`。
+
+2. `VertxRestAccessLogItemMeta`
+
+ ```java
+ // pattern占位符前缀
+ protected String prefix;
+ // pattern占位符后缀
+ protected String suffix;
+ // 优先级序号
+ protected int order;
+ // AccessLogItem构造器
+ protected AccessLogItemCreator<RoutingContext> accessLogItemCreator;
+ ```
+ `VertxRestAccessLogItemMeta`包含如上属性,它定义了ServiceComb如何解析pattern字符串以获得特定的AccessLogItem。
+ - 如果用户想要定义一个占位符为`%user-defined`的`AccessLogItem`,则需要声明一个`VertxRestAccessLogItemMeta`的子类,设置prefix="%user-defined",suffix=null,当`AccessLogPatternParser`解析到"%user-defined"时,从此meta类中取得`AccessLogItemCreator`创建对应的`AccessLogItem`。**注意**:由于"%user-defined"占位符中没有变量部分,因此调用`AccessLogItemCreator`传入的配置参数为null。
+ - 如果用户想要定义一个占位符为`%{VARNAME}user-defined`的`AccessLogItem`,则声明的`VertxRestAccessLogItemMeta`子类中,设置prefix="%{",suffix="}user-defined",当`AccessLogPatternParser`解析到"%{VARNAME}user-defined"时,会截取出"VARNAME"作为配置参数传入`AccessLogItemCreator`,创建一个`AccessLogItem`。
+
+ `VertxRestAccessLogItemMeta`有一个子类`CompositeVertxRestAccessLogItemMeta`,当用户需要定义多个AccessLogItem时,可以将多个`VertxRestAccessLogItemMeta`聚合到`CompositeVertxRestAccessLogItemMeta`中。Parser加载到类型为`CompositeVertxRestAccessLogItemMeta`的AccessLogItemMeta时,会调用其`getAccessLogItemMetas()`方法获得一组AccessLogItemMeta。`VertxRestAccessLogItemMeta`使用SPI机制加载,而`CompositeVertxRestAccessLogItemMeta`可以让用户只在SPI配置文件中配置一条记录就加载多条meta信息,给了用户更灵活的选择。
+
+3. `AccessLogItemCreator`
+
+ ```java
+ public interface AccessLogItemCreator<T> {
+ // 接收配置值,返回一个AccessLogItem。如果AccessLogItem的占位符没有可变的配置值部分,则此方法会接收到null。
+ AccessLogItem<T> createItem(String config);
+ }
+ ```
+
+ 用户通过设置在自定义的`VertxRestAccessLogItemMeta`中的`AccessLogItemCreator`实例化自己的`AccessLogItem`。由于这是一个函数式接口,当`AccessLogItem`的初始化方式较简单时,可以直接使用Lambda表达式定义Creator,以简化开发。
+
+#### AccessLogItemMeta的匹配规则
+
+AccessLogItemMeta加载进Parser后,会进行一次排序。Parser解析pattern串时会从前到后匹配meta list,总的匹配规则如下:
+1. 优先匹配高优先级的meta。
+2. 优先匹配有后缀的meta,当匹配上多个有后缀meta时,取前后缀相距最小的一个。
+3. 优先匹配占位符长的meta,例如有两个meta,"%abc"和"%a",如果匹配中了"%abc"则直接返回,不再匹配"%a"。
+
+#### 示例说明
+
+1. 扩展自定义AccessLogItem
+
+ 首先用户需要`AccessLogItem`接口实现自己的item:
+ ```java
+ public class UserDefinedAccessLogItem implements AccessLogItem<RoutingContext> {
+ private String config;
+
+ public UserDefinedAccessLogItem(String config) {
+ this.config = config;
+ }
+
+ @Override
+ public String getFormattedItem(AccessLogParam<RoutingContext> accessLogParam) {
+ // 此处是用户自定义的逻辑,需要从AccessLogParam或其他地方取相关数据,生成并返回access log片段
+ return "user-defined-[" + config + "]-[" + accessLogParam.getStartMillisecond() + "]";
+ }
+ }
+ ```
+
+2. 定义AccessLogItem的meta类
+
+ 继承`VertxRestAccessLogItemMeta`或`CompositeVertxRestAccessLogItemMeta`类,定义AccessLogItem的前后缀等信息:
+ ```java
+ public class UserDefinedCompositeExtendedAccessLogItemMeta extends CompositeVertxRestAccessLogItemMeta {
+ private static final List<VertxRestAccessLogItemMeta> META_LIST = new ArrayList<>();
+
+ static {
+ META_LIST.add(new VertxRestAccessLogItemMeta("%{", "}user-defined", UserDefinedAccessLogItem::new));
+ }
+
+ @Override
+ public List<VertxRestAccessLogItemMeta> getAccessLogItemMetas() {
+ return META_LIST;
+ }
+ }
+ ```
+
+3. 配置SPI加载文件
+
+ 在`resources/META-INF/services/`目录下定义一个名为"org.apache.servicecomb.transport.rest.vertx.accesslog.parser.VertxRestAccessLogItemMeta"的文件,将上一步中定义的meta类完整类名填写到该文件中,供Parser加载meta类。
+
+4. 配置Access Log的pattern
+
+ 在microservice.yaml文件中的配置pattern,假设为"%{test-config}user-defined",运行服务触发Access Log打印,假设请求开始时间为1,则可以看到Access Log打印内容为"user-defined-[test-config]-[1]"。
+
## 示例代码
### microservice.yaml文件中的配置
@@ -159,6 +267,3 @@ log4j.appender.access.MaxBackupIndex=10
log4j.appender.access.MaxFileSize=20MB
log4j.appender.access.logPermission=rw-------
```
-
-
-
diff --git a/java-chassis-reference/en_US/build-provider/code-first.md b/java-chassis-reference/en_US/build-provider/code-first.md
index 37c01c3..e1a0ea2 100644
--- a/java-chassis-reference/en_US/build-provider/code-first.md
+++ b/java-chassis-reference/en_US/build-provider/code-first.md
@@ -1,3 +1,5 @@
+# 使用隐式契约
+
## 概念阐述
隐式契约是指ServiceComb根据服务实现类自动生成的服务契约。
diff --git a/java-chassis-reference/en_US/build-provider/configuration/lb-strategy.md b/java-chassis-reference/en_US/build-provider/configuration/lb-strategy.md
index 27a53b6..9028584 100644
--- a/java-chassis-reference/en_US/build-provider/configuration/lb-strategy.md
+++ b/java-chassis-reference/en_US/build-provider/configuration/lb-strategy.md
@@ -10,19 +10,20 @@ ServiceComb提供了基于Ribbon的负载均衡方案,用户可以通过配置
| 配置项 | 默认值 | 取值范围 | 是否必选 | 含义 | 注意 |
| :--- | :--- | :--- | :--- | :--- | :--- |
-| servicecomb.loadbalance.strategy.name | RoundRobin | RoundRobin(轮询)<br/>Random(随机)<br/>WeightedResponse(服务器响应时间权值)<br/>SessionStickiness(会话保持) | 否 | 负载均衡路由策略 | - |
-| servicecomb.loadbalance.SessionStickinessRule.sessionTimeoutInSeconds | 30 | Integer | 否 | 客户端闲置时间,超过限制后选择后面的服务器。 | 暂不支持微服务配置。e.g. servicecomb.loadbalance.SessionStickinessRule.sessionTimeoutInSeconds,不能配置为servicecomb.loadbalance.DemoService.SessionStickinessRule.sessionTimeoutInSeconds |
-| servicecomb.loadbalance.SessionStickinessRule.successiveFailedTimes | 5 | Integer | 否 | 客户端失败次数,超过后会切换服务器 | 暂不支持微服务配置 |
-| servicecomb.loadbalance.retryEnabled | FALSE | Boolean | 否 | 负载均衡捕获到服务调用异常,是否进行重试 | - |
-| servicecomb.loadbalance.retryOnNext | 0 | Integer | 否 | 尝试新的服务器的次数 | - |
-| servicecomb.loadbalance.retryOnSame | 0 | Integer | 否 | 同一个服务器尝试的次数 | - |
-| servicecomb.loadbalance.isolation.enabled | FALSE | Boolean | 否 | 是否开启故障实例隔离功能 | - |
-| servicecomb.loadbalance.isolation.enableRequestThreshold | 20 | Integer | 否 | 当实例的调用总次数达到该值时开始进入隔离逻辑门槛 | - |
-| servicecomb.loadbalance.isolation.continuousFailureThreshold | - | Integer | 否 | 当请求实例连续出错达到此阈值时触发实例隔离 | 若配置了此项则覆盖实例故障百分比的配置,否则按照实例故障百分比触发隔离。<br/>由于按请求错误率触发实例隔离在请求次数较多时不易触发也不易恢复,因此建议使用此配置项代替实例故障百分比配置。<br/>请求实例成功时会将连续错误次数请零以保证实例快速恢复。 |
-| servicecomb.loadbalance.isolation.errorThresholdPercentage | 20 | Integer,区间为\(0,100\] | 否 | 实例故障隔离错误百分比 | - |
-| servicecomb.loadbalance.isolation.singleTestTime | 10000 | Integer | 否 | 故障实例单点测试时间 | 单位为ms |
-| servicecomb.loadbalance.transactionControl.policy | org.apache.servicecomb.loadbalance.filter.SimpleTransactionControlFilter | - | 否 | 动态路由分流策略 | 框架提供了简单的分流机制,开发者也可以实现自定义的分流过滤策略 |
-| servicecomb.loadbalance.transactionControl.options | - | key/value pairs | 否 | 针对SimpleTransactionControlFilter分流策略的配置项,可添加任意项过滤标签 | - |
+| servicecomb.loadbalance.\[服务名\].strategy.name | RoundRobin | RoundRobin(轮询)<br/>Random(随机)<br/>WeightedResponse(服务器响应时间权值)<br/>SessionStickiness(会话保持) | 否 | 负载均衡路由策略 | - |
+| servicecomb.loadbalance.\[服务名\].SessionStickinessRule.sessionTimeoutInSeconds | 30 | Integer | 否 | 客户端闲置时间,超过限制后选择后面的服务器。 | - |
+| servicecomb.loadbalance.\[服务名\].SessionStickinessRule.successiveFailedTimes | 5 | Integer | 否 | 客户端失败次数,超过后会切换服务器 | - |
+| servicecomb.loadbalance.\[服务名\].retryEnabled | FALSE | Boolean | 否 | 负载均衡捕获到服务调用异常,是否进行重试 | - |
+| servicecomb.loadbalance.\[服务名\].retryOnNext | 0 | Integer | 否 | 尝试新的服务器的次数 | - |
+| servicecomb.loadbalance.\[服务名\].retryOnSame | 0 | Integer | 否 | 同一个服务器尝试的次数 | - |
+| servicecomb.loadbalance.\[服务名\].isolation.enabled | FALSE | Boolean | 否 | 是否开启故障实例隔离功能 | - |
+| servicecomb.loadbalance.\[服务名\].isolation.enableRequestThreshold | 20 | Integer | 否 | 当实例的调用总次数达到该值时开始进入隔离逻辑门槛 | - |
+| servicecomb.loadbalance.\[服务名\].isolation.continuousFailureThreshold | - | Integer | 否 | 当请求实例连续出错达到此阈值时触发实例隔离 | 若配置了此项则覆盖实例故障百分比的配置,否则按照实例故障百分比触发隔离。<br/>由于按请求错误率触发实例隔离在请求次数较多时不易触发也不易恢复,因此建议使用此配置项代替实例故障百分比配置。<br/>请求实例成功时会将连续错误次数请零以保证实例快速恢复。 |
+| servicecomb.loadbalance.\[服务名\].isolation.errorThresholdPercentage | 20 | Integer,区间为\(0,100\] | 否 | 实例故障隔离错误百分比 | - |
+| servicecomb.loadbalance.\[服务名\].isolation.singleTestTime | 10000 | Integer | 否 | 故障实例单点测试时间 | 单位为ms |
+
+**说明**:
+- 以上配置项都支持全局和微服务两个粒度的配置。例如:servicecomb.loadbalance.strategy.name是全局的负载均衡路由策略;servicecomb.loadbalance.DemoService.strategy.name是仅在调用DemoService服务时生效的负载均衡路由策略。
## 示例代码
diff --git a/java-chassis-reference/en_US/build-provider/configuration/ratelimite-strategy.md b/java-chassis-reference/en_US/build-provider/configuration/ratelimite-strategy.md
index b503f04..5d4dca5 100644
--- a/java-chassis-reference/en_US/build-provider/configuration/ratelimite-strategy.md
+++ b/java-chassis-reference/en_US/build-provider/configuration/ratelimite-strategy.md
@@ -6,7 +6,7 @@
1. 限流策略的控制并不是绝对精确的,可能会有少量误差。
2. provider端的流量控制是业务层面的功能,不是安全意义上的流量控制,如需防止DDoS攻击,需要结合其他的一系列措施。
-3. 流量控制是微服务级的,不是进程级的。
+3. 流量控制是微服务级的,不是实例级的。例如一个consumer服务有三个实例,当对它们依赖的provider实例配置限流策略后,provider不会区分consumer的请求具体是由哪个实例发出的,而是汇总成微服务级的统计数据进行限流判断。
## 配置说明
@@ -39,4 +39,3 @@
> **注意:**
> provider端限流策略配置中的`ServiceName`指的是调用该provider的consumer,而`shema`、`operation`指的是provider自身的。即provider端限流配置的含义是,限制指定consumer调用本provider的某个schema、operation的流量。
-
diff --git a/java-chassis-reference/en_US/build-provider/define-contract.md b/java-chassis-reference/en_US/build-provider/define-contract.md
index 7e6cccc..e653c7e 100644
--- a/java-chassis-reference/en_US/build-provider/define-contract.md
+++ b/java-chassis-reference/en_US/build-provider/define-contract.md
@@ -1,6 +1,17 @@
+# 定义服务契约
+``
## 概念阐述
-服务契约,指基于OpenAPI规范的微服务接口契约,是服务端与消费端对于接口的定义。java chassis提供了两种方式定义契约:显示和隐式。显示契约用于开发者使用RPC方式开发代码,然后期望内部程序客户端使用RPC方式访问,同时期望浏览器、手机终端等通过HTTP访问后台接口场景,显示契约需要开发者在yaml文件中描述接口的访问方式。隐式契约中的契约完全由框架根据默认规则(对于RPC方式)或者Annotation(Spring MVC和JAX RS方式)来生成运行时的契约,不需要准备单独的yaml文件。
+服务契约,指基于OpenAPI规范的微服务接口契约,是服务端与消费端对于接口的定义。java chassis提供了两种方式定义契约:code first和contract first。
+* code first
+
+producer使用Jax-RS或SpringMVC的RESTful annotation声明接口的输入、输出参数,或者再配合OpenAPI的annotation,增加人类可读的信息,比如样例代码、文本描述等等;ServiceComb引擎启动时,根据这些annotation生成契约描述,并自动上传到服务中心。producer也可以使用透明RPC方式开发,但是因为没有任何RESTful的annotation指导如何生成契约,所以此时自动生成的契约非常的不RESTful化,不建议使用。
+consumer使用透明RPC或RestTemplate进行调用。
+code first的开发模式下,开发人员,不必手写契约。
+
+* contract first
+
+此场景下,不使用框架自动生成的契约,而是直接使用开发人员提供的契约文件,这需要由开发人员保证契约与代码的一致性。
## 场景描述
@@ -93,7 +104,10 @@ definitions:
> **注意**:
>
-> * 根据swagger标准,basePath配置的路径需要包括web server的webroot。
+> * ServiceComb中的契约,建议basePath不要包含web container的web root,以及servlet的url pattern。
+
+因为ServiceComb支持部署解耦,既可以脱离servlet container独立部署,也可使用war的方式部署到servlet container中,还可以使用embedded servlet container的方式运行。
+只要base path不包含web root以及url pattern,则部署方式修改导致的实际url变更,ServiceComb consumer业务代码并不需要感知,框架会自动适配。
> * info.x-java-interface需要标明具体的接口路径,根据项目实际情况而定。
> * SchemaId中可以包含"."字符,但不推荐这样命名。这是由于ServiceComb使用的配置文件是yaml格式的,"."符号用于分割配置项名称,如果SchemaId中也包含了"."可能会导致一些支持契约级别的配置无法正确被识别。
> * OperationId的命名中不可包含"."字符。
diff --git a/java-chassis-reference/en_US/build-provider/definition/isolate-relationship.md b/java-chassis-reference/en_US/build-provider/definition/isolate-relationship.md
index 5777c38..375bfca 100644
--- a/java-chassis-reference/en_US/build-provider/definition/isolate-relationship.md
+++ b/java-chassis-reference/en_US/build-provider/definition/isolate-relationship.md
@@ -8,7 +8,7 @@
![](/assets/sc-meta.png)
-在微服务系统结构中,顶层是“项目”,在项目下分为多个租户,租户中包含多个应用,而每个应用由包含多个环境,即测试和生产环境可以分开。在某个特定应用的特定环境中,包含多个微服务,而一个微服务又可以同时存在多个版本。以上,是所有静态元数据的范畴,某个特定服务的特定版本则包含多个在运行时注册上来的微服务实例,因为服务实例的信息在运行时随着系统的伸缩、故障等原因是动态变化的,所以服务实例的路由信息又为动态数据。通过分层管理微服务的这些数据,也就自然而然的实现了实例之间的逻辑隔离。
+在微服务系统结构中,顶层是“项目”,在项目下分为多个租户,租户中包含多个应用,而每个应用又包含多个环境,即测试和生产环境可以分开。在某个特定应用的特定环境中,包含多个微服务,而一个微服务又可以同时存在多个版本。以上,是所有静态元数据的范畴,某个特定服务的特定版本则包含多个在运行时注册上来的微服务实例,因为服务实例的信息在运行时随着系统的伸缩、故障等原因是动态变化的,所以服务实例的路由信息又为动态数据。通过分层管理微服务的这些数据,也就自然而然的实现了实例之间的逻辑隔离。
# 隔离层次说明
@@ -28,11 +28,10 @@ ServiceComb支持自定义分层配置,满足用户的实例分层管理需求
```
servicecomb:
- loadbalance:
- serverListFilters: zoneaware
- serverListFilter:
- zoneaware:
- className: org.apache.servicecomb.loadbalance.filter.ZoneAwareServerListFilterExt
+ datacenter:
+ name: mydatacenter
+ region: my-Region
+ availableZone: my-Zone
```
这样配置后,客户端在路由的时候,会优先将请求转发到zone/region都相同的实例,然后是region相同,但zone不相同的实例,都不相同的时候,则按照路由规则选择一个。亲和性不是逻辑隔离,只要实例之间网络是联通的,那么都有可能访问到;如果网络不通,则会访问失败。
diff --git a/java-chassis-reference/en_US/build-provider/definition/service-definition.md b/java-chassis-reference/en_US/build-provider/definition/service-definition.md
index 1c21959..82da8b3 100644
--- a/java-chassis-reference/en_US/build-provider/definition/service-definition.md
+++ b/java-chassis-reference/en_US/build-provider/definition/service-definition.md
@@ -26,7 +26,6 @@
> 说明:
>
> * 服务的元数据会随服务一同注册到服务中心,如需修改,则要连同服务version一起变更。若想保持服务version不变,则需要通过服务管理中心统一变更元数据。
-> * 默认情况下,微服务只支持同一个app内部的服务调用。可在微服务的properties中配置allowCrossApp=true属性,开启可被跨app访问权限。
> * 虽然微服务名、契约名中可以使用"."字符,但是不推荐在命名中使用"."。这是由于ServiceComb使用的配置文件是yaml格式的,"."符号用于分割配置项名称,如果微服务名、契约名中也包含了"."可能会导致一些支持微服务、契约级别的配置无法正确被识别。
### 示例代码
@@ -46,6 +45,3 @@ instance_description: #实例描述
key3: value3
propertyExtentedClass: org.apache.servicecomb.serviceregistry.MicroServicePropertyExtendedStub
```
-
-
-
diff --git a/java-chassis-reference/en_US/build-provider/interface-constraints.md b/java-chassis-reference/en_US/build-provider/interface-constraints.md
index f260af3..48a693d 100644
--- a/java-chassis-reference/en_US/build-provider/interface-constraints.md
+++ b/java-chassis-reference/en_US/build-provider/interface-constraints.md
@@ -1,6 +1,8 @@
-## 接口约束说明
+# 接口定义和数据类型
-ServiceComb-Java-Chassis对于接口的使用约束建立在一个简单的原则上:接口定义即接口使用说明,不用通过查看代码实现,就能识别如何调用这个接口。可以看出,我们是站在使用者这边的,以更容易被使用作为参考。这个原则,不同的开发者的理解也是有差异的。
+## 接口定义的要求
+
+ServiceComb-Java-Chassis建议接口定义遵循一个简单的原则:接口定义即接口使用说明,不用通过查看代码实现,就能识别如何调用这个接口。可以看出,这个原则站在使用者这边,以更容易被使用作为参考。ServiceComb会根据接口定义生成接口契约,符合这个原则的接口,生成的契约也是用户容易阅读的。
举个例子:
@@ -12,7 +14,7 @@ public class Person {String name;}
显然调用接口一,我们知道要传递一个String类型的id参数,返回值是一个Person类型,Person里面存在String类型的name参数。调用接口二,我们不知道怎么处理返回值,必须参考服务提供者的文档说明。这个视角是熟练的RPC开发者的视角。
-当我们要将接口发布为REST接口的时候,可以通过使用swagger文件,指定id使用RequestParam或者PathVariable或者RequestBody进行传递,也可以使用SpringMVC或者JAX RS提供的标签来描述。
+当我们要将接口发布为REST接口的时候,可以指定接口参数和HTTP协议的映射关系,比如:
```java
public Person query(@RequestParam String id);
@@ -31,13 +33,16 @@ ResponseType methodName(RequestType...)
不能定义异常、不能包含在接口原型未声明的错误码和输出(如果没声明错误码,缺省的错误码除外,比如HTTP 的200)。
-通常,系统约束越多,那么就更加容易对系统进行统一的管控和治理;开发方式越自由,实现业务功能则更加快速。需要在这两方面取得一些平衡。ServiceComb-Java-Chassis是比gRPC要灵活的多的框架,同时也去掉了Spring MVC的一些不常用的扩展。开发者可以在ServiceComb-Java-Chassis讨论区反馈开发过程中期望支持的场景,更好的维护这个平衡。期望这个讨论是围绕某个具体的应用场景来进行的,比如上传文件如何更好的进行,而不是具体的开发方式进行的,比如使用Object来传递参数。
+通常,系统约束越多,那么就更加容易对系统进行统一的管控和治理;开发方式越自由,实现业务功能则更加快速,需要在这两方面取得一些平衡。ServiceComb-Java-Chassis是比gRPC要灵活很多的框架,同时也去掉了Spring MVC的一些不常用的扩展。开发者可以在ServiceComb-Java-Chassis讨论区反馈开发过程中期望支持的场景,更好的维护这个平衡。期望这个讨论是围绕某个具体的应用场景来进行的,比如上传文件如何更好的进行,而不是具体的开发方式进行的,比如使用Object来传递参数。
## 详细的约束列表
开发者不能在接口定义的时候使用如下类型:
* 抽象的数据结构: java.lang.Object, net.sf.json.JsonObject等
+
+ **备注:** 最新版本可以使用java.lang.Object作为参数和返回值。它的运行时类型可以是int、String、Map等。尽管如此,建议开发者不要使用抽象数据结构,以及第三方提供的非POJO类作为接口的参数和返回值。这些类型包括java.math.BigDecimal、org.joda.time.JodaTime等。这些类型会给开发者带来很大的困扰。比如开发者可能以为BidDecimal会以数字传输,实际不然,并且在某些内部状态没正确计算的情况下,得到的并不是用户预期的值。
+
* 接口或者抽象类
```java
public interface IPerson {//...}
@@ -54,10 +59,47 @@ ResponseType methodName(RequestType...)
开发者不用担心记不住这些约束,程序会在启动的时候检查不支持的类型,并给与错误提示。
-除了上面一些类型,开发者尽可能不要使用一些包含特殊内部状态的类型,这些类型会给开发者代码很大的困扰。比如java.math.BigDecimal,开发者可能以为他会以一个数字传输,实际不然,并且在某些内部状态没正确计算的情况下,得到的并不是用户预期的值。
-
总之,数据结构需要能够使用简单的数据类型进行描述,一目了然就是最好的。这个在不同的语言,不同的协议里面都支持的很好,长期来看,可以大大减少开发者联调沟通和后期重构的成本。
+### 关于数据结构和接口变更
+接口名称、参数类型、参数顺序、返回值类型变更都属于接口变更。ServiceComb启动的时候,会根据版本号检测接口变化,接口变化要求修改版本号。ServiceComb识别接口是否变化是通过代码生成的契约内容,有些不规范的接口定义可能导致在代码没有变化的情况下,生成的契约不同。比如:
+
+```
+public void get(Person p)
+class Person {
+ private String value;
+ private boolean isOk;
+ public String getName() {return value}
+ public boolean isOk() {return isOK}
+}
+```
+
+这个接口通过access method定义了"name"和"ok"两个属性,和实际的字段"value"和"isOk"不同。这种情况可能导致每次启动生成的契约不一样。需要将代码调整为符合JAVA Bean规范的定义。
+```
+public void get(Person p)
+class Person {
+ private String name;
+ private boolean ok;
+ public String getName() {return name}
+ public boolean isOk() {return ok}
+}
+```
+
+或者通过JSON标注,显示的指明字段顺序。比如:
+
+```
+public void get(Person p)
+@JsonPropertyOrder({"name", "ok"})
+class Person {
+ private String value;
+ private boolean isOk;
+ public String getName() {return value}
+ public boolean isOk() {return isOK}
+}
+```
+
+考虑到接口变更的影响,建议在进行对外接口定义的时候,尽可能不要使用第三方软件提供的类作为接口参数,而是使用自定义的POJO类。一方面升级三方件的时候,可能感知不到接口变化;另外一方面,如果出现问题,无法通过修改第三方代码进行规避。比如:java.lang.Timestamp, org.joda.time.JodaTime等。
+
## 协议上的差异
尽管ServiceComb-Java-Chassis实现了不同协议之间开发方式的透明,受限于底层协议的限制,不同的协议存在少量差异。
@@ -102,3 +144,17 @@ public Generic getHolderListArea() {
> ***说明:***
> 虽然 ServiceComb-Java-Chassis 支持REST泛型参数,但是我们更加推荐用户使用实体类作为参数,以获得更加明确的接口语义。
+
+## 其他常见问题
+
+* 使用RestTemplate传递raw json
+假设服务端定义了接口
+```
+Person test(Person input)
+```
+用户期望使用RestTemplate自行拼接json字符串,然后进行传递:
+```
+ String personStr = JsonUtils.writeValueAsString(input);
+ result = template.postForObject(cseUrlPrefix + "sayhello", personStr, Person.class);
+```
+ServiceComb不推荐开发者这样使用,里面的处理逻辑存在大量歧义。如果必须使用,需要满足几个约束:Person必须包含带String类型的构造函数;provider/consumer都必须存在这个Person类型。
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/build-provider/jaxrs.md b/java-chassis-reference/en_US/build-provider/jaxrs.md
index 8308d07..b004e33 100644
--- a/java-chassis-reference/en_US/build-provider/jaxrs.md
+++ b/java-chassis-reference/en_US/build-provider/jaxrs.md
@@ -1,6 +1,7 @@
+# 用JAX-RS开发微服务
## 概念阐述
-ServiceComb支持开发者使用JAX-RS注解,使用JAX-RS模式开发服务。
+ServiceComb支持开发者使用JAX-RS注解,使用[JAX-RS](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/jaxrs-sample)模式开发服务。
## 开发示例
@@ -39,6 +40,15 @@ public class JaxrsHelloImpl implements Hello {
public String sayHello(Person person) {
return "Hello person " + person.getName();
}
+ /**
+ * 这个方法是实现类特有的,因此对它的远程调用会有所不同.
+ * 具体可以参考 jaxrs-consumer
+ */
+ @Path("/saybye")
+ @GET
+ public String sayBye() {
+ return "Bye !";
+ }
}
```
@@ -58,6 +68,18 @@ public class JaxrsHelloImpl implements Hello {
</beans>
```
+### 步骤 4启动服务。
+
+```
+public class JaxrsProviderMain{
+
+ public static void main(String[] args) throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
+```
+
## 涉及API
JAX-RS开发模式当前支持如下注解,所有注解的使用方法参考[JAX-RS官方文档](https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/index.html)。
@@ -76,11 +98,101 @@ JAX-RS开发模式当前支持如下注解,所有注解的使用方法参考[J
| javax.ws.rs.PathParam | parameter | 从path中获取参数,必须在path中定义该参数 |
| javax.ws.rs.HeaderParam | parameter | 从header中获取参数 |
| javax.ws.rs.CookieParam | parameter | 从cookie中获取参数 |
+| javax.ws.rs.FormParam | parameter | 从form中获取参数 |
+| javax.ws.rs.BeanParam | parameter | 用于参数聚合,允许在一个JavaBean的属性上打上参数标记以将多个参数聚合为一个JavaBean |
> **说明:**
>
-> * 当方法参数没有注解,且不为HttpServletRequest类型参数时,默认为body类型参数,一个方法只支持最多一个body类型参数。
-> * 打在参数上面的注解建议显式定义出value值,否则将直接使用契约中的参数名,例如应该使用`@QueryParam\("name"\) String name`,而不是`@QueryParam String name`。
+> * 当方法参数没有注解,且不为`HttpServletRequest`、`InvocationContext`类型参数时,默认为body类型参数,一个方法最多只支持一个body类型参数。
+
+## 使用@BeanParam聚合参数
+
+### 使用说明
+
+用户可以使用@BeanParam注解将多个参数聚合到一个JavaBean中,通过将@QueryParam等参数注解打在此JavaBean的属性或setter方法上来声明参数,从而简化业务接口的参数表。可以参考JAX-RS的官方说明:https://docs.oracle.com/javaee/7/api/javax/ws/rs/BeanParam.html
+
+ServiceComb现在也支持类似的用法,该用法的要求如下:
+1. 聚合参数所用的类型必须是标准的JavaBean,即类型的属性与getter、setter方法名称匹配,setter方法的返回类型为`void`
+2. 参数注解可以打在JavaBean的属性或setter方法上
+3. 允许通过@FormParam将多个上传文件参数聚合到JavaBean中
+4. 作为BeanParam的JavaBean内部如果有多余的属性,需要打上`@JsonIgnore`忽略掉
+5. body参数无法聚合进BeanParam
+6. Consumer端不支持将参数聚合为JavaBean发送,即仍然需要按照接口契约单独填写各个参数
+### 代码示例
+#### Provider端开发服务
+- Provider端业务接口代码:
+```java
+ @RestSchema(schemaId = "helloService")
+ @Path("/hello")
+ public class HelloService {
+ @Path("/sayHello/{name}")
+ @GET
+ public String sayHello(@BeanParam Person person) {
+ System.out.println("sayHello is called, person = [" + person + "]");
+ return "Hello, your name is " + person.getName() + ", and age is " + person.getAge();
+ }
+ }
+```
+- BeanParam参数定义:
+```java
+ public class Person {
+ private String name;
+ @QueryParam("age")
+ private int age;
+ @PathParam("name")
+ public void setName(String name) {
+ this.name = name;
+ }
+ @JsonIgnore // 忽略复杂属性
+ private List<Person> children;
+
+ // 其他方法忽略
+ }
+```
+- 接口契约:
+```yaml
+# 忽略契约的其他部分
+basePath: "/hello"
+paths:
+ /sayHello/{name}:
+ get:
+ operationId: "sayHello"
+ parameters:
+ - name: "name"
+ in: "path"
+ required: true
+ type: "string"
+ - name: "age"
+ in: "query"
+ required: false
+ type: "integer"
+ format: "int32"
+ responses:
+ 200:
+ description: "response of 200"
+ schema:
+ type: "string"
+```
+
+#### Consumer端调用服务
+
+- consumer端RPC开发模式:
+ - Provider接口定义
+ ```java
+ public interface HelloServiceIntf {
+ String sayHello(String name, int age);
+ }
+ ```
+ - 调用代码
+ ```java
+ String result = helloService.sayHello("Bob", 22); // result的值为"Hello, your name is Bob, and age is 22"
+ ```
+- consumer端RestTemplate开发模式:
+ ```java
+ String result = restTemplate.getForObject(
+ "cse://provider-service/hello/sayHello/Bob?age=22",
+ String.class); // 调用效果与RPC方式相同
+ ```
diff --git a/java-chassis-reference/en_US/build-provider/listen-address-and-publish-address.md b/java-chassis-reference/en_US/build-provider/listen-address-and-publish-address.md
index 0a397ac..a31cd66 100644
--- a/java-chassis-reference/en_US/build-provider/listen-address-and-publish-address.md
+++ b/java-chassis-reference/en_US/build-provider/listen-address-and-publish-address.md
@@ -1,3 +1,5 @@
+# 服务监听地址和发布地址
+
### 概念阐述
在JavaChassis中,服务的监听地址和发布地址是两个独立的概念,可以独立配置:
@@ -22,7 +24,7 @@
| 2 | 0.0.0.0 | - | 选取一张网卡的IP地址作为发布地址。<br/>要求该地址不能是通配符地址、回环地址或广播地址 |
| 3 | 具体IP | - | 与监听地址一致 |
| 4 | * | 具体IP | 与发布地址配置项一致 |
-| 5 | * | "{网卡名}" | 指定网卡名的IP |
+| 5 | * | "{网卡名}" | 指定网卡名的IP,注意需要加上引号和括号 |
> **说明:**
> - 服务实例实际监听的地址始终与监听地址配置项保持一致。
@@ -35,7 +37,7 @@ microservice.yaml文件的配置示例如下:
```yaml
servicecomb:
service:
- publishAddress: "eth0" # 注册到服务中心的发布地址会是eth0网卡的IP
+ publishAddress: "{eth0}" # 注册到服务中心的发布地址会是eth0网卡的IP
rest:
address: 0.0.0.0:8080 # 监听主机的全部网卡IP
highway:
diff --git a/java-chassis-reference/en_US/build-provider/protocol.md b/java-chassis-reference/en_US/build-provider/protocol.md
index a4b2ea7..6e28c80 100644
--- a/java-chassis-reference/en_US/build-provider/protocol.md
+++ b/java-chassis-reference/en_US/build-provider/protocol.md
@@ -1,12 +1,5 @@
+# 通信协议
+
### 概念阐述
ServiceComb实现了两种网络通道,包括REST和Highway,均支持TLS加密传输。其中,REST网络通道将服务以标准RESTful形式发布,调用端兼容直接使用http client使用标准RESTful形式进行调用。
-
-### 注意事项
-
-参数和返回值的序列化:
-
-当前REST通道的body参数只支持application/json序列化方式,如果要向服务端发送form类型的参数,那么需要在调用端构造好application/json格式的body,不能直接以multipart/form-data格式传递form类型参数。
-
-当前REST通道返回值支持application/json和text/plain两种格式,服务提供者通过produces声明可提供序列化能力,服务消费者通过请求的Accept头指明返回值序列化方式,默认返回application/json格式的数据。
-
diff --git a/java-chassis-reference/en_US/security/http2.md b/java-chassis-reference/en_US/build-provider/protocol/http2.md
similarity index 60%
rename from java-chassis-reference/en_US/security/http2.md
rename to java-chassis-reference/en_US/build-provider/protocol/http2.md
index f2babf3..1998f13 100644
--- a/java-chassis-reference/en_US/security/http2.md
+++ b/java-chassis-reference/en_US/build-provider/protocol/http2.md
@@ -7,25 +7,25 @@
与外部服务通信相关的配置写在microservice.yaml文件中。
* 启用h2\(Http2 + TLS\)进行通信
- 服务端在配置服务监听地址时,可以通过在地址后面追加`?sslEnabled=true`开启TLS通信,具体介绍见[使用TLS通信](https://huawei-servicecomb.gitbooks.io/developerguide/content/security/tls.html "使用TLS通信")章节。然后再追加`&protocol=h2`启用h2通信。示例如下:
+ 服务端在配置服务监听地址时,可以通过在地址后面追加`?sslEnabled=true`开启TLS通信,具体介绍见[使用TLS通信](../../security/tls.md)章节。然后再追加`&protocol=http2`启用h2通信。示例如下:
```yaml
servicecomb:
rest:
- address: 0.0.0.0:8080?sslEnabled=true&protocol=h2
+ address: 0.0.0.0:8080?sslEnabled=true&protocol=http2
highway:
- address: 0.0.0.0:7070?sslEnabled=true&protocol=h2
+ address: 0.0.0.0:7070?sslEnabled=true&protocol=http2
```
* 启用h2c\(Http2 without TLS\)进行通信
- 服务端在配置服务监听地址时,可以通过在地址后面追加`?protocol=h2`启用h2c通信。示例如下:
+ 服务端在配置服务监听地址时,可以通过在地址后面追加`?protocol=http2`启用h2c通信。示例如下:
```yaml
servicecomb:
rest:
- address: 0.0.0.0:8080?protocol=h2
+ address: 0.0.0.0:8080?protocol=http2
highway:
- address: 0.0.0.0:7070?protocol=h2
+ address: 0.0.0.0:7070?protocol=http2
```
* 客户端会通过从服务中心读取服务端地址中的配置来使用http2进行通信。
diff --git a/java-chassis-reference/en_US/build-provider/protocol/rest-over-servlet.md b/java-chassis-reference/en_US/build-provider/protocol/rest-over-servlet.md
index e4795b6..5e08543 100644
--- a/java-chassis-reference/en_US/build-provider/protocol/rest-over-servlet.md
+++ b/java-chassis-reference/en_US/build-provider/protocol/rest-over-servlet.md
@@ -1,3 +1,5 @@
+# REST over Servlet
+
## 配置说明
REST over Servlet对应使用web容器模式部署运行,需要新建一个servlet工程将微服务包装起来,加载到web容器中启动运行,包装微服务的方法有两种,一种完全使用web.xml配置文件配置,另一种仅在web.xml文件中配置listener,在microservice.yaml文件中配置urlPattern,两种方式任选一种即可,配置方式如下所示:
@@ -112,5 +114,14 @@ servicecomb:
timeout: 3000
```
+## 对外发布的Path
+由于将应用部署到Servlet,Servlet会在用户访问的URL上追加context和servlet pattern,比如/mywebapp/rest。在接口定义的时候声明path=/appliation,实际用户需要通过/mywebapp/rest/application来访问服务。通过ServiceComb的API,可以屏蔽部署差异,使用者可以使用一致的URL来访问,比如: restTemplate.getForObject("cse://serviceName/application"...)。因此后续用户将应用改造为独立部署,或者修改context,使用者的代码都可以不需要修改。
+
+对于一些遗留系统改造,用户期望继续使用restTemplate.getForObject("cse://serviceName/mywebapp/rest/application"...),这个时候,用户必须将接口定义的path定位为: /mywebapp/rest/application,例如:
+```
+@RestSchema(schemaId = "test")
+@RequestMapping(path = "/mywebapp/rest/application")
+```
+尽管如此,仍然推荐使用部署形态无关的方式来编码,可以减少后续由于部署形态变化,带来的频繁修改客户端代码问题。
diff --git a/java-chassis-reference/en_US/build-provider/protocol/thread-model.md b/java-chassis-reference/en_US/build-provider/protocol/thread-model.md
index 9d9e594..c8787d2 100644
--- a/java-chassis-reference/en_US/build-provider/protocol/thread-model.md
+++ b/java-chassis-reference/en_US/build-provider/protocol/thread-model.md
@@ -22,4 +22,4 @@ servicecomb:
executors:
Provider:
[schemaId].[operation]
-```
+```
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/build-provider/service-configuration.md b/java-chassis-reference/en_US/build-provider/service-configuration.md
index e69de29..bf7f433 100644
--- a/java-chassis-reference/en_US/build-provider/service-configuration.md
+++ b/java-chassis-reference/en_US/build-provider/service-configuration.md
@@ -0,0 +1,14 @@
+## [负载均衡策略](/build-provider/configuration/lb-strategy.html)
+• ServiceComb提供了基于Ribbon的负载均衡方案,用户可以通过配置文件配置负载均衡策略,当前支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略## [Service Center](https://github.com/apache/incubator-servicecomb-saga){:target="_blank"}
+
+## [限流策略](/build-provider/configuration/ratelimite-strategy.html)
+• 用户在provider端使用限流策略,可以限制指定微服务向其发送请求的频率,达到限制每秒钟最大请求数量的效果。
+
+
+## [降级策略](/build-provider/configuration/parameter-validator.html)
+• 降级策略是当服务请求异常时,微服务所采用的异常处理策略。
+
+
+## [参数效验](/build-provider/configuration/parameter-validator.html)
+• 用户在provider端使用参数效验,可以对相应的参数输入要求预先进行设置,在接口实际调用前进行效验处理,达到控制参数输入标准的效果。
+
diff --git a/java-chassis-reference/en_US/build-provider/springmvc.md b/java-chassis-reference/en_US/build-provider/springmvc.md
index 94b616b..9f24be5 100644
--- a/java-chassis-reference/en_US/build-provider/springmvc.md
+++ b/java-chassis-reference/en_US/build-provider/springmvc.md
@@ -1,6 +1,8 @@
+# 用SpringMVC 开发微服务
+
## 概念阐述
-ServiceComb支持SpringMVC注解,允许使用SpringMVC风格开发微服务。
+ServiceComb支持SpringMVC注解,允许使用SpringMVC风格开发微服务。建议参照着项目 [SpringMVC](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/springmvc-sample)进行详细阅读
## 开发示例
@@ -41,7 +43,7 @@ public class SpringmvcHelloImpl implements Hello {
### 步骤 3发布服务
-在`resources/META-INF/spring`目录下创建`springmvcHello.bean.xml`文件,命名规则为`\*.bean.xml`,配置spring进行服务扫描的base-package,文件内容如下:
+在`resources/META-INF/spring`目录下创建`springmvcprovider.bean.xml`文件,命名规则为`\*.bean.xml`,配置spring进行服务扫描的base-package,文件内容如下:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -56,6 +58,20 @@ public class SpringmvcHelloImpl implements Hello {
</beans>
```
+### 步骤 4启动provider 服务
+
+进行主要相关配置初始化。
+
+```java
+public class SpringmvcProviderMain {
+
+ public static void main(String[] args) throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
+```
+
## 涉及API
Spring MVC开发模式当前支持org.springframework.web.bind.annotation包下的如下注解,所有注解的使用方法参考[Spring MVC官方文档](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html)。
@@ -70,5 +86,97 @@ Spring MVC开发模式当前支持org.springframework.web.bind.annotation包下
| RequestHeader | parameter | 从header中获取参数 |
| RequestBody | parameter | 从body中获取参数,每个operation只能有一个body参数 |
+## Query参数聚合为POJO对象
+
+### 使用说明
+
+SpringBoot支持将Java业务接口中的多个query参数聚合为一个POJO类,SpringBoot原生用法示例如下:
+```java
+@RequestMapping("/hello")
+public class HelloService {
+ @RequestMapping(value = "/sayHello", method = RequestMethod.GET)
+ public String sayHello(Person person) {
+ System.out.println("sayHello is called, person = [" + person + "]");
+ return "Hello, your name is " + person.getName() + ", and age is " + person.getAge();
+ }
+}
+```
+其中,作为参数的`Person`类是一个标准的JavaBean,包含属性`name`和`age`。当服务接收到的请求时,SpringBoot会将query参数`name`和`age`聚合为Person对象传入业务接口。
+
+ServiceComb的SpringMVC开发模式现在也支持类似的用法,该用法的要求如下:
+1. POJO参数上不能有Spring的参数注解,否则ServiceComb不会将其作为聚合的query参数对象处理。
+2. 仅支持聚合query参数
+3. POJO参数类中的属性名与query参数名需要保持一致
+4. POJO参数中不支持复杂的属性,如其他POJO对象、List等。用户可以在这些复杂类型打上`@JsonIgnore`注解来让ServiceComb忽略这些复杂属性。
+5. consumer端不支持query参数聚合为POJO对象,调用服务时依然要按照契约发送请求。即provider端被聚合的POJO参数在契约中会被展开成一系列的query参数,consumer端需要在provider接口方法中依次定义这些query参数(RPC开发模式),或在发送请求时填入这些query参数(RestTemplate开发模式)。
+
+### 代码示例
+
+#### Provider端开发服务
+
+- Provider端业务接口代码:
+```java
+ @RestSchema(schemaId = "helloService")
+ @RequestMapping("/hello")
+ public class HelloService {
+ @RequestMapping(value = "/sayHello", method = RequestMethod.GET)
+ public String sayHello(Person person) {
+ System.out.println("sayHello is called, person = [" + person + "]");
+ return "Hello, your name is " + person.getName() + ", and age is " + person.getAge();
+ }
+ }
+```
+- POJO参数对象定义:
+```java
+ public class Person {
+ private String name;
+ private int age;
+ @JsonIgnore // 复杂属性需要标记@JsonIgnore,否则启动时会报错
+ private List<Person> children;
+ }
+```
+- 接口契约:
+```yaml
+# 忽略契约的其他部分
+basePath: "/hello"
+paths:
+ /sayHello:
+ get:
+ operationId: "sayHello"
+ parameters:
+ # Person类的name属性和age属性作为契约中的query参数
+ - name: "name"
+ in: "query"
+ required: false
+ type: "string"
+ - name: "age"
+ in: "query"
+ required: false
+ type: "integer"
+ format: "int32"
+ responses:
+ 200:
+ description: "response of 200"
+ schema:
+ type: "string"
+```
+#### Consumer端调用服务
+- consumer端RPC开发模式:
+ - Provider接口定义
+ ```java
+ public interface HelloServiceIntf {
+ String sayHello(String name, int age);
+ }
+ ```
+ - 调用代码
+ ```java
+ String result = helloService.sayHello("Bob", 22); // result的值为"Hello, your name is Bob, and age is 22"
+ ```
+- consumer端RestTemplate开发模式:
+ ```java
+ String result = restTemplate.getForObject(
+ "cse://provider-service/hello/sayHello?name=Bob&age=22",
+ String.class); // 调用效果与RPC方式相同
+ ```
diff --git a/java-chassis-reference/en_US/build-provider/swagger-annotation.md b/java-chassis-reference/en_US/build-provider/swagger-annotation.md
index 583b053..49d9f1e 100644
--- a/java-chassis-reference/en_US/build-provider/swagger-annotation.md
+++ b/java-chassis-reference/en_US/build-provider/swagger-annotation.md
@@ -1,3 +1,5 @@
+# 使用 Swagger 注解
+
## 概念阐述
Swagger提供了一套注解用于描述接口契约,用户使用注解,可以在代码中增加对于契约的描述信息。ServiceComb支持其中的部分注解。
diff --git a/java-chassis-reference/en_US/build-provider/transparent-rpc.md b/java-chassis-reference/en_US/build-provider/transparent-rpc.md
index 0d61261..ac378f7 100644
--- a/java-chassis-reference/en_US/build-provider/transparent-rpc.md
+++ b/java-chassis-reference/en_US/build-provider/transparent-rpc.md
@@ -1,3 +1,5 @@
+# 用透明RPC开发微服务
+
## 概念阐述
透明RPC开发模式是一种基于接口和接口实现的开发模式,服务的开发者不需要使用Spring MVC和JAX-RS注解。
@@ -15,6 +17,14 @@ public interface Hello {
String sayHi(String name);
String sayHello(Person person);
}
+
+public interface Compute {
+ int add(int a, int b);
+ int multi(int a, int b);
+ int sub(int a, int b);
+ int divide(int a, int b);
+}
+
```
@@ -23,7 +33,13 @@ public interface Hello {
Hello的服务实现如下:
+> **说明**:
+> 每一个服务接口都需要定义一个schema声明。
+
+* 在接口Hello 和 Compute 的实现类上使用@RpcSchema注解定义schema,代码如下:
+
```java
+@RpcSchema(schemaId = "hello")
public class HelloImpl implements Hello {
@Override
public String sayHi(String name) {
@@ -35,13 +51,39 @@ public class HelloImpl implements Hello {
return "Hello person " + person.getName();
}
}
+
+@RpcSchema(schemaId = "codeFirstCompute")
+public class CodeFirstComputeImpl implements Compute {
+ @Override
+ public int add(int a, int b) {
+ return a + b;
+ }
+
+ @Override
+ public int multi(int a, int b) {
+ return a * b;
+ }
+
+ @Override
+ public int sub(int a, int b) {
+ return a - b;
+ }
+
+ @Override
+ public int divide(int a, int b) {
+ if (b != 0) {
+ return a / b;
+ }
+ return 0;
+ }
+}
```
### 步骤 3发布服务
* 通过配置文件方式
-在resources/META-INF/spring目录下创建pojoHello.bean.xml文件,在文件中声明schema,文件内容如下:
+在resources/META-INF/spring目录下的pojoHello.bean.xml文件中,配置Spring进行服务扫描的base-package,文件内容如下:
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -51,44 +93,24 @@ public class HelloImpl implements Hello {
xmlns:context=" http://www.springframework.org/schema/context "
xsi:schemaLocation=" http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.huawei.com/schema/paas/cse/rpc classpath:META-INF/spring/spring-paas-cse-rpc.xsd">
- <cse:rpc-schema schema-id="pojoHello" implementation="org.apache.servicecomb.samples.pojo.provider.PojoHelloImpl"/>
+ <context:component-scan base-package="org.apache.servicecomb.samples.pojo.provider"/>
</beans>
```
-> **说明**:
-> 每一个服务接口都需要定义一个schema声明。
-
-* 通过注解配置的开发方式
-
-1. 定义服务接口,与使用Spring xml的方式相同。
-2. 实现服务,与使用Spring xml的方式相同。
-3. 发布服务。在接口Hello的实现类上使用@RpcSchema注解定义schema,代码如下:
+### 步骤 4 启动服务
```java
-import org.apache.servicecomb.provider.pojo.RpcSchema;
+public class PojoProviderMain {
-@RpcSchema(schemaId = "pojoHello")
-public class HelloImpl implements Hello {
- // some code omitted
+ public static void main(String[] args) throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
}
```
-在resources/META-INF/spring目录下的pojoHello.bean.xml文件中,配置Spring进行服务扫描的base-package,文件内容如下:
-
-```xml
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns=" http://www.springframework.org/schema/beans " xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
- xmlns:p=" http://www.springframework.org/schema/p " xmlns:util=" http://www.springframework.org/schema/util "
- xmlns:cse=" http://www.huawei.com/schema/paas/cse/rpc "
- xmlns:context=" http://www.springframework.org/schema/context "
- xsi:schemaLocation=" http://www.springframework.org/schema/beans classpath:org/springframework/beans/factory/xml/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.huawei.com/schema/paas/cse/rpc classpath:META-INF/spring/spring-paas-cse-rpc.xsd">
-
- <context:component-scan base-package="org.apache.servicecomb.samples.pojo.provider"/>
-</beans>
-```
-
> **说明**:
> 与Spring MVC开发模式和JAX-RS开发模式不同的是,透明RPC开发模式使用的注解是`@RpcSchema`而非`@RestSchema`。
diff --git a/java-chassis-reference/en_US/catalog/build-consumer.md b/java-chassis-reference/en_US/catalog/build-consumer.md
index e69de29..278ee24 100644
--- a/java-chassis-reference/en_US/catalog/build-consumer.md
+++ b/java-chassis-reference/en_US/catalog/build-consumer.md
@@ -0,0 +1,27 @@
+## 使用RestTemplate开发服务消费者
+RestTemplate是Spring提供的RESTful访问接口,ServiceComb提供该接口的实现类用于服务的调用。
+
+## 使用AsynRestTemplate开发服务消费者
+AsyncRestTemplate 开发方式允许用户异步的进行服务调用。具体的业务流程和 restTemplate 类似,只是这里以异步的形式进行服务的调用。
+
+## 使用透明RPC方式开发服务消费者
+
+透明RPC开发模式允许用户通过简单的java interface像本地调用一样进行服务调用。
+
+## 使用服务契约
+当服务消费者调用服务提供者的服务时,需要注册服务契约。消费者有两种方式获取提供者的服务契约,一种是从服务的提供方离线获取契约文件,手工配置到项目中;另一种是从服务中心自动下载契约。
+
+## 调用控制
+
+### 实例级故障隔离
+实例级故障隔离功能允许在微服务的部分实例调用失败时,停止向故障实例发送请求,从而达到隔离故障实例的功能。
+
+### 熔断策略
+熔断策略是对ServiceComb熔断功能的设置,用户通过配置熔断策略可以指定在何种条件下ServiceComb框架将终止发送请求。
+
+### 限流策略
+用户在consumer端使用限流策略,可以限制发往指定微服务的请求的频率。
+
+### 故障注入
+用户在consumer端使用故障注入,可以设置发往指定微服务的请求的时延和错误及其触发概率。
+
diff --git a/java-chassis-reference/en_US/catalog/build-provider.md b/java-chassis-reference/en_US/catalog/build-provider.md
index e69de29..21118ef 100644
--- a/java-chassis-reference/en_US/catalog/build-provider.md
+++ b/java-chassis-reference/en_US/catalog/build-provider.md
@@ -0,0 +1,47 @@
+## [服务定义](/build-provider/definition/service-definition.html)
+• 服务定义信息是微服务的身份标识,它定义了服务从属于哪个应用,以及名字和版本。服务定义信息中也可以有扩展信息,用于定义服务的属性元数据。
+
+
+## [定义服务契约](/build-provider/define-contract.html)
+• 服务契约,指基于OpenAPI规范的微服务接口契约,是服务端与消费端对于接口的定义。java chassis提供了两种方式定义契约:code first和contract first。
+
+
+## [使用隐式契约](/build-provider/code-first.html)
+• 降级策略是当服务请求异常时,微服务所采用的异常处理策略。
+
+
+## [使用 Swagger 注解](/build-provider/swagger-annotation.html)
+• Swagger提供了一套注解用于描述接口契约,用户使用注解,可以在代码中增加对于契约的描述信息。ServiceComb支持其中的部分注解。
+
+
+## [用SpringMVC 开发微服务](/build-provider/springmvc.html)
+• ServiceComb支持SpringMVC注解,允许使用SpringMVC风格开发微服务。建议参照着项目 SpringMVC进行详细阅读。
+
+## [用JAX-RS开发微服务](/build-provider/jaxrs.html)
+• ServiceComb支持开发者使用JAX-RS注解,使用JAX-RS模式开发服务。
+
+## [使用 Swagger 注解](/build-provider/swagger-annotation.html)
+• Swagger提供了一套注解用于描述接口契约,用户使用注解,可以在代码中增加对于契约的描述信息。ServiceComb支持其中的部分注解。
+
+## [使用 Swagger 注解](/build-provider/swagger-annotation.html)
+• Swagger提供了一套注解用于描述接口契约,用户使用注解,可以在代码中增加对于契约的描述信息。ServiceComb支持其中的部分注解。
+
+## [用透明RPC开发微服务](/build-provider/transparent-rpc.html)
+• 透明RPC开发模式是一种基于接口和接口实现的开发模式,服务的开发者不需要使用Spring MVC和JAX-RS注解。
+
+## [接口定义和数据类型](/build-provider/swagger-annotation.html)
+• ServiceComb-Java-Chassis建议接口定义遵循一个简单的原则:接口定义即接口使用说明,不用通过查看代码实现,就能识别如何调用这个接口。可以看出,这个原则站在使用者这边,以更容易被使用作为参考。ServiceComb会根据接口定义生成接口契约,符合这个原则的接口,生成的契约也是用户容易阅读的。
+
+## [服务监听地址和发布地址](/build-provider/listen-address-and-publish-address.html)
+•在JavaChassis中,服务的监听地址和发布地址是两个独立的概念,可以独立配置:
+
+ 监听地址:指微服务实例启动时监听的地址。该配置项决定了可以通过哪些IP访问此服务。
+ 发布地址:指微服务实例注册到服务中心的地址。其他的微服务实例会通过服务中心获取此实例的信息,根据发布地址访问此服务实例,所以该配置项决定了其他服务实际上会使用哪个IP访问此服务。
+
+## [服务配置](/build-provider/service-configuration.html)
+
+• [负载均衡策略](/build-provider/configuration/lb-strategy.html)
+• [限流策略](/build-provider/configuration/ratelimite-strategy.html)
+• [降级策略](/build-provider/configuration/downgrade-strategy.html)
+• [参数教研](/build-provider/configuration/parameter-validator.html)
+
diff --git a/java-chassis-reference/en_US/catalog/general-develop.md b/java-chassis-reference/en_US/catalog/general-develop.md
index e69de29..4c95230 100644
--- a/java-chassis-reference/en_US/catalog/general-develop.md
+++ b/java-chassis-reference/en_US/catalog/general-develop.md
@@ -0,0 +1,81 @@
+## 访问服务中心
+系统通过服务中心实现服务之间的发现。服务启动过程中,会向服务中心进行注册。在调用其他服务的时候,会从服务中心查询其他服务的实例信息,比如访问地址、使用的协议以及其他参数。服务中心支持使用PULL和PUSH两种模式通知实例变化。
+
+
+## 使用动态配置
+ServiceComb提供了分层次的配置机制。按照优先级,分为:
+• 配置中心(动态配置)
+• Java System Property(-D参数)
+• 环境变量
+• 配置文件,microservice.yaml。microservice.yaml文件从classpath扫描,可以允许存在很多份。通过servicecomb-config-order指定优先级。
+
+## 应用性能监控
+ 一、Metrics介绍
+ 二、统计项汇总
+ 三、使用方法
+
+
+## 微服务调用链
+微服务架构解决了很多单体应用带来的问题,但同时也需要我们付出额外的代价。由于网络的不稳定性带来的请求处理延迟就是代价之一。
+
+在单体应用中,所有模块都在同一个进程中运行,所以并没有模块间互通的问题。但微服务架构中,服务间通过网络沟通,因此我们不得不处理和网络有关的 问题,例如:延迟、超时、网络分区等。
+
+另外,随着业务的扩展服务增多,我们很难洞察数据如何在蛛网般复杂的服务结构中流转。我们如何才能有效的监控网络延迟并且可视化服务中的数据流转呢?
+
+分布式调用链追踪用于有效地监控微服务的网络延时并可视化微服务中的数据流转。
+
+## 自定义调用链打点
+分布式调用链追踪提供了服务间调用的时序信息,但服务内部的链路调用信息对开发者同样重要,如果能将两者合二为一,就能提供更完整的调用链,更容易定位错误和潜在性能问题。
+
+## 本地开发和测试
+本小节介绍如何在开发者本地进行消费者/提供者应用的开发调试。开发服务提供者请参考3 开发服务提供者章节,开发服务消费者请参考4 开发服务消费者。服务提供者和消费提供者均需要连接到在远程的服务中心,为了本地微服务的开发和调试,本小节介绍了两种搭建本地服务中心的方法进行本地微服务调试:
+
+
+## Http Filter
+某些场景中,业务使用http而不是https,作为网络传输通道,此时为了防止被伪造或篡改请求,需要提供consumer、producer之间对http码流的签名功能。
+
+
+## 文件上传
+文件上传,当前支持在vertx rest通道和servlet rest中使用。
+文件上传使用标准的http form格式,可与浏览器的上传直接对接。
+
+## 文件下载
+文件下载,当前在vertx rest通道和servlet rest中可用。
+
+
+## Reactive
+简单同步模式、嵌套同步调用、纯Reactive机制、混合Reactive机制之间的对比及说明。
+
+
+## DNS自定义配置
+用户使用域名连接华为公有云或者三方系统时,需要使用到域名解析系统。在不同的系统、不同的框架使用的域名解析机制都可能不太一样。所以我们有必要提供一个统一的配置入口,以便开发运维人员可以自定义DNS解析机制,而不完全受制于系统配置。
+
+## 代理设置
+作为一名开发者,在公司开发环境,可能是通过公司代理网络接入到因特网。如果调试服务时还必须依赖网上资源,比如直接连接华为共有云服务中心,那么就必须配置代理。
+
+
+## 框架上报版本号
+为方便治理,使用ServiceComb进行开发,会将当前使用的ServiceComb版本号上报至服务中心,并且支持其他框架集成ServiceComb时上报其他框架的版本号。
+
+## 跨应用调用
+应用是微服务实例隔离层次中的一层,一个应用包含多个微服务。默认情况下,只允许同应用的微服务实例相互调用。
+
+
+## 定制序列化和反序列化方法
+由于HTTP协议的非安全性,在网络中传输的数据能轻易被各种抓包工具监听。在实际应用中,业务对应用或服务间传输的敏感数据有较高的安全要求,这类数据需要特别的加密保护(业务不同对算法要求不同),这样即使内容被截获,也可以保护其中的敏感数据不被轻易获取。
+
+
+## 使用Context传递控制消息
+ServiceComb提供了Context在微服务之间传递数据。Context是key/value对,只能够使用String类型的数据。由于Context会序列化为json格式并通过HTTP Header传递,因此也不支持ASCII之外的字符,其他字符需要开发者先自行编码再传递。Context在一次请求中,会在请求链上传递,不需要重新设置。access log的trace id等功能都基于这个特性实现的。
+
+
+## 返回值序列化扩展
+当前REST通道返回值支持application/json和text/plain两种格式,支持开发人员扩展和重写,服务提供者通过produces声明可提供序列化能力,服务消费者通过请求的Accept头指明返回值序列化方式,默认返回application/json格式的数据。
+
+
+## CORS机制
+跨域资源共享(CORS, Cross-Origin Resource Sharing)允许Web服务器进行跨域访问控制,使浏览器可以更安全地进行跨域数据传输。
+
+
+## 获取熔断与实例隔离告警事件信息
+在微服务运行期间熔断或实例隔离状态发生变化时,需要监听到相关事件,获取相关信息并进行处理
diff --git a/java-chassis-reference/en_US/catalog/open-service.md b/java-chassis-reference/en_US/catalog/open-service.md
deleted file mode 100644
index e69de29..0000000
diff --git a/java-chassis-reference/en_US/catalog/security.md b/java-chassis-reference/en_US/catalog/security.md
index e69de29..de45733 100644
--- a/java-chassis-reference/en_US/catalog/security.md
+++ b/java-chassis-reference/en_US/catalog/security.md
@@ -0,0 +1,5 @@
+##使用TLS通信
+用户通过简单的配置即可启用TLS通信,以保障数据的传输安全。
+
+## 使用RSA认证
+用户通过简单的配置即可启用服务间RSA认证,以保障服务接口的安全性。详细介绍参考公钥认证
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/catalog/service-package-run.md b/java-chassis-reference/en_US/catalog/service-package-run.md
index e69de29..e4191a1 100644
--- a/java-chassis-reference/en_US/catalog/service-package-run.md
+++ b/java-chassis-reference/en_US/catalog/service-package-run.md
@@ -0,0 +1,6 @@
+## 以standalone模式打包
+一个Standalone的容器,以简单的Main加载Spring启动,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务。微框架提供了standalone部署运行模式,服务容器只是一个简单的Main方法,并加载一个简单的Spring容器,用于暴露服务。
+
+## 以WEB容器模式打包
+如果需要将该微服务加载到web容器中启动运行时,需要新建一个servlet工程包装一下,该servlet工程,根据需要,可以不写或写少量的引导代码即可。
+
diff --git a/java-chassis-reference/en_US/catalog/start.md b/java-chassis-reference/en_US/catalog/start.md
index 297cfe0..8d5fba1 100644
--- a/java-chassis-reference/en_US/catalog/start.md
+++ b/java-chassis-reference/en_US/catalog/start.md
@@ -1,4 +1,15 @@
-#
+### [术语表](/start/terminology.html)
+
+### [微服务系统架构](/start/architecture.html)
+### [安装本地开发环境](/build-provider/definition/service-definition.html)
+• 服务定义信息是微服务的身份标识,它定义了服务从属于哪个应用,以及名字和版本。服务定义信息中也可以有扩展信息,用于定义服务的属性元数据。
+
+### [开发第一个微服务](/start/first-sample.html)
+
+开发者可以通过两种方式快速构建一个项目:
+
+• 下载samples项目。建议把整个项目都下载下来,按照例子 SpringMVC 或者 JAX RS进行初始化配置。
+• 使用archetypes生成项目
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/edge/by-servicecomb-sdk.md b/java-chassis-reference/en_US/edge/by-servicecomb-sdk.md
index b33ee84..bda6b16 100644
--- a/java-chassis-reference/en_US/edge/by-servicecomb-sdk.md
+++ b/java-chassis-reference/en_US/edge/by-servicecomb-sdk.md
@@ -1,20 +1,93 @@
-# 一、功能范围
+# 使用Edge Service做边缘服务
-Edge Service作为整个微服务系统对外的接口,向最终用户提供服务,接入RESTful请求,转发给内部微服务。Edge Service以开发框架的形式提供,其中的服务映射、请求解析、加密解密、鉴权等逻辑需要业务通过扩展点自行开发。
+Edge Service是ServiceComb提供的JAVA网关服务。Edge Service作为整个微服务系统对外的接口,向最终用户提供服务,接入RESTful请求,转发给内部微服务。Edge Service以开发框架的形式提供,开发者可以非常简单的搭建一个Edge Service服务,通过简单的配置就可以定义路由转发规则。同时Edge Service支持强大的扩展能力,服务映射、请求解析、加密解密、鉴权等逻辑都可以通过扩展实现。
-Edge Service本身也是一个微服务,需遵守所有微服务开发的规则,其本身部署为多实例,前端需使用负载均衡装置进行负载分发。
+Edge Service本身也是一个微服务,需遵守所有微服务开发的规则。其本身可以部署为多实例,前端使用负载均衡装置进行负载分发;也可以部署为主备,直接接入用户请求。开发者可以根据Edge Service承载的逻辑和业务访问量、组网情况来规划。
-页面开发、页面模板等表现层,不在Edge Service框架范围内,使用自行使用合适的技术去承载。但是Edge Service也提供了足够的灵活性,可以使用vertx API实现非ServiceComb SDK开发的微服务的请求转发,可以查看专题文章中示例。
+## 开发Edge Service服务
+开发Edge Service和开发一个普通的微服务步骤差不多,开发者可以从导入[ServiceComb Edge Service Demo](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/demo/demo-edge)入手。从头搭建项目包含如下几个步骤:
-# 二、特性
+* 配置依赖关系
-## 1.部署、启动无耦合
+在项目中加入edge-core的依赖,就可以启动Edge Service的功能。Edge Service在请求转发的时候,会经过处理链,因此还可以加入相关的处理链的模块的依赖,下面的实例增加的负载均衡的处理链,这个是必须的。
+```
+<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>edge-core</artifactId>
+</dependency>
+<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-loadbalance</artifactId>
+</dependency>
+```
+
+* 定义启动类
+
+和开发普通微服务一样,可以通过加载Spring的方式将服务拉起来。
+```
+public class EdgeMain {
+ public static void main(String[] args) throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
+```
+
+* 增加配置文件microservie.yaml
+
+Edge Service本身也是一个微服务,遵循微服务查找的规则,自己也会进行注册。注意APPLICAIONT_ID与需要转发的微服务相同。在下面的配置中,指定了Edge Service监听的地址,处理链等信息。其中auth处理链是DEMO项目中自定义的处理链,用于实现认证。同时auth服务本身,不经过这个处理链,相当于不鉴权。
+```
+APPLICATION_ID: edge
+service_description:
+ name: edge
+ version: 0.0.1
+servicecomb:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+ rest:
+ address: 127.0.0.1:18080
+ handler:
+ chain:
+ Consumer:
+ default: auth,loadbalance
+ service:
+ auth: loadbalance
+```
-Edge Service与转发目标微服务之间,没有部署、启动顺序上的要求,仅仅只要求转发请求时,目标微服务已经部署,并且已经启动。
+## 工作流程
+Edge Service的工作流程如下,蓝色背景部分在Eventloop线程中执行,黄色背景部分:
+ * 如果工作于reactive模式,则直接在Eventloop线程执行
+ * 如果工作于线程池模式,则在线程池的线程中执行
+![](/assets/workFlow.png)
-## 2.自动根据能力集合进行路由
+## 定制路由规则
+使用Edge Service的核心工作是配置路由规则。场景不同,规则也不同。
+路由规则由一系列AbstractEdgeDispatcher组成。Edge Service提供了几个常见的Dispatcher,通过配置即可启用,如果这些Dispatcher不满足业务场景需要,还可以自定义。
-假设某微服务,兼容规划为所有高版本必须兼容低版本,部署了以下版本实例:
+### 使用DefaultEdgeDispatcher
+DefaultEdgeDispatcher是一个非常简单、容易管理的Dispatcher,使用这个Dispatcher,用户不用动态管理转发规则,应用于实际的业务场景非常方便,这个也是推荐的一种管理机制。它包含如下几个配置项:
+```
+servicecomb:
+ http:
+ dispatcher:
+ edge:
+ default:
+ enabled: true
+ prefix: rest
+ withVersion: true
+ prefixSegmentCount: 1
+```
+
+常见的这些配置项的示例及含义如下:
+* [prefix=rest;withVersion=true;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。
+* [prefix=rest;withVersion=true;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。
+* [prefix=rest;withVersion=true;prefixSegmentCount=3]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。
+* [prefix=rest;withVersion=false;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求可能转发到任意微服务实例。
+* [prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,,请求可能转发到任意微服务实例。
+* [prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/abc,,请求可能转发到任意微服务实例。
+
+withVersion配置项提供了客户端灰度规则,可以让客户端指定访问的服务端版本。Edge Service还包含根据接口兼容性自动路由的功能,请求会转发到包含了该接口的实例。假设某微服务,兼容规划为所有高版本必须兼容低版本,部署了以下版本实例:
* 1.0.0,提供了operation1
@@ -26,17 +99,52 @@ Edge Service在转发operation2时,会自动使用1.1.0+的规则来过滤实
以上过程用户不必做任何干预,全自动完成,以避免将新版本的operation转发到旧版本的实例中去。
-## 3.治理
+### 使用URLMappedEdgeDispatcher
+URLMappedEdgeDispatcher允许用户配置URL和微服务的映射关系。使用它可以非常灵活的定义哪些URL转发到哪些微服务。它包含如下几个配置项:
+```
+servicecomb:
+ http:
+ dispatcher:
+ edge:
+ url:
+ enabled: true
+ 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
+```
+
+businessV1配置项表示的含义是将请求路径为/usr/business/v1/.*的请求,转发到business这个微服务,并且只转发到版本号为1.0.0-2.0.0的实例(不含2.0.0)。转发的时候URL为/business/v1/.*。path使用的是JDK的正则表达式,可以查看Pattern类的说明。prefixSegmentCount表示前缀的URL Segment数量,前缀不包含在转发的URL路径中。有三种形式的versionRule可以指定。2.0.0-3.0.0表示版本范围,含2.0.0,但不含3.0.0;2.0.0+表示大于2.0.0的版本,含2.0.0;2.0.0表示只转发到2.0.0版本。2,2.0等价于2.0.0。
+
+从上面的配置可以看出,URLMappedEdgeDispatcher也支持客户端灰度。当然配置项会比DefaultEdgeDispatcher多。URLMappedEdgeDispatcher支持通过配置中心动态的修改配置,调整路由规则。
+
+### 自定义Dispatcher
+
+自定义Dispatcher包含两个步骤:
+
+1. 实现AbstractEdgeDispatcher
+2. 通过SPI发布:增加文件META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,并写入实现类
-路由转发基于ServiceComb sdk,是标准的ServiceComb consumer机制,自动支持所有consumer端的治理功能。
+详细的代码细节可以参考下面的章节"DEMO功能说明"。开发者也可以参考DefaultEdgeDispatcher等代码来定义自己的Dispatcher。
-# 三、部署示例
+### 进行认证鉴权和其他业务处理
+
+通过Edge Servie工作流程可以看出,可以通过多种方式来扩展Edge Service的功能,包括Dispatcher、HttpServerFilter、Handler、HttpClientFilter等。比较常用和简单的是通过Handler来扩展。DEMO里面展示了如何通过Handler扩展来实现鉴权。详细的代码细节可以参考下面的章节"DEMO功能说明"。
+
+## 部署示例
![](/assets/deployment.png)
-# 四、工作模式
+## 工作模式
-## 1.reactive \(默认\)
+### reactive \(默认\)
Edge Service默认工作于高性能的reactive模式,此模式要求工作于Edge Service转发流程中的业务代码不能有任何的阻塞操作,包括不限于:
@@ -52,7 +160,7 @@ Edge Service的底层是基于netty的vertx,以上约束即是netty的reactive
![](/assets/reactive.png)
-## 2.线程池
+### 线程池
如果业务模型无法满足reactive要求,则需要使用线程池模式。
@@ -68,19 +176,7 @@ servicecomb:
![](/assets/threadPool.png)
-## 五、调用流程
-
-蓝色背景部分在Eventloop线程中执行
-
-黄色背景部分:
-
-* 如果工作于reactive模式,则直接在Eventloop线程执行
-
-* 如果工作于线程池模式,则在线程池的线程中执行
-
-![](/assets/workFlow.png)
-
-## 六、开发手册
+## DEMO功能说明
请参考github上的edge service demo:
@@ -98,7 +194,7 @@ servicecomb:
通过edge-service访问微服务business的不同版本,并确认是由正确的实例处理的。
-## 1.注册Dispatcher
+### 1.注册Dispatcher
实现接口org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,或从org.apache.servicecomb.edge.core.AbstractEdgeDispatcher继承,实现自己的dispatcher功能。
@@ -132,7 +228,7 @@ _假设Dispatcher A和B都可以处理同一个url,并且A优先级更高,
* _如果A处理完,然后调用了RoutingContext.next\(\),则会将请求转移给B处理_
-## 2.转发请求
+### 2.转发请求
注册路由时,指定了使用哪个方法来处理请求(下面使用onRequest来指代该方法),在onRequest中实现转发逻辑。
@@ -162,7 +258,7 @@ edgeInvoke调用内部,会作为ServiceComb标准consumer去转发调用。
作为标准consumer,意味着ServiceComb所有标准的治理能力在这里都是生效的。
-## 3.设置兼容规则
+### 3.设置兼容规则
不同的业务可能有不同的兼容规划,servicecomb默认的兼容规则,要求所有新版本兼容旧版本。如果满足这个要求,则不必做任何特殊的设置。
@@ -192,7 +288,7 @@ versionMapper的作用是将v1或是v2这样的串,转为1.0.0-2.0.0或2.0.0-3
接口不兼容会导致非常多的问题。java chassis要求高版本服务兼容低版本服务,只允许增加接口不允许删除接口。在增加接口后,必须增加微服务的版本号。在开发阶段,接口变更频繁,开发者往往忘记这个规则。当这个约束被打破的时候,需要清理服务中心微服务的信息,并重启微服务和Edge Service\(以及依赖于该微服务的其他服务\)。否则可能出现请求转发失败等情况。
-## 4.鉴权
+### 4.鉴权
Edge Service是系统的边界,对于很多请求需要执行鉴权逻辑。
diff --git a/java-chassis-reference/en_US/edge/edge-service.md b/java-chassis-reference/en_US/edge/edge-service.md
deleted file mode 100644
index e69de29..0000000
diff --git a/java-chassis-reference/en_US/edge/nginx.md b/java-chassis-reference/en_US/edge/nginx.md
index 4ec95e7..2f0d633 100644
--- a/java-chassis-reference/en_US/edge/nginx.md
+++ b/java-chassis-reference/en_US/edge/nginx.md
@@ -1,3 +1,5 @@
+# 使用confd和Nginx做边缘服务
+
## 概念阐述
### **confd**
diff --git a/java-chassis-reference/en_US/edge/open-service.md b/java-chassis-reference/en_US/edge/open-service.md
new file mode 100644
index 0000000..e406c8c
--- /dev/null
+++ b/java-chassis-reference/en_US/edge/open-service.md
@@ -0,0 +1,5 @@
+# 服务能力开放
+
+大量的微服务能力需要通过网关开放给用户、其他外部系统访问。网关一方面扮演着汇集用户请求的作用,同时还会扮演认证、鉴权、流量控制、防攻击的用途。同时,由于网关是一个汇聚点,容易形成业务的瓶颈,通常还会采用多级网关机制,最外层的网关提供主备以及简单的请求转发功能,中间层的实现鉴权等功能,多实例部署。常见的可以用于网关的技术和服务包括LVS、Nginx、Zuul等。
+
+ServiceComb 也提供了自己的网关服务Edge Service。Edge Service内建了强大的路由策略,支持接口级别的兼容性转发(灰度发布),内嵌ServiceComb治理能力,并支持非常灵活的扩展机制。
diff --git a/java-chassis-reference/en_US/edge/zuul.md b/java-chassis-reference/en_US/edge/zuul.md
index 6a89957..4233f37 100644
--- a/java-chassis-reference/en_US/edge/zuul.md
+++ b/java-chassis-reference/en_US/edge/zuul.md
@@ -1,3 +1,5 @@
+# 使用zuul做边缘服务
+
## 概念阐述
### API Gateway:
@@ -25,6 +27,10 @@ Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器,可以使
Zuul做API Gateway,即建立一个Zuul Proxy应用,在该Proxy应用中统一定义所有的微服务访问入口,通过使用不同的前缀\(stripped\)来区分各个微服务。本小节通过建立一个ZuulProxy SpringBoot应用来演示Zuul的API Gateway功能。
+## 注意事项
+
+本小节介绍的ZuulProxy和ZuulServer等demo都是基于SpringBoot和ServiceComb框架的应用,具体请参考[在Spring Boot中使用java chassis](/using-java-chassis-in-spring-boot.md)。
+
## 启动Zuul Proxy
本节介绍如何启动一个zuul proxy应用作为API Gateway。步骤如下:
@@ -89,8 +95,6 @@ servicecomb:
address: 0.0.0.0:8082 #微服务端口,可不写
```
-本小节所有服务使用的都是本地的服务中心,具体的服务中心启动流程请参考[启动本地服务中心](#li2337491491436)
-
* **步骤 5 **Run ZuulMain Application
## 使用Zuul Proxy
diff --git a/java-chassis-reference/en_US/general-development/AlarmEvent.md b/java-chassis-reference/en_US/general-development/AlarmEvent.md
new file mode 100644
index 0000000..538bcd5
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/AlarmEvent.md
@@ -0,0 +1,37 @@
+# 获取熔断与实例隔离告警事件
+
+## 场景描述
+* 在微服务运行期间熔断或实例隔离状态发生变化时,需要监听到相关事件,获取相关信息并进行处理
+
+## 使用参考
+
+* 监听熔断事件
+```
+Object receiveEvent = new Object() {
+ @Subscribe
+ public void onEvent(CircutBreakerEvent circutBreakerEvent) {
+ //Get information from circutBreakerEvent
+ }
+ };
+circutBreakerEventNotifier.eventBus.register(receiveEvent);
+```
+* 监听实例隔离事件
+```
+Object receiveEvent = new Object() {
+ @Subscribe
+ public void onEvent(IsolationServerEvent isolationServerEvent) {
+ //Get information from isolationServerEvent
+ }
+ };
+circutBreakerEventNotifier.eventBus.register(receiveEvent);
+```
+* 两个事件均监听
+```
+Object receiveEvent = new Object() {
+ @Subscribe
+ public void onEvent(AlarmEvent alarmEvent) {
+ //Get information from alarmEvent
+ }
+ };
+circutBreakerEventNotifier.eventBus.register(receiveEvent);
+```
diff --git a/java-chassis-reference/en_US/general-development/CORS.md b/java-chassis-reference/en_US/general-development/CORS.md
new file mode 100644
index 0000000..be16cff
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/CORS.md
@@ -0,0 +1,36 @@
+# CORS机制
+
+## 概念阐述
+
+跨域资源共享(CORS, Cross-Origin Resource Sharing)允许Web服务器进行跨域访问控制,使浏览器可以更安全地进行跨域数据传输。
+
+## 场景描述
+
+当用户需要从浏览器上跨域发送REST请求时就有可能要用到CORS机制,接收跨域请求的微服务需要开启CORS支持。
+
+## 配置说明
+
+CORS功能在microservice.yaml文件中配置,配置项见下表所述。
+
+| 配置项 | 默认值 | 取值范围 | 是否必选 | 含义 | 注意 |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| servicecomb.cors.enabled | `false` | `true`/`false` | 否 | 是否开启CORS功能 | - |
+| servicecomb.cors.origin | `*` | - | 否 | Access-Control-Allow-Origin | - |
+| servicecomb.cors.allowCredentials | `false` | `true`/`false` | 否 | Access-Control-Allow-Credentials | 根据CORS标准,当Access-Control-Allow-Credentials设置为`true`时,Access-Control-Allow-Origin不可设置为"*",否则将会抛出异常 |
+| servicecomb.cors.allowedHeader | 无 | - | 否 | Access-Control-Allow-Headers | 多个值使用逗号分隔 |
+| servicecomb.cors.allowedMethod | 无 | - | 否 | Access-Control-Allow-Methods | 多个值使用逗号分隔 |
+| servicecomb.cors.exposedHeader | 无 | - | 否 | Access-Control-Expose-Headers | 多个值使用逗号分隔 |
+| servicecomb.cors.maxAge | 无 | (0,2147483647],整型 | 否 | Access-Control-Max-Age | 单位是秒,如果用户不配置此项,则CORS应答中没有Access-Control-Max-Age |
+
+
+## 示例代码
+
+```yaml
+servicecomb:
+ cors:
+ enabled: true
+ origin: "*"
+ allowCredentials: false
+ allowedMethod: PUT,DELETE
+ maxAge: 3600
+```
diff --git a/java-chassis-reference/en_US/general-development/config.md b/java-chassis-reference/en_US/general-development/config.md
new file mode 100644
index 0000000..279297f
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/config.md
@@ -0,0 +1,53 @@
+# 使用动态配置
+
+ServiceComb提供了分层次的配置机制。按照优先级,分为:
+* 配置中心(动态配置)
+* Java System Property(-D参数)
+* 环境变量
+* 配置文件,microservice.yaml。microservice.yaml文件从classpath扫描,可以允许存在很多份。通过servicecomb-config-order指定优先级。
+
+配置文件默认是classpath下的microservice.yaml, 但是可以通过环境变量传入其他文件,可以设置的环境变量为:
+
+|变量|描述|
+|---|---|
+|servicecomb.configurationSource.additionalUrls|配置文件的列表,以,分隔的多个包含具体位置的完整文件名|
+|servicecomb.configurationSource.defaultFileName|默认配置文件名|
+
+动态配置的默认实现是config-cc客户端,对接配置中心,配置项如下:
+
+|变量|描述|
+|---|---|
+|servicecomb.config.client.refreshMode|应用配置的刷新方式,0为config-center主动push,1为client周期pull,默认为0|
+|servicecomb.config.client.refreshPort|config-center推送配置的端口|
+|servicecomb.config.client.tenantName|应用的租户名称|
+|servicecomb.config.client.serverUri|config-center访问地址,http(s)://{ip}:{port},以,分隔多个地址(可选,当cse.config.client.regUri配置为空时该配置项才会生效)|
+
+## 在程序中获取配置信息
+
+开发者使用一致的API获取配置,不区分配置的存储路径:
+```
+DynamicDoubleProperty myprop = DynamicPropertyFactory.getInstance().getDoubleProperty("trace.handler.sampler.percent", 0.1);
+```
+
+具体方法可参考[API DOC](https://netflix.github.io/archaius/archaius-core-javadoc/com/netflix/config/DynamicPropertyFactory.html)
+
+## 处理配置变更
+可以注册callback处理配置变更:
+```
+ myprop.addCallback(new Runnable() {
+ public void run() {
+ // Handle configuration changes
+ }
+ });
+```
+
+## 进行配置项映射
+有些情况下,我们要屏蔽我们使用的一些开源组件的配置并给用户提供我们自己的配置项。在这种情况下,可以通过classpath下的config.yaml进行映射定义:
+```
+registry:
+ client:
+ serviceUrl:
+ defaultZone: eureka.client.serviceUrl.defaultZone
+```
+
+定义映射后,在配置装载的时候框架会默认进行映射,把以我们定义的配置项映射为开源组件可以认的配置项。
diff --git a/java-chassis-reference/en_US/general-development/context.md b/java-chassis-reference/en_US/general-development/context.md
new file mode 100644
index 0000000..1b4b97a
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/context.md
@@ -0,0 +1,36 @@
+# 使用Context传递控制消息
+
+ServiceComb提供了Context在微服务之间传递数据。Context是key/value对,只能够使用String类型的数据。由于Context会序列化为json格式并通过HTTP Header传递,因此也不支持ASCII之外的字符,其他字符需要开发者先自行编码再传递。Context在一次请求中,会在请求链上传递,不需要重新设置。[access log](../build-provider/access-log-configuration.md)的trace id等功能都基于这个特性实现的。
+
+## 场景描述
+* 在认证场景,Edge Service认证通过以后,需要将会话ID、用户名称等信息传递给微服务,实现鉴权等逻辑
+* 灰度发布场景,需要结合自定义的tag实现引流,tag信息需要传递给微服务
+
+## 使用参考
+
+* 在Hanlder中获取和设置Context
+
+Handler包含了Invocation对象,可以直接调用invocation.addContext和invocation.getContext设置。
+
+* 在服务接口中获取Context
+
+通过接口注入
+```
+public Response cseResponse(InvocationContext c1)
+```
+或者
+```
+ContextUtils.getInvocationContext()
+```
+
+* 在Edge Service中设置Context
+
+通过重载EdgeInvocation
+```
+EdgeInvocation edgeInvocation = new EdgeInvocation() {
+ protected void createInvocation() {
+ super.createInvocation();
+ this.invocation.addContext("hello", "world");
+ }
+};
+```
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/general-development/cross-app-invocation.md b/java-chassis-reference/en_US/general-development/cross-app-invocation.md
new file mode 100644
index 0000000..097e542
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/cross-app-invocation.md
@@ -0,0 +1,46 @@
+### 概念阐述
+
+应用是微服务实例隔离层次中的一层,一个应用包含多个微服务。默认情况下,只允许同应用的微服务实例相互调用。
+
+### 场景描述
+
+当用户需要不同应用间的微服务相互调用时,就需要开启跨应用调用功能。
+
+### 配置说明
+
+若要开启跨应用调用,首先需在provider端的microservice.yaml文件开启跨应用调用配置。配置项如下:
+```yaml
+service_description:
+ # other configuration omitted
+ properties:
+ allowCrossApp: true # enable cross app invocation
+```
+
+consumer端指定微服务名称调用provider的时候,需要加上provider所属的应用ID,格式变为`[appID]:[microserviceName]`。
+
+### 示例代码
+
+示例假设provider所属应用为helloApp,微服务名称为helloProvider;consumer所属应用为helloApp2,微服务名称为helloConsumer。
+
+- RestTemplate调用方式
+
+ 当consumer端以RestTemplate方式开发微服务消费者时,需要在调用的URL中将`[microserviceName]`改为`[appID]:[microserviceName]`,代码示例如下:
+ ```java
+ RestTemplate restTemplate = RestTemplateBuilder.create();
+
+ ResponseEntity<String> responseEntity = restTemplate
+ .getForEntity("cse://helloApp:helloProvider/hello/sayHello?name={name}",
+ String.class, "ServiceComb");
+ ```
+
+- RPC调用方式
+
+ 当consumer端以RPC方式开发微服务消费者时,声明的服务提供者代理如下:
+ ```java
+ @RpcReference(schemaId = "hello", microserviceName = "helloApp:helloProvider")
+ private Hello hello;
+ ```
+ 调用方式和调用同应用下的微服务相同:
+ ```java
+ hello.sayHello("ServiceComb");
+ ```
diff --git a/java-chassis-reference/en_US/general-development/error-handling.md b/java-chassis-reference/en_US/general-development/error-handling.md
new file mode 100644
index 0000000..11737ad
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/error-handling.md
@@ -0,0 +1,162 @@
+# Handle exceptions
+
+ServiceComb has three categories of exceptions:
+* User Defined Exceptions:Exceptions defined in API. These exceptions are generated to swagger.
+* Control Messages Exceptions:Most of them are thrown by handlers. e.g. Flow control throws TOO_MANY_REQUESTS_STATUS.
+
+```
+CommonExceptionData errorData = new CommonExceptionData("rejected by qps flowcontrol");
+asyncResp.producerFail(new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData));
+```
+
+* Unknown Exceptions:Unkown exceptions may throw by service implementation like NullPointerException or network SocketException. These exceptions will be caught by ServiceComb and return 490, 590 like error code. e.g.
+
+```
+CommonExceptionData errorData = new CommonExceptionData(cause.getMessage());
+asyncResp.producerFail(new InvocationException(590, errorData)
+
+or
+asyncResp.consumerFail(new InvocationException(490, errorData)
+```
+
+
+## User Defined Exceptions
+
+Users can use @ApiResonse to define different types of exceptions。e.g.
+
+```
+ @Path("/errorCode")
+ @POST
+ @ApiResponses({
+ @ApiResponse(code = 200, response = MultiResponse200.class, message = ""),
+ @ApiResponse(code = 400, response = MultiResponse400.class, message = ""),
+ @ApiResponse(code = 500, response = MultiResponse500.class, message = "")})
+ public MultiResponse200 errorCode(MultiRequest request) {
+ if (request.getCode() == 400) {
+ MultiResponse400 r = new MultiResponse400();
+ r.setCode(400);
+ r.setMessage("bad request");
+ throw new InvocationException(javax.ws.rs.core.Response.Status.BAD_REQUEST, r);
+ } else if (request.getCode() == 500) {
+ MultiResponse500 r = new MultiResponse500();
+ r.setCode(500);
+ r.setMessage("internal error");
+ throw new InvocationException(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR, r);
+ } else {
+ MultiResponse200 r = new MultiResponse200();
+ r.setCode(200);
+ r.setMessage("success result");
+ return r;
+ }
+ }
+```
+
+and client code know exception type.
+
+```
+ MultiRequest request = new MultiRequest();
+
+ request.setCode(200);
+ ResponseEntity<MultiResponse200> result = template
+ .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse200.class);
+ TestMgr.check(result.getStatusCode(), 200);
+ TestMgr.check(result.getBody().getMessage(), "success result");
+
+ request.setCode(400);
+ MultiResponse400 t400 = null;
+ try {
+ template.postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse400.class);
+ } catch (InvocationException e) {
+ t400 = (MultiResponse400) e.getErrorData();
+ }
+ TestMgr.check(t400.getCode(), 400);
+ TestMgr.check(t400.getMessage(), "bad request");
+
+ request.setCode(500);
+ MultiResponse500 t500 = null;
+ try {
+ template.postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse400.class);
+ } catch (InvocationException e) {
+ t500 = (MultiResponse500) e.getErrorData();
+ }
+ TestMgr.check(t500.getCode(), 500);
+ TestMgr.check(t500.getMessage(), "internal error");
+```
+
+## Control Messages Exceptions
+
+Control message exceptions not defined in swagger and the type is unknown for serializers. Client code use raw type to process it.
+
+```
+ JsonObject requestJson = new JsonObject();
+ requestJson.put("code", 400);
+ requestJson.put("message", "test message");
+
+ try {
+ template
+ .postForEntity(SERVER + "/MultiErrorCodeService/noClientErrorCode", requestJson, Object.class);
+ } catch (InvocationException e) {
+ TestMgr.check(e.getStatusCode(), 400);
+ mapResult = RestObjectMapperFactory.getRestObjectMapper().convertValue(e.getErrorData(), Map.class);
+ TestMgr.check(mapResult.get("message"), "test message");
+ TestMgr.check(mapResult.get("code"), 400);
+ TestMgr.check(mapResult.get("t400"), 400);
+ }
+```
+
+The above code assume the type of exception data is unknown and convert it to map. Usually, ServiceComb throws its control messages exception with CommonExceptionData.
+
+## Unknown Exceptions
+
+Unknown exceptions are wrapped to 490 and 590 error code, and type is CommonExceptionData.
+
+## Customize exceptions type
+
+We can define actual types for error code and convert one type of exception to another.
+
+* define actual types for error code
+
+Define actual types for error code can make consumer code easier, and do not to use raw types. Users can implement a SPI interface org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper to specify the target exception type for specific error code.
+```
+ private final static Map<Integer, ResponseMeta> CODES = new HashMap<>(1);
+
+ static {
+ ResponseMeta meta = new ResponseMeta();
+ meta.setJavaType(SimpleType.constructUnsafe(IllegalStateErrorData.class));
+ CODES.put(500, meta);
+ }
+
+ @Override
+ public Map<Integer, ResponseMeta> getMapper() {
+ return CODES;
+ }
+```
+
+* convert one type of exception to another
+
+ServiceComb will serialize InvocationException data to response, and when exception type is not InvocationException,a wrapped InvocationException with error code 490, 590 is created。Implement SPI interface org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter can convert from one type of exception to the other.
+
+```
+public class CustomExceptionToResponseConverter implements ExceptionToResponseConverter<IllegalStateException> {
+ @Override
+ public Class<IllegalStateException> getExceptionClass() {
+ return IllegalStateException.class;
+ }
+
+ @Override
+ public int getOrder() {
+ return 100;
+ }
+
+ @Override
+ public Response convert(SwaggerInvocation swaggerInvocation, IllegalStateException e) {
+ IllegalStateErrorData data = new IllegalStateErrorData();
+ data.setId(500);
+ data.setMessage(e.getMessage());
+ data.setState(e.getMessage());
+ InvocationException state = new InvocationException(Status.INTERNAL_SERVER_ERROR, data);
+ return Response.failResp(state);
+ }
+}
+
+```
diff --git a/java-chassis-reference/en_US/general-development/file-download.md b/java-chassis-reference/en_US/general-development/file-download.md
index ae79a77..1a039aa 100644
--- a/java-chassis-reference/en_US/general-development/file-download.md
+++ b/java-chassis-reference/en_US/general-development/file-download.md
@@ -1,4 +1,4 @@
-文件下载,当前只在vertx rest通道中可用,servlet rest的支持后续会增加。
+文件下载,当前在vertx rest通道和servlet rest中可用。
# 一、Producer
@@ -156,6 +156,3 @@ org.apache.servicecomb.foundation.vertx.http.ReadStreamPart.saveToFile(File, Ope
* 如果要阻塞等待下载完成,通过future.get\(\)即可
* 如果通过future.whenComplete进行异步回调处理,要注意回调是发生在网络线程中的,此时需要遵守reactive的线程规则。
-
-
-
diff --git a/java-chassis-reference/en_US/general-development/file-upload.md b/java-chassis-reference/en_US/general-development/file-upload.md
index b2c114f..0f99b7b 100644
--- a/java-chassis-reference/en_US/general-development/file-upload.md
+++ b/java-chassis-reference/en_US/general-development/file-upload.md
@@ -1,20 +1,24 @@
-文件上传,当前只在vertx rest通道中可用,servlet rest的支持后续会增加。
+文件上传,当前支持在vertx rest通道和servlet rest中使用。
文件上传使用标准的http form格式,可与浏览器的上传直接对接。
## Producer:
+支持jaxrs和springmvc开发模式
-在jaxrs或springmvc开发模式下可用:
+jaxrs开发模式:
+* 支持servlet定义的javax.servlet.http.Part类型
-* 支持servlet定义的javax.servlet.http.Part类型,
+* 可以直接使用@FormParam传递文件类型及普通参数
-* Springmvc模式下,也支持org.springframework.web.multipart.MultipartFile
+springmvc开发模式:
-两种数据类型:
+* 支持servlet定义的javax.servlet.http.Part类型,也支持org.springframework.web.multipart.MultipartFile类型
-* 功能是一致的,MultipartFile的底层也是Part
+* 两种数据类型功能是一致的,MultipartFile的底层也是Part
-* 可以混合使用,比如第一个参数是Part,第二个参数是MultipartFile
+* 两种数据类型可以混合使用,比如第一个参数是Part,第二个参数是MultipartFile
+
+* 可以直接使用@RequestPart传递文件类型及普通参数
注意:
@@ -26,8 +30,6 @@
* 通过MultipartFile或Part打开流后,记得关闭,否则上传的临时文件会无法删除,最终导致上传临时目录被撑爆
-* 可以直接使用@RequestPart传递普通参数
-
Springmvc模式下的代码样例:
```java
@@ -89,6 +91,3 @@ String reseult = template.postForObject(
entry,
String.class);
```
-
-
-
diff --git a/java-chassis-reference/en_US/general-development/local-develop-test.md b/java-chassis-reference/en_US/general-development/local-develop-test.md
index f5c7b4f..e38f946 100644
--- a/java-chassis-reference/en_US/general-development/local-develop-test.md
+++ b/java-chassis-reference/en_US/general-development/local-develop-test.md
@@ -40,13 +40,11 @@
```
注意:前端(frontend)在Linux环境下默认会绑定ipv6地址,导致浏览器报错,修复办法为:先修改conf/app.conf中的httpaddr为外部可达网卡ip,之后修改app/appList/apiList.js中`ip : 'http://127.0.0.1'`为对应ip,最后重启ServiceCenter即可。
- {: .notice--warning}
</div>
</div>
注意:Window和Linux版本均只支持64位系统。
- {: .notice--warning}
2. 以Docker的方式运行
@@ -59,11 +57,11 @@ docker run -d -p 30100:30100 servicecomb/service-center:latest
```yaml
servicecomb:
- service:
- registry:
- address:
-http://127.0.0.1:30100
- #服务中心地址及端口
+ service:
+ registry:
+ address:
+ # 服务中心地址及端口
+ http://127.0.0.1:30100
```
* **步骤 3 **开发服务提供/消费者,启动微服务进行本地测试。
@@ -71,39 +69,48 @@ http://127.0.0.1:30100
**----结束**
## Mock机制启动服务中心
+在本进程内存中模拟一个只能本进程使用的服务中心,一般是在测试场景中使用。
+* ### 进程内调用
+只需要在启动ServiceComb引擎之前声明一下即可启用:
+```java
+System.setProperty("local.registry.file", "notExistJustForceLocal");
+```
+* ### 跨进程调用
+如果部署比较简单,并且部署信息是静态的,即使有跨进程调用也可以使用本Mock机制
+producer端仍然像“进程内调用”一样声明即可
+但是,因为Mock并不能跨进程生效,所以consumer端的Mock,需要提供一个本地的配置文件,在里面描述调用目标的详细信息,包括名字、版本、地址、schema id等等信息
+同样,因为Mock不能跨进程,consumer也无法动态取得producer的契约信息,所以,需要在本地提供契约文件
+(这个场景,使用Mock服务中心,比使用standalone的服务中心,成本高得多得多,不建议使用)
-* **步骤 1**新建本地服务中心定义文件registry.yaml,内容如下:
+* **步骤 1**新建本地服务中心定义文件,假设名字为registry.yaml,内容示例如下:
```yaml
-springmvctest:
- - id: "001"
- version: "1.0"
- appid: myapp #调试的服务id
- instances:
- - endpoints:
- - rest://127.0.0.1:8080
+localserv:
+ - id: "100"
+ version: "0.0.1"
+ appid: localservreg
+ schemaIds:
+ - hello
+ instances:
+ - endpoints:
+ - rest://localhost:8080
+ - highway://localhost:7070
```
+* **步骤 2**consumer本地部署契约文件
-#### 注意:mock机制需要自己准备契约,并且当前只支持在本地进行服务消费端\(consumer\)侧的调试,不支持服务提供者\(provider\)
-
-* **步骤 2**在服务消费者Main函数首末添加如下代码:
+参考:[定义服务契约](https://huaweicse.github.io/servicecomb-java-chassis-doc/zh_CN/build-provider/define-contract.html)
+* **步骤 3**在consumer main函数,启动ServiceComb引擎之前声明:
```java
-public class xxxClient {
-public static void main(String[] args) {
System.setProperty("local.registry.file", "/path/registry.yaml");
- // your code
- System.clearProperty("local.registry.file");
-}
```
setProperty第二个参数填写registry.yaml在磁盘中的系统绝对路径,注意区分在不同系统下使用对应的路径分隔符。
-* **步骤 3**开发服务消费者,启动微服务进行本地测试。
## 通过设置环境信息方便本地调试
java chassis在设计时,严格依赖于契约,所以正常来说契约变了就必须要修改微服务的版本。但是如果当前还是开发模式,那么修改接口是很正常的情况,每次都需要改版本的话,对用户来说非常的不友好,所以增加了一个环境设置。如果微服务配置成开发环境,接口修改了(schema发生了变化),重启就可以注册到服务中心,而不用修改版本号。但是如果有consumer已经调用了重启之前的服务,那么consumer端需要重启才能获取最新的schema。比如A -> B,B接口进行了修改并且重启,那么A这个时候还是使用B老的schema,调用可能会出错,以免出现未知异常,A也需要重启。有三种方式可以设置,推荐使用方法1
-* 方法1:通过JVM启动参数**-Dinstance_description.environment=dev**进行设置
+* 方法1:通过JVM启动参数**-Dinstance_description.environment=development**进行设置
* 方法2:通过microservice.yaml配置文件来指定
diff --git a/java-chassis-reference/en_US/general-development/produceprocess.md b/java-chassis-reference/en_US/general-development/produceprocess.md
new file mode 100644
index 0000000..6e204f0
--- /dev/null
+++ b/java-chassis-reference/en_US/general-development/produceprocess.md
@@ -0,0 +1,89 @@
+# 返回值序列化扩展
+## 概念阐述
+
+当前REST通道返回值支持application/json和text/plain两种格式,支持开发人员扩展和重写,服务提供者通过produces声明可提供序列化能力,服务消费者通过请求的Accept头指明返回值序列化方式,默认返回application/json格式的数据。
+
+## 开发说明
+
+* ### 扩展
+
+ 开发人员可以根据业务需要,通过编程的方式来扩展返回值序列化方式。实施步骤如下,以扩展支持application/xml格式为例:
+
+ 1.实现接口`ProduceProcessor`
+
+ > getName\(\)返回当前扩展的数据类型名
+ >
+ > getOrder\(\)返回当前数据类型优先级,有多个同名实现类时生效,只加载优先级最高的,数字越小优先级越高
+ >
+ > doEncodeResponse\(OutputStream output, Object result\)把result对象编码成output,此处逻辑需要自行实现
+ >
+ > doDecodeResponse\(InputStream input, JavaType type\)把input解析成相应对象,此处逻辑需要自行实现
+
+ ```java
+ public class ProduceAppXmlProcessor implements ProduceProcessor {
+
+ @Override
+ public String getName() {
+ return MediaType.APPLICATION_XML;
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public void doEncodeResponse(OutputStream output, Object result) throws Exception {
+ output.write(JAXBUtils.convertToXml(result).getBytes());
+ }
+
+ @Override
+ public Object doDecodeResponse(InputStream input, JavaType type) throws Exception {
+ return JAXBUtils.convertToJavaBean(input, type);
+ }
+ }
+ ```
+
+ 2.添加配置文件
+
+ 在resources下META-INF/services/文件夹新建文件xxx.ProduceProcessor(xxx为接口的包名),内容填写xxx.ProduceAppXmlProcessor(xxx为实现类的包名)。
+
+* ### 重写
+
+ 开发人员可以对现有的application/json和text/plain两种格式实现逻辑进行重写,也可以对自行扩展的格式进行重写,以重写xml序列化方式为例:
+
+ 1.创建一个同名类`ProduceAppXmlProcessor`,实现接口`ProduceProcessor`
+
+ 2.重写`doEncodeResponse`和`doDecodeResponse`方法里的编解码逻辑
+
+ 3.更改getOrder方法里的返回值,要比原方法的返回值小,例如返回-1,application/json和text/plain的原方法返回值默认都为0
+
+ 4.在resources下META-INF/services/文件夹新建文件xxx.ProduceProcessor(xxx为接口的包名),内容填写xxx.ProduceAppXmlProcessor(xxx为实现类的包名)。
+
+* ### 验证
+
+ 服务提供者通过produces声明可提供xml序列化能力
+
+ ```java
+ @RequestMapping(path = "/appXml", method = RequestMethod.POST, produces = MediaType.APPLICATION_XML_VALUE)
+ public JAXBPerson appXml(@RequestBody JAXBPerson person) {
+ return person;
+ }
+ ```
+
+ 服务消费者通过请求的Accept头指明返回值xml序列化方式
+
+ ```java
+ private void testCodeFirstAppXml(RestTemplate template, String cseUrlPrefix) {
+ JAXBPerson person = new JAXBPerson("jake", 22, "it", "60kg");
+ person.setJob(new JAXBJob("developer", "coding"));
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Accept", MediaType.APPLICATION_XML_VALUE);
+ HttpEntity<JAXBPerson> requestEntity = new HttpEntity<>(person, headers);
+ ResponseEntity<JAXBPerson> resEntity = template.exchange(cseUrlPrefix + "appXml",
+ HttpMethod.POST,
+ requestEntity,
+ JAXBPerson.class);
+ TestMgr.check(person, resEntity.getBody());
+ }
+ ```
diff --git a/java-chassis-reference/en_US/edge/secret-field.md b/java-chassis-reference/en_US/general-development/secret-field.md
similarity index 100%
rename from java-chassis-reference/en_US/edge/secret-field.md
rename to java-chassis-reference/en_US/general-development/secret-field.md
diff --git a/java-chassis-reference/en_US/introduction.md b/java-chassis-reference/en_US/introduction.md
index 76102a4..c25475d 100644
--- a/java-chassis-reference/en_US/introduction.md
+++ b/java-chassis-reference/en_US/introduction.md
@@ -1,3 +1,4 @@
+# 概述
Apache ServiceComb (incubating) Java Chassis 给开发者提供一个快速构建微服务的JAVA SDK。它包含如下特性:
* 多种开发风格,REST(JAX-RS、Spring MVC)和RPC
diff --git a/java-chassis-reference/en_US/question-and-answer/interface-compatibility.md b/java-chassis-reference/en_US/question-and-answer/interface-compatibility.md
index 8beaf54..2ef0fed 100644
--- a/java-chassis-reference/en_US/question-and-answer/interface-compatibility.md
+++ b/java-chassis-reference/en_US/question-and-answer/interface-compatibility.md
@@ -9,6 +9,9 @@
3. 作为Consumer,使用Provider的新接口时候,指定Provider的最小版本号。比如:servicecomb.references.\[serviceName\].version-rule=2.1.3+,其中serviceName为Provider的微服务名称。
4. 在服务中心,定期清理不再使用的老版本的微服务信息。
+ServiceComb还有如下一些注意事项:
+1. 修改微服务信息,必须升级版本号,因为服务注册的时候,不会覆盖已经注册的微服务信息。
+
# 接口兼容常见问题及其解决办法
开发阶段,由于存在频繁的接口修改,也不会清理服务中心的数据,容易出现调试的时候接口调用失败的情况。建议开发者可以安装下载一个[服务中心的frontend](http://apache.org/dyn/closer.cgi/incubator/servicecomb/incubator-servicecomb-service-center/1.0.0-m1/), 可以随时清理服务中心数据。
@@ -34,7 +37,3 @@
可能是Provider增加了接口,但是没有更新版本号。需要删除微服务数据或者更新版本号后重新启动Provider,并重启Consumer。
-
-*
-
-
diff --git a/java-chassis-reference/en_US/references-handlers/intruduction.md b/java-chassis-reference/en_US/references-handlers/intruduction.md
new file mode 100644
index 0000000..1a3131f
--- /dev/null
+++ b/java-chassis-reference/en_US/references-handlers/intruduction.md
@@ -0,0 +1,9 @@
+## 处理链参考
+处理链(Handlers)是ServiceComb的核心组成部分,它们构成服务运行管控的基础。ServiceComb通过处理链来处理负载均衡、熔断容错、流量控制等。
+
+## 开发处理链
+开发者自定义处理链包含如下几个步骤。由于ServiceComb的核心组成就是处理链,开发者可以参考handlers目录的实现详细了解处理链。下面简单总结下几个关键步骤:
+
+* 实现Handler接口
+* 增加*.handler.xml文件,给Handler取一个名字
+* 在microservice.yaml中启用新增加的处理链
diff --git a/java-chassis-reference/en_US/references-handlers/loadbalance.md b/java-chassis-reference/en_US/references-handlers/loadbalance.md
new file mode 100644
index 0000000..0265379
--- /dev/null
+++ b/java-chassis-reference/en_US/references-handlers/loadbalance.md
@@ -0,0 +1,172 @@
+# 负载均衡
+
+## 场景描述
+
+ServiceComb提供了非常强大的负载均衡能力。它的核心包括两部分,第一部分是DiscoveryTree,通过将微服务实例根据接口兼容性、数据中心、实例状态等分组,DiscoveryFilter是其主要组成部分;第二部分是基于Ribbon的负载均衡方案,支持随机、顺序、基于响应时间的权值等多种负载均衡路由策略IRule,以及可以支持Invocation状态的ServerListFilterExt。
+
+DiscoveryTree的逻辑比较复杂,可以通过下面的处理流程了解其处理过程。
+![](/assets/loadbalance-001.png)
+
+负载均衡适用于Consumer处理链,名称为loadbalance,示例如下:
+```
+servicecomb:
+ handler:
+ chain:
+ Consumer:
+ default: loadbalance
+```
+
+POM依赖:
+```
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-loadbalance</artifactId>
+ </dependency>
+```
+
+## 按照数据中心信息进行路由转发
+服务提供者和消费者都可以通过在microservice.yaml中声明自己的服务中心信息:
+```yaml
+servicecomb:
+ datacenter:
+ name: mydatacenter
+ region: my-Region
+ availableZone: my-Zone
+```
+
+消费者通过比较自己的数据中心信息和提供者的信息,优先将请求转发到region和availableZone都相同的实例;如果不存在,则转发到region相同的实例;如果仍然不存在,则转发到其他实例。
+
+这里的region和availableZone是一般性的概念,用户可以自行确定其业务含义以便应用于资源隔离的场景中。可以参见[微服务实例之间的逻辑隔离关系](/build-provider/definition/isolate-relationship.md),了解更多其他实例发现相关的隔离机制。
+
+该规则默认启用,如果不需要使用,可以通过servicecomb.loadbalance.filter.zoneaware.enabled进行关闭。数据中心信息隔离功能在ZoneAwareDiscoveryFilter实现。
+
+## 根据实例属性进行路由转发
+微服务可以指定实例的属性。实例属性可以在microservice.yaml中指定,也可以通过服务中心的API进行修改。
+```
+instance_description:
+ properties:
+ tag: mytag
+```
+
+消费者可以指定消费具备某些属性的实例,不访问其他实例
+```
+servicecomb:
+ loadbalance:
+ myservice:
+ transactionControl:
+ options:
+ tag: mytag
+```
+上面的配置表示只访问myservice所有实例中tag属性为mytag的实例。
+
+该规则需要给每个服务单独配置,未配置表示不启用该规则,不支持对于所有服务的全局配置。
+
+该规则默认启用,如果不需要使用,可以通过servicecomb.loadbalance.filter.instanceProperty.enabled进行关闭。根据实例属性进行路由转发功能在InstancePropertyDiscoveryFilter实现。
+
+## 实例隔离功能
+开发者可以配置实例隔离的参数,以暂时屏蔽对于错误实例的访问,提升系统可靠性和性能。下面是其配置项和缺省值
+```
+servicecomb:
+ loadbalance:
+ isolation:
+ enabled: true
+ errorThresholdPercentage: 0
+ enableRequestThreshold: 5
+ singleTestTime: 60000
+ continuousFailureThreshold: 2
+```
+
+隔离的统计周期是1分钟。按照上面的配置,在1分钟内,如果请求总数大于5,并且连续错误超过2次,那么就会将实例隔离。
+错误率默认值为0,表示不启用,可通过配置100以内的整数来启用,例如配置为20,则表示,在1分钟内,如果请求总数大于5,并且[1]错误率大于20%或者[2]连续错误超过2次,那么就会将实例隔离。
+实例隔离的时间是60秒,60秒后会尝试启用实例(还需要根据负载均衡策略确定是否选中)。
+
+注意事项:
+
+1. 当错误率达到设定值导致实例隔离后,要想恢复,需要等待隔离时间窗结束后的第一次成功请求进行周期性累加,直到总的错误率下降到设定值以下才行。由于请求总数是触发实例隔离的门槛,若请求总数达到设定值时计算出来的错误率远大于设定值,要想恢复是需要很久的。
+2. ServiceComb为了检测实例状态,在后台启动类一个线程,每隔10秒检测一次实例状态(如果实例在10秒内有被访问,则不检测),如果检测失败,每次检测会将错误计数加1。这里的计数,也会影响实例隔离。
+
+系统缺省的实例状态检测机制是发送一个telnet指令,参考SimpleMicroserviceInstancePing的实现。如果业务需要覆盖状态检测机制,可以通过如下两个步骤完成:
+
+1. 实现MicroserviceInstancePing接口
+2. 配置SPI:增加META-INF/services/org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing,内容为实现类的全名
+
+开发者可以针对不同的微服务配置不一样的隔离策略。只需要给配置项增加服务名,例如:
+```
+servicecomb:
+ loadbalance:
+ myservice:
+ isolation:
+ enabled: true
+ errorThresholdPercentage: 20
+ enableRequestThreshold: 5
+ singleTestTime: 10000
+ continuousFailureThreshold: 2
+```
+
+该规则默认启用,如果不需要使用,可以通过servicecomb.loadbalance.filter.isolation.enabled进行关闭。数据中心信息隔离功能在IsolationDiscoveryFilter实现。
+
+## 配置路由规则
+开发者可以通过配置项指定负载均衡策略。
+```
+servicecomb:
+ loadbalance:
+ strategy:
+ name: RoundRobin # Support RoundRobin,Random,WeightedResponse,SessionStickiness
+```
+
+开发者可以针对不同的微服务配置不一样的策略,只需要给配置项增加服务名,例如:
+```
+servicecomb:
+ loadbalance:
+ myservice:
+ strategy:
+ name: RoundRobin # Support RoundRobin,Random,WeightedResponse,SessionStickiness
+```
+
+每种策略还有一些专属配置项,也支持针对不同微服务进行配置。
+
+* SessionStickiness
+
+```
+servicecomb:
+ loadbalance:
+ SessionStickinessRule:
+ sessionTimeoutInSeconds: 30 # 客户端闲置时间,超过限制后选择后面的服务器
+ successiveFailedTimes: 5 # 客户端失败次数,超过后会切换服务器
+```
+
+## 设置重试策略
+负载均衡模块还支持配置失败重试的策略。
+```
+servicecomb:
+ loadbalance:
+ retryEnabled: false
+ retryOnNext: 0
+ retryOnSame: 0
+```
+缺省情况未启用重试。同时也支持对不同的服务设置特殊的策略:
+```
+servicecomb:
+ loadbalance:
+ myservice:
+ retryEnabled: true
+ retryOnNext: 1
+ retryOnSame: 0
+```
+
+retryOnNext表示失败以后,根据负载均衡策略,重新选择一个实例重试(可能选择到同一个实例)。 retryOnSame表示仍然使用上次失败的实例进行重试。
+
+## 自定义
+负载均衡模块提供的功能已经非常强大,能够通过配置支持大部分应用场景。同时它也提供了强大的扩展能力,包括DiscoveryFilter、ServerListFilterExt、ExtensionsFactory(扩展IRule,RetryHandler等)。loadbalance模块本身包含了每一个扩展的实现,这里不再详细描述如何扩展,只简单描述步骤。开发者可以自行下载ServiceComb源码进行参考。
+
+* DiscoveryFilter
+ * 实现DiscoveryFilter接口
+ * 配置SPI:增加META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter文件,内容为实现类的全名
+
+* ServerListFilterExt
+ * 实现ServerListFilterExt接口
+ * 配置SPI:增加META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt文件,内容为实现类的全名
+ * 注意:这个开发说明适用于1.0.0及其以后的版本,早期的版本开发方式不同。
+
+* ExtensionsFactory
+ * 实现ExtensionsFactory,并使用@Component将其发布为一个spring bean。
diff --git a/java-chassis-reference/en_US/references-handlers/publickey.md b/java-chassis-reference/en_US/references-handlers/publickey.md
new file mode 100644
index 0000000..4d540d7
--- /dev/null
+++ b/java-chassis-reference/en_US/references-handlers/publickey.md
@@ -0,0 +1,59 @@
+# 公钥认证
+
+## 场景描述
+
+公钥认证是ServiceComb提供的一种简单高效的微服务之间认证机制,它的安全性建立在微服务与服务中心之间的交互是可信的基础之上,即微服务和服务中心之间必须先启用认证机制。它的基本流程如下:
+
+1. 微服务启动的时候,生成秘钥对,并将公钥注册到服务中心。
+2. 消费者访问提供者之前,使用自己的私钥对消息进行签名。
+3. 提供者从服务中心获取消费者公钥,对签名的消息进行校验。
+
+公钥认证需要在消费者、提供者都启用。
+
+```
+servicecomb:
+ handler:
+ chain:
+ Consumer:
+ default: auth-consumer
+ Provider:
+ default: auth-provider
+```
+
+POM依赖:
+
+* 在pom.xml中增加依赖:
+
+ ```
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-publickey-auth</artifactId>
+ </dependency>
+ ```
+
+## 配置黑白名单
+
+基于公钥认证机制,ServiceComb提供了黑白名单功能。通过黑白名单,可以控制微服务允许其他哪些服务访问。目前支持通过配置服务属性来控制,配置项如下:
+
+```
+servicecomb:
+ publicKey:
+ accessControl:
+ black:
+ list01:
+ category: property ## property, fixed value
+ propertyName: serviceName ## property name
+# property value match expression.
+# only supports prefix match and postfix match and exactly match.
+# e.g. hacker*, *hacker, hacker
+ rule: hacker
+ white:
+ list02:
+ category: property
+ propertyName: serviceName
+ rule: cust*
+```
+
+以上规则配置了黑名单,不允许微服务名称为hacker的访问;白名单,允许微服务名称为cust前缀的服务访问。
+
+ServiceComb提供了[trust-sample](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/trust-sample)来演示黑白名单功能。
\ No newline at end of file
diff --git a/java-chassis-reference/en_US/security/shi-yong-rsa-ren-zheng.md b/java-chassis-reference/en_US/security/shi-yong-rsa-ren-zheng.md
index cf9fbf8..e66d2a2 100644
--- a/java-chassis-reference/en_US/security/shi-yong-rsa-ren-zheng.md
+++ b/java-chassis-reference/en_US/security/shi-yong-rsa-ren-zheng.md
@@ -2,7 +2,7 @@
用户通过简单的配置即可启用服务间RSA认证,以保障服务接口的安全性。
-
+详细介绍参考[公钥认证](../references-handlers/publickey.md)
## Consumer配置
diff --git a/java-chassis-reference/en_US/start/architecture.md b/java-chassis-reference/en_US/start/architecture.md
index 813b63f..33c5b3a 100644
--- a/java-chassis-reference/en_US/start/architecture.md
+++ b/java-chassis-reference/en_US/start/architecture.md
@@ -1,3 +1,5 @@
+# 微服务系统架构
+
## ![](/start/architecture.png)框架概述
## **主要设计意图**
@@ -23,6 +25,3 @@
| 运行模型 | handler-loadbalance | 是 | 负载均衡模块。提供各种路由策略和配置方法。一般客户端使用。 |
| 运行模型 | handler-bizkeeper | 是 | 和服务治理相关的功能,比如隔离、熔断、容错。 |
| 运行模型 | handler-tracing | 是 | 调用链跟踪模块,对接监控系统,吐出打点数据。 |
-
-
-
diff --git a/java-chassis-reference/en_US/start/development-environment.md b/java-chassis-reference/en_US/start/development-environment.md
index 50e07ee..fa5a25e 100644
--- a/java-chassis-reference/en_US/start/development-environment.md
+++ b/java-chassis-reference/en_US/start/development-environment.md
@@ -1,6 +1,6 @@
-
+# 安装本地开发环境
-应用开发环境所需安装的工具包括JDK、Maven和Eclipse。如果已经安装了这些开发工具,请跳过本节。
+应用开发环境所需安装的工具包括JDK、Maven、Eclipse 和 IDEA 。如果已经安装了这些开发工具,请跳过本节。
## JDK约束及安装步骤
@@ -53,7 +53,18 @@ e.(可选)设置本地仓库路径,用于保存从远程仓库获取的插
这里以路径D:\maven\repository为例。在/conf中找到settings.xml文件,设置localRepository为D:\maven\repository
-f.结果验证
+f. (可选)要想项目能够快速的下载各种依赖,建议配置下中心仓库。
+
+```
+ <mirror>
+ <id>mirrorId</id>
+ <mirrorOf>*</mirrorOf>
+ <name>Mirror of central repository.</name>
+ <url>http://maven.huaweicse.com/nexus/content/groups/public</url>
+ </mirror>
+```
+
+g.结果验证
使用mvn -version命令验证是否安装成功,windows环境下回显如下:
@@ -88,3 +99,26 @@ c.(可选)将之前Maven安装中介绍的插件m2eclipse解压到Eclipse安
d.启动Eclipse,配置jre、maven settings以及默认编码格式为utf-8。
+
+
+## IDEA安装
+
+### **前提条件**
+
+a.JDK已经安装。
+
+b.Maven已经安装。
+
+### **安装步骤**
+
+a. 在官方网站下载 IDEA 安装包,收费版或者社区版的按个人需求。
+
+b. 设置编码格式都为 utf-8。
+
+打开IDEA,选择 File -> Settings -> Editor -> File Encoding
+把 project Encoding 和 default encoding for properties files 改为 utf-8。
+
+c. 设置maven 配置
+
+打开IDEA,选择 File -> Settings -> Build,Execution,Deployment -> Bulid Tools -> Maven
+注意配置 Maven home directory 和 User settings file
diff --git a/java-chassis-reference/en_US/start/first-sample.md b/java-chassis-reference/en_US/start/first-sample.md
index 0c5cecc..3ec45f4 100644
--- a/java-chassis-reference/en_US/start/first-sample.md
+++ b/java-chassis-reference/en_US/start/first-sample.md
@@ -1,6 +1,9 @@
+# 开发第一个微服务
+
开发者可以通过两种方式快速构建一个项目:
-* 下载samples项目
+* 下载samples项目。建议把整个项目都下载下来,按照例子[ SpringMVC ](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/springmvc-sample)或者 [JAX RS](https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/samples/jaxrs-sample)进行初始化配置。
+
* 使用archetypes生成项目
开始之前,开发者需要先选择熟悉的开发方式,目前有3种方式可供选择:
diff --git a/java-chassis-reference/en_US/styles/website.css b/java-chassis-reference/en_US/styles/website.css
new file mode 100644
index 0000000..815fe4b
--- /dev/null
+++ b/java-chassis-reference/en_US/styles/website.css
@@ -0,0 +1,5 @@
+table {
+ table-layout: fixed;
+ display:block;
+ overflow-x: auto;
+}
\ No newline at end of file
diff --git a/java-chassis-reference/zh_CN/SUMMARY.md b/java-chassis-reference/zh_CN/SUMMARY.md
index 4e587d0..eac2340 100644
--- a/java-chassis-reference/zh_CN/SUMMARY.md
+++ b/java-chassis-reference/zh_CN/SUMMARY.md
@@ -60,6 +60,7 @@
* [CORS机制](general-development/CORS.md)
* [获取熔断与实例隔离告警事件信息](general-development/AlarmEvent.md)
* [优雅停机](general-development/shutdown.md)
+ * [异常处理](general-development/error-handling.md)
* [服务能力开放](edge/open-service.md)
* [使用Edge Service做边缘服务](edge/by-servicecomb-sdk.md)
* [使用confd和Nginx做边缘服务](edge/nginx.md)
diff --git a/java-chassis-reference/zh_CN/general-development/error-handling.md b/java-chassis-reference/zh_CN/general-development/error-handling.md
new file mode 100644
index 0000000..e53b573
--- /dev/null
+++ b/java-chassis-reference/zh_CN/general-development/error-handling.md
@@ -0,0 +1,163 @@
+# 异常处理
+
+ServiceComb异常情况可以分为三类:
+* 业务定义异常:这类异常由业务接口定义。用户在获取到服务swagger定义到时候,就能够从定义中看到这类异常对应的错误码,以及返回值类型。
+* 处理控制异常:这类异常通常是框架处理流程上的异常。比如流控Handler抛出TOO_MANY_REQUESTS_STATUS异常。
+
+```
+CommonExceptionData errorData = new CommonExceptionData("rejected by qps flowcontrol");
+asyncResp.producerFail(new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData));
+```
+
+* 未知异常:这类异常发生的情况不确定。比如业务代码实现的时候,抛出NullPointerException等未捕获异常、底层的网络连接超时异常等。这类异常会由ServiceComb封装成590或者490错误返回。比如:
+
+```
+CommonExceptionData errorData = new CommonExceptionData(cause.getMessage());
+asyncResp.producerFail(new InvocationException(590, errorData)
+
+或者
+asyncResp.consumerFail(new InvocationException(490, errorData)
+```
+
+
+## 业务定义异常
+
+通常业务在开发服务代码的时候,只有一个返回值,但有些情况,也需要视具体情况返回不同的消息。可以通过@ApiResonse来定义不同错误码对应的返回消息。业务异常具备确定的数据类型,并且会在swagger里面体现,客户端代码在处理异常的时候,能够直接获取到错误类型。比如下面的代码:
+
+```
+ @Path("/errorCode")
+ @POST
+ @ApiResponses({
+ @ApiResponse(code = 200, response = MultiResponse200.class, message = ""),
+ @ApiResponse(code = 400, response = MultiResponse400.class, message = ""),
+ @ApiResponse(code = 500, response = MultiResponse500.class, message = "")})
+ public MultiResponse200 errorCode(MultiRequest request) {
+ if (request.getCode() == 400) {
+ MultiResponse400 r = new MultiResponse400();
+ r.setCode(400);
+ r.setMessage("bad request");
+ throw new InvocationException(javax.ws.rs.core.Response.Status.BAD_REQUEST, r);
+ } else if (request.getCode() == 500) {
+ MultiResponse500 r = new MultiResponse500();
+ r.setCode(500);
+ r.setMessage("internal error");
+ throw new InvocationException(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR, r);
+ } else {
+ MultiResponse200 r = new MultiResponse200();
+ r.setCode(200);
+ r.setMessage("success result");
+ return r;
+ }
+ }
+```
+
+客户端代码可以按照如下方式处理异常。异常的类型是确定的,可以通过cast获取到异常类型。
+
+```
+ MultiRequest request = new MultiRequest();
+
+ request.setCode(200);
+ ResponseEntity<MultiResponse200> result = template
+ .postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse200.class);
+ TestMgr.check(result.getStatusCode(), 200);
+ TestMgr.check(result.getBody().getMessage(), "success result");
+
+ request.setCode(400);
+ MultiResponse400 t400 = null;
+ try {
+ template.postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse400.class);
+ } catch (InvocationException e) {
+ t400 = (MultiResponse400) e.getErrorData();
+ }
+ TestMgr.check(t400.getCode(), 400);
+ TestMgr.check(t400.getMessage(), "bad request");
+
+ request.setCode(500);
+ MultiResponse500 t500 = null;
+ try {
+ template.postForEntity(SERVER + "/MultiErrorCodeService/errorCode", request, MultiResponse400.class);
+ } catch (InvocationException e) {
+ t500 = (MultiResponse500) e.getErrorData();
+ }
+ TestMgr.check(t500.getCode(), 500);
+ TestMgr.check(t500.getMessage(), "internal error");
+```
+
+## 控制异常
+
+控制异常一般在接口定义里面没有声明。客户端在做异常处理的时候,不知道异常类型。可以采用弱类型的方式处理异常:
+
+```
+ JsonObject requestJson = new JsonObject();
+ requestJson.put("code", 400);
+ requestJson.put("message", "test message");
+
+ try {
+ template
+ .postForEntity(SERVER + "/MultiErrorCodeService/noClientErrorCode", requestJson, Object.class);
+ } catch (InvocationException e) {
+ TestMgr.check(e.getStatusCode(), 400);
+ mapResult = RestObjectMapperFactory.getRestObjectMapper().convertValue(e.getErrorData(), Map.class);
+ TestMgr.check(mapResult.get("message"), "test message");
+ TestMgr.check(mapResult.get("code"), 400);
+ TestMgr.check(mapResult.get("t400"), 400);
+ }
+```
+
+上面的代码假设不知道异常类型,通过API将异常类型转换为Map类型,然后从Map里面读取异常类型。在ServiceComb自己抛出的异常类型中,一般控制异常的类型也是固定的,为CommonExceptionData。
+
+## 未知异常
+
+未知异常统一被封装为490, 590错误码,异常消息的类型固定为CommonExceptionData类型。
+
+## 异常转换和定制
+
+有时候,业务需要将所有的未知异常、控制异常进行捕获,转换为对用户友好的消息。或者对控制异常进行捕获,将消息体转换为自定义的JSON格式。这里面有几个参考点。
+
+* 控制消息消息体序列化
+
+控制消息消息体序列化的目的是简化消费者的异常处理逻辑,不用使用弱类型,而是使用确切类型。可以采用注册全局的错误码类型。
+业务需要通过SPI实现org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper接口。接口的核心内容是为每个错误码制定序列化类型:
+```
+ private final static Map<Integer, ResponseMeta> CODES = new HashMap<>(1);
+
+ static {
+ ResponseMeta meta = new ResponseMeta();
+ meta.setJavaType(SimpleType.constructUnsafe(IllegalStateErrorData.class));
+ CODES.put(500, meta);
+ }
+
+ @Override
+ public Map<Integer, ResponseMeta> getMapper() {
+ return CODES;
+ }
+```
+
+* 异常转换
+
+如果业务不对异常进行转换,ServiceComb会将InvocationException中的data直接序列化到响应消息中。如果不是InvocationException,则转换为490, 590,序列化的消息为CommonExceptionData。业务可以通过SPI实现org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter对异常进行转换。该接口的核心是需要指定转换的类型,以及转换处理逻辑。
+
+```
+public class CustomExceptionToResponseConverter implements ExceptionToResponseConverter<IllegalStateException> {
+ @Override
+ public Class<IllegalStateException> getExceptionClass() {
+ return IllegalStateException.class;
+ }
+
+ @Override
+ public int getOrder() {
+ return 100;
+ }
+
+ @Override
+ public Response convert(SwaggerInvocation swaggerInvocation, IllegalStateException e) {
+ IllegalStateErrorData data = new IllegalStateErrorData();
+ data.setId(500);
+ data.setMessage(e.getMessage());
+ data.setState(e.getMessage());
+ InvocationException state = new InvocationException(Status.INTERNAL_SERVER_ERROR, data);
+ return Response.failResp(state);
+ }
+}
+
+```