diff --git a/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md b/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md index 3b092a4..84c317b 100644 --- a/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md +++ b/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md @@ -13,3 +13,4 @@ * [Java Chassis 3技术解密:接口维度负载均衡](secrets/load-balancer-operation.md) * [Java Chassis 3技术解密:实用的可观测性](secrets/observability.md) * [Java Chassis 3技术解密:流式响应和人工智能应用开发](secrets/sse.md) +* [Java Chassis 3技术解密:WebSocket和人工智能应用开发](secrets/websocket.md) diff --git a/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md b/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md new file mode 100644 index 0000000..1dd4e20 --- /dev/null +++ b/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md @@ -0,0 +1,199 @@ +# Java Chassis 3技术解密:WebSocket和人工智能应用开发 + +前一篇《Java Chassis 3技术解密:流式响应和人工智能应用开发》解密了Java Chassis 3使用流式响应和SSE开发人工智能应用的功能。为了获取更好的用户体验和提升人工智能后台资源调度效率,WebSocket的双向通信特征在人工智能场景也经常被采用。 + +以最常见的知识问答为例:当用户输入一段文本,人工智能会逐段生成应答,用户根据结果,提出新的问题和发表疑问,人工智能根据新的信息重新计算应答。在一些复杂的对话场景,人工智能的响应可能被打断,需要根据用户的输入时刻对处理结果进行调整。 + +人工智能的处理后台需要保留用户会话上下文,并针对该会话合理调度处理资源和缓存会话信息。 + +Java Chassis 3提供了非常简洁的WebSocket支持,满足上述场景对于微服务开发框架功能的要求。 + +## 使用WebSocket + +首先,看看微服务架构下一个简单的调用场景。 + + 前端(浏览器) -> 应用网关(edge service) -> 消费者微服务 -> 提供者微服务 + +* 提供者微服务:定义WebSocket服务和响应用户请求 + +定义WebSocket非常简单,只需要使用 `Transport` 标签声明接口方法为 `WEBSOCKET` ,参数使用 `ServerWebSocket`。 + +```java +@RestSchema(schemaId = "WebsocketController") +@RequestMapping(path = "/ws") +public class WebsocketController { + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + AtomicInteger receiveCount = new AtomicInteger(0); + serverWebsocket.writeTextMessage("hello", r -> { + }); + serverWebsocket.textMessageHandler(s -> { + receiveCount.getAndIncrement(); + }); + serverWebsocket.closeHandler((v) -> System.out.println("closed")); + new Thread(() -> { + for (int i = 0; i < 5; i++) { + serverWebsocket.writeTextMessage("hello " + i, r -> { + }); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + serverWebsocket.writeTextMessage("total " + receiveCount.get()); + serverWebsocket.close(); + }).start(); + } +} +``` + +上述例子使用后台线程给消费者写入5条消息,并记录收取到的消息次数,最终写入收取到消息次数。 Open API并没有对双向流式通信做出规范定义,Java Chassis 3要求WebSocket的方法使用 `Post`。 + +`WebSocket`是一个新的 `Tranport`, 但是它直接构建于 `REST` 之上,因此底层实现复用了 `Rest Over Vert.x` 通信协议,只需要在其上增加 `websocketEnabled` 和 `websocket-prefix`两个参数。 需要注意Websocket接口定义的URL前缀需要和`websocket-prefix`保持一致。 + +```yaml +servicecomb: + rest: + address: 0.0.0.0:9094?websocketEnabled=true + server: + websocket-prefix: /ws +``` + +* 消费者微服务: 消费提供者WebSocket,并对外提供新的WebSocket服务 + +消费者可以像调用普通REST接口一样调用WebSocket,开发起来非常简单。 + +```java +@RestSchema(schemaId = "ClientWebsocketController") +@RequestMapping(path = "/ws") +public class ClientWebsocketController { + interface ProviderService { + WebSocket websocket(); + } + + @RpcReference(schemaId = "WebsocketController", microserviceName = "provider") + private ProviderService providerService; + + @PostMapping("/websocket") + @Transport(name = CoreConst.WEBSOCKET) + public void websocket(ServerWebSocket serverWebsocket) { + WebSocket providerWebSocket = providerService.websocket(); + providerWebSocket.closeHandler(v -> serverWebsocket.close()); + providerWebSocket.textMessageHandler(m -> { + System.out.println("send message " + m); + serverWebsocket.writeTextMessage(m); + }); + serverWebsocket.textMessageHandler(m -> { + System.out.println("receive message " + m); + providerWebSocket.writeTextMessage(m); + }); + } +} +``` + +上述代码消费提供者的WebSocket服务,实现将前端的消息写给提供者,并将提供者的消息返回给前端。 和提供者微服务一样,也需要在配置文件增加 `websocketEnabled` 和 `websocket-prefix`两个参数。 + +* 应用网关:透明转发 + +应用网关无需开发代码,可以实现透明转发,只需要在配置文件里面启用WebSocket和设置路由信息。 + +```yaml +servicecomb: + rest: + address: 0.0.0.0:9090?websocketEnabled=true + server: + websocket-prefix: /ws + + http: + dispatcher: + edge: + websocket: + mappings: + consumer: + prefixSegmentCount: 0 + path: "/ws/.*" + microserviceName: consumer + versionRule: 0.0.0+ +``` + +上述代码将前端 `/ws/.*` 路径下的WebSocket请求转发给后端的 `consumer` 服务。 + +* 前端(浏览器):消费WebSocket + +大部分浏览器都支持通过 `WebSocket` 与后端交互。下面是简单的代码片段: + +```javascript + + +WebSocket Test + +

WebSocket Test

+
+ +``` + +上述代码将收取到的消息打印在控制台,并将消息写回服务器。 + +## WebSocket、SSE、Long/Short Polling + +WebSocket、SSE、Long/Short Polling都被应用于人工智能场景,它们都有各自的优点和适用场景。WebSocket可以提供最好的用户体验,但是在扩容、大规模并发方面会面临问题。Long/Short Polling可以提供更好的扩展性和可靠性,但是开发难度大,用户体验差。 SSE是两者非常好的权衡。 + +> 在 `小艺` 人工智能应用中,为了提供更好的交互体验和提升后端资源调度能力,需要选择WebSocket。WebSocket在整个应用系统中使用的比例并不高,为了部分场景引入一个新的技术,开发和维护成本非常高。Java Chassis 3 的WebSocket功能具备和普通RPC/REST接口一样简单的开发体验,能够帮助开发团队提升开发效率和降低维护成本。