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 2024/07/29 02:02:09 UTC
(servicecomb-docs) branch master updated: update faq documents (#349)
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/servicecomb-docs.git
The following commit(s) were added to refs/heads/master by this push:
new 8625797 update faq documents (#349)
8625797 is described below
commit 86257977672f73771887615b93684fefd77e0d18
Author: liubao68 <bi...@qq.com>
AuthorDate: Mon Jul 29 10:02:05 2024 +0800
update faq documents (#349)
---
.../zh_CN/docs/question-and-answer/faq.md | 304 +++------------------
.../question-and-answer/interface-compatibility.md | 142 ----------
.../docs/question-and-answer/question_answer.md | 281 -------------------
java-chassis-reference/zh_CN/mkdocs.yml | 6 +-
4 files changed, 38 insertions(+), 695 deletions(-)
diff --git a/java-chassis-reference/zh_CN/docs/question-and-answer/faq.md b/java-chassis-reference/zh_CN/docs/question-and-answer/faq.md
index 6289757..f984c3d 100644
--- a/java-chassis-reference/zh_CN/docs/question-and-answer/faq.md
+++ b/java-chassis-reference/zh_CN/docs/question-and-answer/faq.md
@@ -1,54 +1,50 @@
# 常见问题
-* [Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?](#Q2)
-* [Q: Map类型的key必须使用 String 类型?](#Q3)
-* [Q: 参数返回值不能使用接口?](#Q4)
-* [Q: 参数返回值不能使用泛型?](#Q5)
-* [Q: 实现类中 public 方法全部被发布为接口,如何排除?](#Q6)
-* [Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?](#Q7)
+> 如果在使用Java Chassis的过程中碰到问题或者疑问,可以在 [Java Chassis Github Issues](https://github.com/apache/servicecomb-java-chassis/issues) 提交问题和搜索答案。
-<h2 id="Q2">Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?</h2>
+* [Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?](#Q1)
+* [Q: Map类型的key必须使用 String 类型?](#Q2)
+* [Q: 参数返回值不能使用接口?](#Q3)
+* [Q: 参数返回值不能使用泛型?](#Q4)
+* [Q: 实现类中 public 方法全部被发布为接口,如何排除?](#Q5)
+* [Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?](#Q6)
+
+<h2 id="Q1">Q: 契约生成会报错 Caused by: java.lang.Error: OperationId must be unique,不支持函数重载?</h2>
+
+* A: 支持函数重载,但是需要注意每个接口必须有唯一的operation id。可以加上`@Operation`标签给重载的接口指定唯一
+ 的 operation id。示例代码如下:
-* A: 支持函数重载,但是需要注意每个接口必须有唯一的operation id。可以加上`@ApiOperation`标签给重载的接口指定唯一
- 的 operation id (对应于 nickname 属性)。示例代码如下:
-
```java
- @Path("/sayHi")
+ @Path("/sayHello")
@GET
@Produces("text/plain;charset=UTF-8")
- @ApiOperation(value = "", nickname = "sayHi")
+ @Operation(operationId = "sayHello", summary = "say hello without parameter")
public String sayHello() {
- return "ApiOperationJaxrsSchema#sayHello";
+ return "Hello";
}
- @Path("/sayHello")
+ @Path("/sayHelloName")
@GET
@Produces("application/json;charset=UTF-8")
- @ApiOperation(value = "", nickname = "sayHello")
+ @Operation(operationId = "sayHelloName", summary = "say hello with name parameter")
public String sayHello(@ApiParam("name") String name) {
- return name;
+ return "Hello " + name;
}
```
-
-
-<h2 id="Q3">Q: Map类型的 key 必须使用 String 类型?</h2>
+<h2 id="Q2">Q: Map类型的 key 必须使用 String 类型?</h2>
* A: 是的。java-chassis 遵循 [Open API 规范](https://swagger.io/docs/specification/data-models/dictionaries/), MAP
类型的 key 必须使用 String 类型。 业务可以结合实际情况,使用符合规范的类型。 如果必须使用其他类型,
可以考虑接口定义使用 Object 规避,客户端可以对返回值结果自行进行 json 转换。
-
-
-
-<h2 id="Q4">Q: 参数返回值不能使用接口?</h2>
-* A: 是的。java-chassis 不允许参数、返回值的类型为 `Interface` 或者 `Abstract Class`。因为这些类型
- 无法正确的生成 swagger 描述。如果必须使用这些类型,可以考虑接口定义使用 Object 规避,客户端可以对返回值结果
- 自行进行 json 转换。
+<h2 id="Q3">Q: 参数返回值不能使用接口?</h2>
+* A: 是的。java-chassis 不允许参数、返回值的类型为 `Interface` 或者 `Abstract Class`。因为这些类型 无法生成正确的 swagger 描述。如果必须使用这些类型,可以考虑接口定义使用 Object 规避,客户端可以对返回值结果自行进行 json 转换。
-<h2 id="Q5">Q: 参数返回值不能使用泛型?</h2>
+
+<h2 id="Q4">Q: 参数返回值不能使用泛型?</h2>
* A: 可以使用泛型。但是必须明确泛型类型。比如:
@@ -77,268 +73,40 @@
}
```
-如果业务必须使用泛型,并且不能确定类型,可以考虑接口定义使用 Object 规避,客户端可以对返回值结果
-自行进行 json 转换。
+如果业务必须使用泛型,并且不能确定类型,可以考虑接口定义使用 Object 规避,客户端可以对返回结果自行进行 json 转换。
-<h2 id="Q6">Q: 实现类中 public 方法全部被发布为接口,如何排除?</h2>
+<h2 id="Q5">Q: 实现类中 public 方法全部被发布为接口,如何排除?</h2>
-* A: java chassis 会将所有 public 方法发布为接口。 如果有些接口不需要发布为接口,可以使用 @ApiOperation
+* A: java chassis 会将所有 public 方法发布为接口。 如果有些接口不需要发布为接口,可以使用 @Operation
标签声明不发布为接口。例子如下:
-
+
```java
- @ApiOperation(value = "", hidden = true)
+ @Operation(summary = "", hidden = true)
public void hidden() {
}
```
-在迁移改造的过程中,比如将 HSF 和 Dubbo 的内部 RPC 接口改造为 java-chassis 的 RPC 接口,可能还有更加复杂
-的情况,比如:
-
-```java
-@HSFProvider(MyInterface.class)
-public MyService extends AbstractMyService implements MyInterface
-```
-
-如果直接改造为
+更加复杂的情况,比如:
```java
@RpcSchema(schemaId = "MyService")
-public MyService extends AbstractMyService implements MyInterface
-```
-
-那么 `AbstractMyService` 的公共方法也会发布为 RPC 接口, 而 HSF 和 dubbo 则不会。 这种情况建议增加
-一个类,而将原来的接口声明为服务类来处理, 比如:
-
-```java
-@Service("MyService")
-public MyService extends AbstractMyService implements MyInterface
-
-@RpcSchema(schemaId = "MyServiceImpl")
-public MyServiceImpl implements MyInterface {
- @Autowired
- @Qualifier("MyService")
- MyInterface service;
-
- public String hello(String name) {
- return service.hello(name);
- }
+public MyService extends AbstractMyService implements MyInterface {
+
}
```
-
-
-<h2 id="Q7">Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?</h2>
-
-* A: 对于 2xx 的返回值,可以通过 @ApiResponse 实现,例如:
+那么 `AbstractMyService` 的公共方法也会发布为 RPC 接口。 这种情况可以声明为只发布接口里面的方法, 比如:
```java
-@ApiResponse(code = 201, response = Integer.class, message = "")
-public int test(int x) {
- return 100;
-}
-```
-
-对于其他返回值,可以通过抛出自定义的 InvocationException 实现,例如:
+@RpcSchema(schemaId = "MyService", schemaInterface = MyInterface.class)
+public MyService extends AbstractMyService implements MyInterface {
-```java
-@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;
- }
}
```
-* **Q: 如何定制自己微服务的日志配置?**
-
- * A: ServiceComb不绑定日志器,只是使用了slf4j,用户可以自由选择log4j/log4j2/logback等等。ServiceComb提供了一个log4j的扩展,在标准log4j的基础上,支持log4j的properties文件的增量配置。
- * 默认以规则:"classpath\*:config/log4j.properties"加载配置文件
- * 实际会搜索出classpath中所有的```config/log4j.properties和config/log4j.*.properties```, 从搜索出的文件中切出```\*```的部分,进行alpha排序,然后按顺序加载,最后合成的文件作为log4j的配置文件。
- * 如果要使用ServiceComb的log4j扩展,则需要调用Log4jUtils.init,否则完全按标准的日志器的规则使用。
-
-* **Q: 当服务配置了多个transport的时候,在运行时是怎么选择使用哪个transport的?**
-
- * A: ServiceComb的consumer、transport、handler、producer之间是解耦的,各功能之间通过契约定义联合在一起工作的,即:
- consumer使用透明rpc,还是springmvc开发与使用highway,还是RESTful在网络上传输没有关系与producer是使用透明rpc,还是jaxrs,
- 或者是springmvc开发,也没有关系handler也不感知,业务开发方式以及传输方式。consumer访问producer,在运行时的transport选择上,
- 总规则为:cnsumer的transport与producer的endpoint取交集,如果交集后,还有多个transport可选择,则轮流使用,分解开来,存在以下场景:
-
- * 当一个微服务producer同时开放了highway以及RESTful的endpoint
- * consumer进程中只部署了highway transport jar,则只会访问producer的highway endpoint
- * consumer进程中只部署了RESTful transport jar,则只会访问producer的RESTful endpoint
- * consumer进程中,同时部署了highway和RESTful transport jar,则会轮流访问producer的highway、RESTful endpoint
-
- * 如果consumer想固定使用某个transport访问producer,可以在consumer进程的microservice.yaml中配置,指定transport的名称:
-
- servicecomb:
- references:
- <service_name>:
- transport: highway
-
- * 当一个微服务producer只开放了highway的endpoint
- * consumer进程只部署了highway transport jar,则正常使用highway访问
- * consumer进程只部署了RESTful transport jar,则无法访问
- * consumer进程同时部署了highway和RESTful transport jar,则正常使用highway访问
-
- * 当一个微服务producer只开放了RESTful的endpoint
- * consumer进程只部署了highway transport jar,则无法访问
- * consumer进程只部署了RESTful transport jar,则正常使用RESTful访问
- * consumer进程同时部署了highway和RESTful transport jar,则正常使用RESTful访问
-
-* **Q: ServiceComb微服务框架服务调用是否使用长连接?**
-
- * A: http使用的是长连接(有超时时间),highway方式使用的是长连接(一直保持)。
-
-* **Q: 服务断连服务中心注册信息是否自动删除**
-
- * A: 服务中心心跳检测到服务实例不可用,只会移除服务实例信息,服务的静态数据不会移除。
-
-* **Q: 如果使用tomcat方式集成ServiceComb微服务框架,如何实现服务注册**
-
- * A: 如果使用ServiceComb sdk servlet方式(使用transport-rest-servlet依赖)制作为war包部署到tomcat,需要保证,
- 服务描述文件(microservice.yaml)中rest端口配置和外置容器一致才能实现该服务的正确注册。否则无法感知tomcat开放端口。
-
-* **Q: 如果使用tomcat方式集成ServiceComb微服务框架,服务注册的时候如何将war包部署的上下文注册到服务中心**
-
- * A: 发布服务接口的时候需要将war包部署的上下文(context)放在baseurl最前面,这样才能保证注册到服务中心的路径是完整的路径(包含了上下文)。示例:
-
- @path(/{context}/xxx)
- class ServiceA
-
-* **Q: ServiceComb微服务框架如何实现数据多个微服务间透传**
-
- * A: 透传数据塞入:
-
- CseHttpEntity<xxxx.class> httpEntity = new CseHttpEntity<>(xxx);
- //透传内容
- httpEntity.addContext("contextKey","contextValue");
- ResponseEntity<String> responseEntity = RestTemplateBuilder.create()
- .exchange("cse://springmvc/springmvchello/sayhello",HttpMethod.POST,httpEntity,String.class);
-
- 透传数据获取:
-
- @Override
- @RequestMapping(path="/sayhello",method = RequestMethod.POST)
- public String sayHello(@RequestBody Person person,InvocationContext context){
- //透传数据获取
- context.getContext();
- return "Hello person " + person.getName();
- }
-
-* **Q: ServiceComb body Model部分暴露**
-
- * A: 一个接口对应的body对象中,可能有一些属性是内部的,不想开放出去,生成schema的时候不要带出去,使用:
-
- @ApiModelProperty(hidden = true)
-
-* **Q: 服务超时设置**
-
- * A: 在微服务描述文件(microservice.yaml)中添加如下配置:
-
- servicecomb:
- request:
- timeout: 30000
-
-* **Q: URL 地址就可以唯一定位,为什么要加上一个schema?**
-
- * A:
- 1. schema 是用来匹配服务契约的,用来保证服务端和消费端契约兼容,每个契约需要一个唯一ID,在服务中心存储。
- 2. schema映射到java的interface概念,在consumer使用透明rpc模式开发时,可以找到是微服务里的哪个operation。schema之间的方法名是没有唯一性要求的。
- 3. operation qualified name是治理的key,而URL 因为path参数的存在,没办法直接查找,而qualified name是不会变的。治理是不区分传输的,如果治理按URL 走,那么highway调进来时,还得根据参数反向构造出url,再来正则表达式匹配,太折腾了。
- 4. http只是一种传输通道,还有别的传输通道不需要映射到URL的。
-
-* **Q: rest客户端调用的时候,实际上只带上了服务名和URL,并不需要指定schema id的, 而实际上根据这个URL也能找到具体契约的,所以指定schema id作用何在?**
-
- * A: 由于透明rpc是接口式调用,并没有URL,内部实际都归一化到operation来描述的,这样就可以结合schema id唯一定位到具体的请求处理中。
-
-* **Q: Transport是个什么概念?用来干什么的?**
-
- * A: transport负责编解码,以及传输。通信模型有rest和highway两种,highway对应的是私有协议,使用protobuf编码,rest用的是json。highway和rest都是基于vertx做的,vertx是基于netty的。
-
-* **Q: ServiceComb和服务中心是怎么交互的?**
-
- * A: 走rest,主要负责注册,取数据和心跳等;watch事件走websocket,watch事件是观察服务中心实例信息有没有变更。
-
-* **Q: 有类似dubbo那种治理中心吗?**
-
- * A: bizkeeper是一个handler,是治理的其中一个内容。治理可以通过handler扩展。
-
-* **Q: service path怎么理解?**
-
- * A: 每个微服务有一个servicePathManager,每一个schema将自己的path注册进去。
-
-* **Q: 浏览器能直接访问微服务Endpoint吗?**
-
- * A: 可以,restful发布的微服务Endpoint,可以直接在浏览器中使用HTTP加service path访问提供get方法的服务,如果是访问其他Http方法提供的服务建议安装使用[Postman](https://www.sap.com/developer/tutorials/api-tools-postman-install.html)。
-
-* **Q: 契约生成时,需要强制带上版本号和语言吗?**
-
- * A: 契约是属于微服务的,微服务本来就有版本,但语言是不应该带上版本号的。应该契约要求与语言无关。契约“没有版本”,契约的版本体现在微服务上,实例能找到所属的微服务的版本,就能找到一个确定的契约。
-
-* **Q: 如果同时引入了`transport-rest-servlet`和`transport-rest-vertx`的依赖,那么它怎么决定采用哪一个?**
-
- * A: 如果端口没被占用,就用vertx;如果被占用了,就用servlet。
-
-
-* **Q: qps流控设计时是出于什么场景考虑的?**
-
- * A: 限流有两个主要作用,第一通过给不同的消费者限流保证对一些重点服务的服务效果,第二防止雪崩效应。可根据服务的重要性来决定水管的粗细,ServiceComb是支持消费端限流和服务端限流两种限流方式的,消费端限流可以做到比较精细的控制。
-
-
-* **Q: 如果服务端是链式调用,即类似a->b->c,那设置了qps 流控会不会造成水管粗细不均的事情?**
-
- * A: 一般采取的模式是先测量再设置。qps设置最终是结合整体业务需求来进行调控的,而不是就单个节点来进行设置。
-
-* **Q: 如何在契约DTO中忽略中指定的属性?**
-
- * A: 可以使用@JsonIgnore注解标记需要忽略的属性, 例如:
-
- ```java
- public class OutputForTest{
- @JsonIgnore
- private String outputId = null;
- private String inputId = null;
- ...
- }
- ```
-
- * **Q: 如何使用数据压缩传输的能力?**
-
- * A: 服务端要开启响应数据压缩传输的能力,需要进行如下配置:
+<h2 id="Q6">Q: 如何自定义某个Java方法对应的REST接口里的HTTP Status Code?</h2>
- ```yaml
- servicecomb:
- rest:
- server:
- compression: true
- ```
- 同时,消费端需要同步开启配置项:
- ```yaml
- servicecomb:
- rest:
- client:
- connection:
- compression: true
- ```
- 当消费端在请求头中设置Accept-Encoding:gzip, deflate的字段时,服务端就会依据该字段中提供的算法,对响应数据进行压缩处理,并返回。
+* A: 参考[多个返回值和错误码](../build-provider/multi-code.md)
diff --git a/java-chassis-reference/zh_CN/docs/question-and-answer/interface-compatibility.md b/java-chassis-reference/zh_CN/docs/question-and-answer/interface-compatibility.md
deleted file mode 100644
index 445f3dc..0000000
--- a/java-chassis-reference/zh_CN/docs/question-and-answer/interface-compatibility.md
+++ /dev/null
@@ -1,142 +0,0 @@
-# 微服务接口兼容常见问题
-
-在进行微服务持续迭代开发的过程中,由于新特性不停的加入,一些过时的特性不停的修改,接口兼容问题面临巨大的挑战,特别是在允许多版本共存(灰度发布)的环境。本章节主要描述接口兼容管理的一些实践建议,以及在使用ServiceComb过程中碰到了兼容性问题的解决办法。由于微服务一般都通过REST接口对外提供服务,没有特殊说明的情况下,这里的接口都指REST接口。
-
-## 保证接口兼容的实践
-
-为了防止接口兼容问题,开发者在进行接口变更(新增、修改、删除等)的时候,建议遵循下面的一些原则。
-
-* 只增加接口,不修改、不删除接口。
-
-* 作为Provider,增加接口的时候,相应的将微服务版本号递增,比如将2.1.2修改为2.1.3。版本号按照规范使用x.y.z的格式,只包含数字便于管理,建议每位数字不大于125。
-
-* 作为Consumer,使用Provider的新接口时候,指定Provider的最小版本号。比如:
-
-```
-servicecomb:
- references:
- ProviderMicroserviceName: # 修改为Provide的微服务名称
- version-rule: 2.1.3+
-```
-
-其中serviceName为Provider的微服务名称。
-
-* 在服务中心,定期清理不再使用的老版本的微服务信息。
-
-如果微服务的版本号没有变化,微服务启动的时候,不会覆盖服务中心的老版本数据,从Consumer的角度,看到的是老版本接口。ServiceComb缺省情况下,如果出现接口变更,并且微服务版本号没有修改,启动会失败,这样就强制要求开发者必须修改版本号,避免将问题遗漏到生产环节。对于新项目,接口修改和调整可能非常频繁,建议增加如下配置,可以不用修改版本号:
-
-```
-service_description:
- environment: development
-```
-
-这个配置项使得Provider开发简单了,如果Consumer已经启动,并且希望调用新的接口,那么Consumer仍然需要重启。
-
-## 接口兼容常见问题及其解决办法
-
-- 开发阶段,由于存在频繁的接口修改,又不想频繁修改版本号,容易本地和服务中心契约不一致,且契约未被允许更新到服务中心,导致调试的时候接口调用失败的情况。
-
-推荐使用ServiceComb提供了微服务按environment区分、隔离的能力(当前支持development和production),允许处于development环境的微服务在不升级版本的情况下,仅需重启服务即可重新注册契约到服务中心。
-
-所有微服务在microservice.yaml中增如下配置,且需要在Provider启动后,再重启Consumer(若请求走edge,需要重启edge服务):
-
-```
-service_description:
- name: xxx-service
- version: 0.0.1
- environment: development
-```
-
-
-
-- 开发阶段,由于存在频繁的接口修改,也不会清理服务中心的数据,容易出现调试的时候接口调用失败的情况。
-
-推荐使用华为公有云在线的服务中心,可以直接登录使用微服务引擎提供的微服务管理功能删除微服务或微服务实例。微服务引擎也提供了[本地轻量化服务中心](https://console.huaweicloud.com/cse/?region=cn-north-1#/cse/tools),将服务停止后即可清理服务中心数据。服务中心及其frontend代码已开源,[项目地址](https://github.com/apache/incubator-servicecomb-service-center)。
-
-
-- 发布阶段,需要审视下接口兼容的实践的步骤,确保不在线上引入接口兼容问题。如果不小心漏了其中的某个步骤,则可能导致如下一些接口兼容问题:
-
-- [ ] 如果修改、删除接口:导致一些老的Consumer将请求路由到新的Provider,调用失败。
-
-解决办法:指定Provider的版本号、或修改Consumer适配新的Provider。
-
-- [ ] 如果忘记修改微服务版本号:导致一些新的Consumer将请求路由到老的Provider,调用失败。
-
-解决办法:升级Provider版本号、删除老的Provider实例、重启Consumer。
-
-- [ ] 如果忘记配置Consumer的最小依赖版本:当部署顺序为先停止Consumer,再启动Consumer,再停止Provider,再启动Provider的情况,Consumer无法获取到新接口信息,就采用了老接口,当Provider启动以后,Consumer发起对新接口的调用会失败;或者在Provider没启动前,调用新接口失败等。
-
-解决办法:建议先启动Provider,再启动Consumer。
-
-通用规避措施:出现的接口兼容问题不同,处理方式会有差异。极端情况,只需要清理Provider、Consumer的微服务信息,然后重启微服务即可。当服务调用关系复杂的情况下,接口兼容问题影响范围会更加广泛,同时清理Provider、Consumer数据会变得复杂,因此建议遵循上面的规范,避免不兼容的情况发生。
-
-
-
-## 常见的接口不兼容情况的日志
-
-* consumer method \[com.huawei.paas.cse.demo.CodeFirstPojoIntf:testUserMap\] not exist in swagger
-
-可能是Provider增加了接口,但是没有更新版本号。需要删除微服务数据或者更新版本号后重新启动Provider,并重启Consumer。
-
-
-
-* 契约或接口变更(含增删查改、参数变化等),但environment未设定为development,契约不允许更新。schemaId为download、upload的两个契约已存在,但新增的schemaId为TaskTemplateController的无法注册,相应接口自然会调用失败。需要升级版本号,或指定environment为development。
-
-```
-2018-06-14 22:51:55,239 [ERROR] SchemaIds is different between local and service center. Please change microservice version. id=1f4c94c66fe011e8945700ff37174dd4 appId=uploadapp, name=upload-service, version=0.0.1, local schemaIds=[download, upload, TaskTemplateController], service center schemaIds=[download, upload] org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.checkSchemaIdSet(MicroserviceRegisterTask.java:116)
-2018-06-14 22:51:55,243 [INFO] schemaId download exists true org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
-2018-06-14 22:51:55,246 [INFO] schemaId upload exists true org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
-2018-06-14 22:51:55,249 [WARN] get response for org.apache.servicecomb.serviceregistry.api.response.GetExistenceResponse failed, 400:Bad Request, {"errorCode":"400016","errorMessage":"Schema does not exist","detail":"schema does not exist."}
- org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.lambda$null$0(ServiceRegistryClientImpl.java:118)
-2018-06-14 22:51:55,250 [INFO] schemaId TaskTemplateController exists false org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
-2018-06-14 22:51:55,258 [ERROR] Register schema 1f4c94c66fe011e8945700ff37174dd4/TaskTemplateController failed, statusCode: 400, statusMessage: Bad Request, description: {"errorCode":"400014","errorMessage":"Undefined schema id","detail":"schemaId non-exist, can't be added, environment is production"}
-. org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.registerSchema(ServiceRegistryClientImpl.java:306)
-```
-
-* Provider无可用版本,请查Provider和Consumer是否属于同一environment(默认为Production),且成功注册到服务中心。
-
-```
-2018-06-15 11:03:56,045 [ERROR] invoke failed, invocation=PRODUCER rest customer-service.reactiveClient.hello org.apache.servicecomb.swagger.invocation.exception.DefaultExceptionToResponseConverter.convert(DefaultExceptionToResponseConverter.java:35)
-java.lang.IllegalStateException: Probably invoke a service before it is registered, appId=uploadapp, name=upload-service
- at org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory.getOrCreateMicroserviceMeta(ConsumerSchemaFactory.java:90)
- at org.apache.servicecomb.core.provider.consumer.ReferenceConfig.<init>(ReferenceConfig.java:36)
- at org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager.getReferenceConfig(ConsumerProviderManager.java:82)
-```
-
-* 本地开发调试时无法使用部分云上仪表盘功能,会出现下述异常,不影响功能,可以忽略。可以通过设置servicecomb.monitor.client.enable为false禁用仪表盘功能。
-
-```
-2018-06-14 22:23:59,407 [WARN] {"errorCode":"400012","errorMessage":"Micro-service does not exist","detail":"provider not exist, consumer 8e24bc416fde11e8945700ff37174dd4 find provider default/CseMonitoring/latest"}
- org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.lambda$null$4(ServiceRegistryClientImpl.java:199)
-2018-06-14 22:23:59,408 [ERROR] Can not find any instances from service center due to previous errors. service=default/CseMonitoring/latest org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry.findServiceInstances(AbstractServiceRegistry.java:256)
-```
-
-* 下面两种错误(前者直接消费upload-service,后者通过edge-service消费upload-service)均表示接口未注册到服务中心或消费者未拿到最新契约,调用报locate path failed. 请排除:1、Provider对应接口契约已注册到服务中心,内容与本地应用启动时输出一致;2、确保Consumer和edge-service在Provider启动后,手动重启以重新获取Provider契约信息;3、Debug启动Consumer,找到ConsumerSchemaFactory类中的loadSwagger(位于servicecomb的java-chassis-core包中),查看schemaContent内容是否拿到Consumer对应契约内容。
-
-```
-2018-06-15 14:52:45,312 [ERROR] locate path failed, status:Not Found, http method:GET, path:/favicon.ico/, microserviceName:upload-service org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:72)
-```
-
-```
-2018-06-15 14:56:35,342 [ERROR] locate path failed, status:Not Found, http method:POST, path:/taskTemplate/uploadTaskTemplate/, microserviceName:upload-service org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:72)
-2018-06-15 14:56:35,344 [ERROR] edge server failed. org.apache.servicecomb.edge.core.AbstractEdgeDispatcher.onFailure(AbstractEdgeDispatcher.java:33)
-InvocationException: code=404;msg=CommonExceptionData [message=Not Found]
- at org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:77)
- at org.apache.servicecomb.common.rest.locator.ServicePathManager.consumerLocateOperation(ServicePathManager.java:107)
- at org.apache.servicecomb.edge.core.EdgeInvocation.locateOperation(EdgeInvocation.java:114)
- at org.apache.servicecomb.common.rest.AbstractRestInvocation.findRestOperation(AbstractRestInvocation.java:77)
- at org.apache.servicecomb.edge.core.EdgeInvocation.edgeInvoke(EdgeInvocation.java:66)
- at com.huawei.cse.houseapp.edge.ApiDispatcher.onRequest(ApiDispatcher.java:84)
- at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:223)
-```
-
-* 消费接口时Content-Type不一致将报参数非法,如前端使用form-data,Provider需要application/json
-
-```
-2018-06-27 14:51:13,939 [ERROR] invoke failed, invocation=PRODUCER rest loadbalance-isolation-server.hello.sayHello org.apache.servicecomb.swagger.invocation.exception.DefaultExceptionToResponseConverter.convert(DefaultExceptionToResponseConverter.java:35)
-java.lang.IllegalArgumentException: argument type mismatch
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
- at java.lang.reflect.Method.invoke(Method.java:498)
-```
diff --git a/java-chassis-reference/zh_CN/docs/question-and-answer/question_answer.md b/java-chassis-reference/zh_CN/docs/question-and-answer/question_answer.md
deleted file mode 100644
index 0ff38ec..0000000
--- a/java-chassis-reference/zh_CN/docs/question-and-answer/question_answer.md
+++ /dev/null
@@ -1,281 +0,0 @@
-# 问题描述:如何自定义某个Java方法对应的REST接口里的HTTP Status Code?
-
-** 解决方法:**
-
-对于正常的返回值,可以通过SwaggerAnnotation实现,例如:
-
-```java
-@ApiResponse(code = 300, response = String.class, message = "")
-public int test(int x) {
- return 100;
-}
-```
-
-对于异常的返回值,可以通过抛出自定义的InvocationException实现,例如:、
-
-```java
- public String testException(int code) {
- String strCode = String.valueOf(code);
- switch (code) {
- case 200:
- return strCode;
- case 456:
- throw new InvocationException(code, strCode, strCode + " error");
- case 556:
- throw new InvocationException(code, strCode, Arrays.asList(strCode + " error"));
- case 557:
- throw new InvocationException(code, strCode, Arrays.asList(Arrays.asList(strCode + " error")));
- default:
- break;
- }
-
- return "not expected";
- }
-```
-
-# 问题描述: 如何定制自己微服务的日志配置
-
-** 解决方法:**
-ServiceComb不绑定日志器,只是使用了slf4j,用户可以自由选择log4j/log4j2/logback等等。ServiceComb提供了一个log4j的扩展,在标准log4j的基础上,支持log4j的properties文件的增量配置。
-
-* 默认以规则:"classpath\*:config/log4j.properties"加载配置文件
-* 实际会搜索出classpath中所有的`config/log4j.properties和config/log4j.*.properties`, 从搜索出的文件中切出`\*`的部分,进行alpha排序,然后按顺序加载,最后合成的文件作为log4j的配置文件。
-* 如果要使用ServiceComb的log4j扩展,则需要调用Log4jUtils.init,否则完全按标准的日志器的规则使用。
-
-# 问题描述: 当服务配置了多个transport的时候,在运行时是怎么选择使用哪个transport的?
-
-** 解决方法:**
-
-* ServiceComb的consumer、transport、handler、producer之间是解耦的,各功能之间通过契约定义联合在一起工作的,即:
- consumer使用透明rpc,还是springmvc开发与使用highway,还是RESTful在网络上传输没有关系与producer是使用透明rpc,还是jaxrs,或者是springmvc开发,也没有关系handler也不感知,业务开发方式以及传输方式
-
-* consumer访问producer,在运行时的transport选择上,总规则为:
- consumer的transport与producer的endpoint取交集,如果交集后,还有多个transport可选择,则轮流使用
-
-分解开来,存在以下场景:
-
-* 当一个微服务producer同时开放了highway以及RESTful的endpoint
- * consumer进程中只部署了highway transport jar,则只会访问producer的highway endpoint
- * consumer进程中只部署了RESTful transport jar,则只会访问producer的RESTful endpoint
- * consumer进程中,同时部署了highway和RESTful transport jar,则会轮流访问producer的highway、RESTful endpoint
-
-如果,此时consumer想固定使用某个transport访问producer,可以在consumer进程的microservice.yaml中配置,指定transport的名称:
-
-```
-servicecomb:
- references:
- transport:
- <service_name>: highway
-```
-
-* 当一个微服务producer只开放了highway的endpoint
-
- * consumer进程只部署了highway transport jar,则正常使用higway访问
- * consumer进程只部署了RESTful transport jar,则无法访问
- * consumer进程同时部署了highway和RESTful transport jar,则正常使用highway访问
-
-* 当一个微服务producer只开放了RESTful的endpoint
-
- * consumer进程只部署了highway transport jar,则无法访问
- * consumer进程只部署了RESTful transport jar,则正常使用RESTful访问
- * consumer进程同时部署了highway和RESTful transport jar,则正常使用RESTful访问
-
-# 问题描述: swagger body参数类型定义错误,导致服务中心注册的内容没有类型信息
-
-**现象描述:**
-
-定义如下接口,将参数放到body传递
-
-```
-/testInherate:
- post:
- operationId: "testInherate"
- parameters:
- - in: "body"
- name: "xxxxx"
- required: false
- type: string
- responses:
- 200:
- description: "response of 200"
- schema:
- $ref: "#/definitions/ReponseImpl"
-```
-
-采用上面方式定义接口。在服务注册以后,从服务中心查询下来的接口type: string 丢失,变成了:
-
-```
-/testInherate:
- post:
- operationId: "testInherate"
- parameters:
- - in: "body"
- name: "xxxxx"
- required: false
- responses:
- 200:
- description: "response of 200"
- schema:
- $ref: "#/definitions/ReponseImpl"
-```
-
-如果客户端没有放置swagger,还会报告如下异常:
-
-Caused by: java.lang.ClassFormatError: Method "testInherate" in class ? has illegal signature "
-
-**解决方法:**
-
-定义body参数的类型的时候,需要使用schema,不能直接使用type。
-
-```
-/testInherate:
- post:
- operationId: "testInherate"
- parameters:
- - in: "body"
- name: "request"
- required: false
- schema:
- type: string
- responses:
- 200:
- description: "response of 200"
- schema:
- $ref: "#/definitions/ReponseImpl"
-```
-
-# 问题描述:微服务框架服务调用是否使用长连接
-
-** 解决方法:**
-
-http使用的是长连接(有超时时间),highway方式使用的是长连接(一直保持)。
-
-# 问题描述:服务断连服务中心注册信息是否自动删除
-
-** 解决方法:**
-
-服务中心心跳检测到服务实例不可用,只会移除服务实例信息,服务的静态数据不会移除。
-
-
-# 问题描述:微服务框架如何实现数据多个微服务间透传
-
-** 解决方法:**
-
-透传数据塞入:
-
-```java
-CseHttpEntity<xxxx.class> httpEntity = new CseHttpEntity<>(xxx);
-//透传内容
-httpEntity.addContext("contextKey","contextValue");
-ResponseEntity<String> responseEntity = RestTemplateBuilder.create().exchange("cse://springmvc/springmvchello/sayhello",HttpMethod.POST,httpEntity,String.class);
-```
-
-透传数据获取:
-
-```java
-@Override
-@RequestMapping(path="/sayhello",method = RequestMethod.POST)
-public String sayHello(@RequestBody Person person,InvocationContext context){
- //透传数据获取
- context.getContext();
- return "Hello person " + person.getName();
-}
-```
-
-# 问题描述:微服务框架服务如何自定义返回状态码
-
-** 解决方法:**
-
-```java
-@Override
-@RequestMapping(path = "/sayhello",method = RequestMethod.POST)
-public String sayHello(@RequestBody Person person){
- InvocationContext context = ContextUtils.getInvocationContext();
- //自定义状态码
- context.setStatus(Status.CREATED);
- return "Hello person "+person.getName();
-}
-```
-
-# 问题描述: body Model部分暴露
-
-** 解决方法:**
-
-一个接口对应的body对象中,可能有一些属性是内部的,不想开放出去,生成schema的时候不要带出去,使用:
-
-```java
-@ApiModelProperty(hidden = true)
-```
-
-# 问题描述:框架获取远端consumer的地址
-
-** 解决方法:**
-
-如果使用http rest方式(使用transport-rest-vertx依赖)可以用下面这种方式获取:
-
-```java
-HttpServletRequest request = (HttpServletRequest) invocation.getHandlerContext().get(RestConst.REST_REQUEST);
-String host = request.getRemoteHost();
-```
-
-实际场景是拿最外层的地址,所以应该是LB传入到edgeservice,edgeService再放到context外下传递。
-
-
-# 问题描述:对handler描述
-
-** 解决方法:**
-
-consumer默认的handler是simpleLB,没有配置的时候handler链会使用这个,如果配置了handler,里面一定要包含lb的handler,否则调用报错,需要在文档里面进行说明。
-
-
-# 问题描述:netty版本问题
-
-** 解决方法:**
-
-netty3和netty4是完全不同的三方件,因为坐标跟package都不相同,所以可以共存,但是要注意小版本问题,小版本必须使用的版本。
-
-# 问题描述:服务超时设置
-
-** 解决方法:**
-
-在微服务描述文件(microservice.yaml)中添加如下配置:
-
-```
-servicecomb:
- request:
- timeout: 30000
-```
-
-# 问题描述:服务治理的处理链顺序是否有要求?
-
-**解决方法:**
-
-处理链的顺序不同,那么系统工作行为也不同。 下面列举一下常见问题。
-
-1、loadbalance和bizkeeper-consumer
-
-这两个顺序可以随机组合。但是行为是不一样的。
-
-当loadbalance在前面的时候,那么loadbalance提供的重试功能会在bizkeeper-consumer抛出异常时发生,比如超时等。但是如果已经做了fallbackpolicy配置,比如returnnull,那么loadbalance则不会重试。
-
-如果loadbalance在后面,那么loadbalance的重试会延长超时时间,即使重试成功,如果bizkeeper-consumer设置的超时时间不够,那么最终的调用结果也是失败。
-
-2、tracing-consumer,sla-consumer,tracing-provider,sla-provider
-
-这些处理链建议放到处理链的最开始位置,保证成功、失败的情况都可以记录日志(由于记录日志需要IP等信息,对于消费者,只能放到loadbalance后面)。
-
-如果不需要记录客户端返回的异常,则可以放到末尾,只关注网络层返回的错误。但是如果bizkeeper-consumer等超时提前返回的话,则可能不会记录日志。
-
-3、建议的顺序
-
-Consumer: loadbalance, tracing-consumer, sla-consumer, bizkeeper-consumer
-
-Provider: tracing-provider, sla-provider, bizkeeper-provider
-
-这种顺序能够满足大多数场景,并且不容易出现不可理解的错误。
-
-# 问题描述: 文件上传中配置项最大请求大小的含义
-
-配置项: servicecomb.uploads.maxSize
-
-含义: 请求体中允许的最大字节数,默认值为-1,表示没有限制。
diff --git a/java-chassis-reference/zh_CN/mkdocs.yml b/java-chassis-reference/zh_CN/mkdocs.yml
index 2a70aa7..6c8734e 100644
--- a/java-chassis-reference/zh_CN/mkdocs.yml
+++ b/java-chassis-reference/zh_CN/mkdocs.yml
@@ -130,10 +130,8 @@ nav:
- 2.8.0 升级 3.0.0指导: upgrading/2_8_0T3_0_0.md
- 常用配置项参考:
- REST Transport Client 配置项: config-reference/rest-transport-client.md
-- 常见问题:
- - 'FAQ' : question-and-answer/faq.md
- - 'Q & A' : question-and-answer/question_answer.md
- - 微服务接口兼容常见问题: question-and-answer/interface-compatibility.md
+- 常见问题: question-and-answer/faq.md
+
theme: material
plugins:
- search