| <!DOCTYPE html> |
| <html class="writer-html5" lang="en" > |
| <head> |
| <meta charset="utf-8" /> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <link rel="shortcut icon" href="../img/favicon.ico" /> |
| <title>使用 Edge Service 做网关 - ServiceComb Java Chassis 开发指南</title> |
| <link rel="stylesheet" href="../css/theme.css" /> |
| <link rel="stylesheet" href="../css/theme_extra.css" /> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/github.min.css" /> |
| |
| <script> |
| // Current page data |
| var mkdocs_page_name = "\u4f7f\u7528 Edge Service \u505a\u7f51\u5173"; |
| var mkdocs_page_input_path = "edge/by-servicecomb-sdk.md"; |
| var mkdocs_page_url = null; |
| </script> |
| |
| <script src="../js/jquery-3.6.0.min.js" defer></script> |
| <!--[if lt IE 9]> |
| <script src="../js/html5shiv.min.js"></script> |
| <![endif]--> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script> |
| <script>hljs.initHighlightingOnLoad();</script> |
| </head> |
| |
| <body class="wy-body-for-nav" role="document"> |
| |
| <div class="wy-grid-for-nav"> |
| <nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav"> |
| <div class="wy-side-scroll"> |
| <div class="wy-side-nav-search"> |
| <a href="../index.html" class="icon icon-home"> ServiceComb Java Chassis 开发指南 |
| </a> |
| </div> |
| |
| <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu"> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../toc.html">目录</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../index.html">概述</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../start/catalog.html">快速入门</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../start/design.html">设计选型参考</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../build-provider/definition/service-definition.html">微服务定义</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../build-provider/catalog.html">开发服务提供者</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../build-consumer/catalog.html">开发服务消费者</a> |
| </li> |
| </ul> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../general-development/catalog.html">通用功能开发</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">多样化的通信协议功能参考</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../transports/introduction.html">多协议介绍</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../transports/rest-over-servlet.html">REST over Servlet</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../transports/rest-over-vertx.html">REST over Vertx</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../transports/http2.html">REST over HTTP2</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../transports/highway-rpc.html">Highway</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">多样化的服务注册与发现功能参考</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../registry/introduction.html">注册发现说明</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../registry/service-center.html">使用服务中心</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../registry/local-registry.html">本地注册发现</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../registry/distributed.html">去中心化注册发现</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">管理服务配置</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../config/general-config.html">通用配置说明</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../config/read-config.html">在程序中读取配置信息</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">服务治理功能参考</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/intruduction.html">处理链介绍</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/loadbalance.html">负载均衡</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/ratelimit.html">限流</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/router.html">灰度发布</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/fault-injection.html">故障注入</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/governance.html">流量特征治理</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/fail-retry.html">快速失败和重试</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">网关功能参考</span></p> |
| <ul class="current"> |
| <li class="toctree-l1"><a class="reference internal" href="open-service.html">介绍</a> |
| </li> |
| <li class="toctree-l1 current"><a class="reference internal current" href="by-servicecomb-sdk.html">使用 Edge Service 做网关</a> |
| <ul class="current"> |
| <li class="toctree-l2"><a class="reference internal" href="#edge-service_1">开发 Edge Service 服务</a> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#_1">工作流程</a> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#header">定制公共转发 Header</a> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#_2">定制路由规则</a> |
| <ul> |
| <li class="toctree-l3"><a class="reference internal" href="#defaultedgedispatcher">使用 DefaultEdgeDispatcher</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#urlmappededgedispatcher">使用 URLMappedEdgeDispatcher</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#commonhttpedgedispatcher">使用 CommonHttpEdgeDispatcher</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#dispatcher">自定义 Dispatcher</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#_3">进行认证鉴权和其他业务处理</a> |
| </li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#_4">部署示例</a> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#_5">工作模式</a> |
| <ul> |
| <li class="toctree-l3"><a class="reference internal" href="#reactive">reactive (默认)</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#_6">线程池</a> |
| </li> |
| </ul> |
| </li> |
| <li class="toctree-l2"><a class="reference internal" href="#demo">DEMO功能说明</a> |
| <ul> |
| <li class="toctree-l3"><a class="reference internal" href="#1dispatcher">1.注册Dispatcher</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#getorder">getOrder</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#init">init</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#2">2.转发请求</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#3">3.设置兼容规则</a> |
| </li> |
| <li class="toctree-l3"><a class="reference internal" href="#4">4.鉴权</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="zuul.html">使用 `zuul` 和 `spring cloud gateway` 做网关</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="nginx.html">nginx 网关简单介绍</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">安全特性参考</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../references-handlers/publickey.html">公钥认证</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../security/tls.html">使用TLS通信</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../security/shi-yong-rsa-ren-zheng.html">使用RSA认证</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">服务打包和运行</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../packaging/standalone.html">以standalone模式打包</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../packaging/web-container.html">以WEB容器模式打包</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">专题文章</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../using-java-chassis-in-spring-boot/using-java-chassis-in-spring-boot.html">在Spring Boot中使用java chassis</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../featured-topics/features.html">新功能介绍系列文章</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../featured-topics/compatibility.html">兼容问题和兼容性策略</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../featured-topics/upgrading.html">升级指导系列文章</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../featured-topics/performance.html">性能问题分析和调优</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">常用配置项参考</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../config-reference/rest-transport-client.html">REST Transport Client 配置项</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../config-reference/config-center-client.html">Config Center Client 配置项</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../config-reference/service-center-client.html">Service Center Client 配置项</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../config-reference/kie-client.html">ServiceComb Kie Client 配置项</a> |
| </li> |
| </ul> |
| <p class="caption"><span class="caption-text">常见问题</span></p> |
| <ul> |
| <li class="toctree-l1"><a class="reference internal" href="../question-and-answer/faq.html">FAQ</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../question-and-answer/question_answer.html">Q & A</a> |
| </li> |
| <li class="toctree-l1"><a class="reference internal" href="../question-and-answer/interface-compatibility.html">微服务接口兼容常见问题</a> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </nav> |
| |
| <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> |
| <nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu"> |
| <i data-toggle="wy-nav-top" class="fa fa-bars"></i> |
| <a href="../index.html">ServiceComb Java Chassis 开发指南</a> |
| |
| </nav> |
| <div class="wy-nav-content"> |
| <div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation"> |
| <ul class="wy-breadcrumbs"> |
| <li><a href="../index.html" class="icon icon-home" alt="Docs"></a> »</li> |
| <li>网关功能参考 »</li> |
| <li>使用 Edge Service 做网关</li> |
| <li class="wy-breadcrumbs-aside"> |
| </li> |
| </ul> |
| <hr/> |
| </div> |
| <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> |
| <div class="section" itemprop="articleBody"> |
| |
| <h1 id="edge-service">使用 Edge Service 做网关</h1> |
| <p>Edge Service 是ServiceComb 提供的JAVA网关服务开发框架。Edge Service作为整个微服务系统对外的接口,向最终用户提供服务,接入RESTful请求,转发给内部微服务。Edge Service以开发框架的形式提供,开发者可以非常简单的搭建一个Edge Service服务,通过简单的配置就可以定义路由转发规则。同时Edge Service支持强大的扩展能力,服务映射、请求解析、加密解密、鉴权等逻辑都可以通过扩展实现。</p> |
| <p>Edge Service 本身也是一个微服务,需遵守所有微服务开发的规则。其本身可以部署为多实例,前端使用负载均衡装置进行负载分发;也可以部署为主备,直接接入用户请求。开发者可以根据Edge Service承载的逻辑和业务访问量、组网情况来规划。</p> |
| <h2 id="edge-service_1">开发 Edge Service 服务</h2> |
| <p>开发 Edge Service 和开发一个普通的微服务步骤差不多,开发者可以从导入<a href="https://github.com/apache/incubator-servicecomb-java-chassis/tree/master/demo/demo-edge">ServiceComb Edge Service Demo</a>入手。从头搭建项目包含如下几个步骤:</p> |
| <ul> |
| <li>配置依赖关系</li> |
| </ul> |
| <p>在项目中加入edge-core的依赖,就可以启动Edge Service的功能。Edge Service在请求转发的时候,会经过处理链,因此还可以加入相关的处理链的模块的依赖,下面的实例增加的负载均衡的处理链,这个是必须的。</p> |
| <pre><code><dependency> |
| <groupId>org.apache.servicecomb</groupId> |
| <artifactId>edge-core</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.apache.servicecomb</groupId> |
| <artifactId>handler-loadbalance</artifactId> |
| </dependency> |
| </code></pre> |
| <ul> |
| <li>定义启动类</li> |
| </ul> |
| <p>和开发普通微服务一样,可以通过加载Spring的方式将服务拉起来。</p> |
| <pre><code>public class EdgeMain { |
| public static void main(String[] args) throws Exception { |
| Log4jUtils.init(); |
| BeanUtils.init(); |
| } |
| } |
| </code></pre> |
| <ul> |
| <li>增加配置文件microservie.yaml</li> |
| </ul> |
| <p>Edge Service本身也是一个微服务,遵循微服务查找的规则,自己也会进行注册。注意APPLICAIONT_ID与需要转发的微服务相同。在下面的配置中,指定了Edge Service监听的地址,处理链等信息。其中auth处理链是DEMO项目中自定义的处理链,用于实现认证。同时auth服务本身,不经过这个处理链,相当于不鉴权。</p> |
| <pre><code>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 |
| </code></pre> |
| <h2 id="_1">工作流程</h2> |
| <p>Edge Service的工作流程如下,蓝色背景部分在Eventloop线程中执行,黄色背景部分: |
| * 如果工作于reactive模式,则直接在Eventloop线程执行 |
| * 如果工作于线程池模式,则在线程池的线程中执行 |
| <img alt="" src="../assets/workFlow.png" /></p> |
| <h2 id="header">定制公共转发 Header</h2> |
| <p>Edge Service 在转发请求的时候, 会默认过滤掉 <code>公共请求头</code> 。 也就是除了 <strong>Provider</strong> 端显示 声明需要的 <code>HEADER</code> 外, 其他的 header 在转发的时候都会丢失。用户可以通过配置相关参数保留 公共请求头。</p> |
| <pre><code class="language-yaml">servicecomb: |
| edge: |
| filter: |
| addHeader: |
| # 开启 公共请求头保留功能。默认 false |
| enabled: true |
| # 要保留的公共请求头,以逗号隔开 |
| allowedHeaders: external_1,external_2 |
| </code></pre> |
| <p>如果对接了配置中心, 可以在配置中心动态修改 配置 <code>servicecomb.edge.filter.addHeader.enabled</code> 和 <code>servicecomb.edge.filter.addHeader.allowedHeaders</code> , 配置动态生效。</p> |
| <h2 id="_2">定制路由规则</h2> |
| <p>使用Edge Service的核心工作是配置路由规则。场景不同,规则也不同。 |
| 路由规则由一系列AbstractEdgeDispatcher组成。Edge Service提供了几个常见的Dispatcher,通过配置即可启用,如果这些Dispatcher不满足业务场景需要,还可以自定义。</p> |
| <h3 id="defaultedgedispatcher">使用 DefaultEdgeDispatcher</h3> |
| <p>DefaultEdgeDispatcher是一个非常简单、容易管理的Dispatcher,使用这个Dispatcher,用户不用动态管理转发规则,应用于实际的业务场景非常方便,这个也是推荐的一种管理机制。它包含如下几个配置项:</p> |
| <pre><code>servicecomb: |
| http: |
| dispatcher: |
| edge: |
| default: |
| enabled: true |
| prefix: rest |
| withVersion: true |
| prefixSegmentCount: 1 |
| </code></pre> |
| <p>常见的这些配置项的示例及含义如下:</p> |
| <ul> |
| <li>[prefix=rest;withVersion=true;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。</li> |
| <li>[prefix=rest;withVersion=true;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。</li> |
| <li>[prefix=rest;withVersion=true;prefixSegmentCount=3]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/v1/abc,请求只转发到[1.0.0-2.0.0)版本的微服务实例。</li> |
| <li>[prefix=rest;withVersion=false;prefixSegmentCount=1]微服务xService提供的URL为: /xService/v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,请求可能转发到任意微服务实例。</li> |
| <li>[prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /v1/abc,通过Edge访问的地址为/rest/xService/v1/abc,,请求可能转发到任意微服务实例。</li> |
| <li>[prefix=rest;withVersion=false;prefixSegmentCount=2]微服务xService提供的URL为: /abc,通过Edge访问的地址为/rest/xService/abc,,请求可能转发到任意微服务实例。</li> |
| </ul> |
| <p>withVersion配置项提供了客户端灰度规则,可以让客户端指定访问的服务端版本。Edge Service还包含根据接口兼容性自动路由的功能,请求会转发到包含了该接口的实例。假设某微服务,兼容规划为所有高版本必须兼容低版本,部署了以下版本实例:</p> |
| <ul> |
| <li> |
| <p>1.0.0,提供了operation1</p> |
| </li> |
| <li> |
| <p>1.1.0,提供了operation1、operation2</p> |
| </li> |
| </ul> |
| <p>Edge Service在转发operation1时,会自动使用1.0.0+的规则来过滤实例</p> |
| <p>Edge Service在转发operation2时,会自动使用1.1.0+的规则来过滤实例</p> |
| <p>以上过程用户不必做任何干预,全自动完成,以避免将新版本的operation转发到旧版本的实例中去。</p> |
| <h3 id="urlmappededgedispatcher">使用 URLMappedEdgeDispatcher</h3> |
| <p>URLMappedEdgeDispatcher 允许用户配置URL和微服务的映射关系。使用它可以非常灵活的定义哪些URL转发到哪些微服务。它包含如下几个配置项:</p> |
| <pre><code class="language-yaml">servicecomb: |
| http: |
| dispatcher: |
| edge: |
| url: |
| enabled: true |
| pattern: /(.*) ## 默认值,一般不需要配置 |
| mappings: |
| businessV1: |
| prefixSegmentCount: 1 |
| path: "/url/business/v1/.*" |
| microserviceName: business |
| versionRule: 1.0.0-2.0.0 |
| businessV2: |
| prefixSegmentCount: 1 |
| path: "/url/business/v2/.*" |
| microserviceName: business |
| versionRule: 2.0.0-3.0.0 |
| </code></pre> |
| <p>businessV1配置项表示的含义是将请求路径为/usr/business/v1/.<em>的请求,转发到business这个微服务,并且只转发到版本号为1.0.0-2.0.0的实例(不含2.0.0)。转发的时候URL为/business/v1/.</em>。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。</p> |
| <p>从上面的配置可以看出,URLMappedEdgeDispatcher也支持客户端灰度。当然配置项会比DefaultEdgeDispatcher多。URLMappedEdgeDispatcher支持通过配置中心动态的修改配置,调整路由规则。</p> |
| <h3 id="commonhttpedgedispatcher">使用 CommonHttpEdgeDispatcher</h3> |
| <p>CommonHttpEdgeDispatcher 能够将请求转发到监听 HTTP 或者 HTTP 2 协议的 Provider, 对于 Provider 的开发框架没有限制,也不 |
| 要求 Provider 注册契约信息。 </p> |
| <pre><code class="language-yaml">servicecomb: |
| http: |
| dispatcher: |
| edge: |
| http: |
| enabled: true |
| pattern: /(.*) ## 默认值,一般不需要配置 |
| mappings: |
| businessV2: |
| prefixSegmentCount: 1 |
| path: "/http/business/v2/.*" |
| microserviceName: business |
| versionRule: 2.0.0 |
| </code></pre> |
| <p>CommonHttpEdgeDispatcher 配置项的含义和 URLMappedEdgeDispatcher 类似。</p> |
| <h3 id="dispatcher">自定义 Dispatcher</h3> |
| <p>自定义Dispatcher包含两个步骤:</p> |
| <ol> |
| <li>实现AbstractEdgeDispatcher</li> |
| <li>通过SPI发布:增加文件META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,并写入实现类</li> |
| </ol> |
| <p>详细的代码细节可以参考下面的章节"DEMO功能说明"。开发者也可以参考DefaultEdgeDispatcher等代码来定义自己的Dispatcher。</p> |
| <h3 id="_3">进行认证鉴权和其他业务处理</h3> |
| <p>通过Edge Servie工作流程可以看出,可以通过多种方式来扩展Edge Service的功能,包括Dispatcher、HttpServerFilter、Handler、HttpClientFilter等。比较常用和简单的是通过Handler来扩展。DEMO里面展示了如何通过Handler扩展来实现鉴权。详细的代码细节可以参考下面的章节"DEMO功能说明"。</p> |
| <h2 id="_4">部署示例</h2> |
| <p><img alt="" src="../assets/deployment.png" /></p> |
| <h2 id="_5">工作模式</h2> |
| <h3 id="reactive">reactive (默认)</h3> |
| <p>Edge Service默认工作于高性能的reactive模式,此模式要求工作于Edge Service转发流程中的业务代码不能有任何的阻塞操作,包括不限于:</p> |
| <ul> |
| <li> |
| <p>远程同步调用,比如同步查询数据库、同步调用微服务,或是同步查询远程缓存等等</p> |
| </li> |
| <li> |
| <p>任何的sleep调用</p> |
| </li> |
| <li> |
| <p>任何的wait调用</p> |
| </li> |
| <li> |
| <p>超大的循环</p> |
| </li> |
| </ul> |
| <p>Edge Service的底层是基于netty的vertx,以上约束即是netty的reactive模式约束。</p> |
| <p><img alt="" src="../assets/reactive.png" /></p> |
| <h3 id="_6">线程池</h3> |
| <p>如果业务模型无法满足reactive要求,则需要使用线程池模式。</p> |
| <p>此时需要在Edge Service的microservice.yaml中配置:</p> |
| <pre><code>servicecomb: |
| executors: |
| default: servicecomb.executor.groupThreadPool |
| </code></pre> |
| <p>这里的servicecomb.executor.groupThreadPool是ServiceComb内置的默认线程池对应的spring bean的beanId;业务可以定制自己的线程池,并声明为一个bean,其beanId也可以配置到这里。</p> |
| <p><img alt="" src="../assets/threadPool.png" /></p> |
| <h2 id="demo">DEMO功能说明</h2> |
| <p>DEMO 源码请参考 <a href="https://github.com/apache/servicecomb-java-chassis/tree/master/demo/demo-edge">edge service demo</a></p> |
| <h3 id="1dispatcher">1.注册Dispatcher</h3> |
| <p>实现接口org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher,或从 |
| org.apache.servicecomb.edge.core.AbstractEdgeDispatcher继承,实现自己的dispatcher功能。</p> |
| <p>实现类通过java标准的SPI机制注册到系统中去。</p> |
| <p>Dispatcher需要实现2个方法:</p> |
| <ul> |
| <li> |
| <h3 id="getorder">getOrder</h3> |
| </li> |
| </ul> |
| <p>Dispatcher需要向vertx注入路由规则,路由规则之间是有优先级顺序关系的。</p> |
| <p>系统中所有的Dispatcher按照getOrder的返回值按从小到大的方式排序,按顺序初始化。</p> |
| <p>如果2个Dispatcher的getOrder返回值相同,则2者的顺序不可预知。</p> |
| <ul> |
| <li> |
| <h3 id="init">init</h3> |
| </li> |
| </ul> |
| <p>init方法入参为vertx框架中的io.vertx.ext.web.Router,需要通过该对象实现路由规则的定制。</p> |
| <p>可以指定满足要求的url,是否需要处理cookie、是否需要处理body、使用哪个自定义方法处理收到的请求等等</p> |
| <p>更多路由规则细节请参考vertx官方文档:<a href="http://vertx.io/docs/vertx-web/java/#_routing_by_exact_path">vertx路由机制</a></p> |
| <p><em>提示:</em></p> |
| <p><em>多个Dispatcher可以设置路由规则,覆盖到相同的url。</em></p> |
| <p><em>假设Dispatcher A和B都可以处理同一个url,并且A优先级更高,则:</em></p> |
| <ul> |
| <li> |
| <p><em>如果A处理完,既没应答,也没有调用RoutingContext.next(),则属于bug,本次请求挂死了</em></p> |
| </li> |
| <li> |
| <p><em>如果A处理完,然后调用了RoutingContext.next(),则会将请求转移给B处理</em></p> |
| </li> |
| </ul> |
| <h3 id="2">2.转发请求</h3> |
| <p>注册路由时,指定了使用哪个方法来处理请求(下面使用onRequest来指代该方法),在onRequest中实现转发逻辑。</p> |
| <p>方法原型为:</p> |
| <pre><code>void onRequest(RoutingContext context) |
| </code></pre> |
| <p>系统封装了org.apache.servicecomb.edge.core.EdgeInvocation来实现转发功能,至少需要准备以下参数:</p> |
| <ul> |
| <li> |
| <p>microserviceName,业务自行制定规则,可以在url传入,或是根据url查找等等</p> |
| </li> |
| <li> |
| <p>context,即onRequest的入参</p> |
| </li> |
| <li> |
| <p>path,转发目标的url</p> |
| </li> |
| <li> |
| <p>httpServerFilters,Dispatcher父类已经初始化好的成员变量</p> |
| </li> |
| </ul> |
| <pre><code> EdgeInvocation edgeInvocation = new EdgeInvocation(); |
| edgeInvocation.init(microserviceName, context, path, httpServerFilters); |
| edgeInvocation.edgeInvoke(); |
| </code></pre> |
| <p>edgeInvoke调用内部,会作为ServiceComb标准consumer去转发调用。</p> |
| <p>作为标准consumer,意味着ServiceComb所有标准的治理能力在这里都是生效的。</p> |
| <h3 id="3">3.设置兼容规则</h3> |
| <p>不同的业务可能有不同的兼容规划,servicecomb默认的兼容规则,要求所有新版本兼容旧版本。如果满足这个要求,则不必做任何特殊的设置。</p> |
| <p>还有一种典型的规划:</p> |
| <ul> |
| <li> |
| <p>1.0.0-2.0.0内部兼容,url为/microserviceName/v1/….的形式</p> |
| </li> |
| <li> |
| <p>2.0.0-3.0.0内部兼容,url为/microserviceName/v2/….的形式</p> |
| </li> |
| </ul> |
| <p>……</p> |
| <p>各大版本之间不兼容</p> |
| <p>此时,开发人员需要针对EdgeInvocation设置兼容规则:</p> |
| <pre><code>private CompatiblePathVersionMapper versionMapper = new CompatiblePathVersionMapper(); |
| |
| …… |
| |
| edgeInvocation.setVersionRule(versionMapper.getOrCreate(pathVersion).getVersionRule()); |
| </code></pre> |
| <p>versionMapper的作用是将v1或是v2这样的串,转为1.0.0-2.0.0或2.0.0-3.0.0这样的兼容规则。</p> |
| <h3 id="4">4.鉴权</h3> |
| <p>Edge Service是系统的边界,对于很多请求需要执行鉴权逻辑。</p> |
| <p>基于标准的ServiceComb机制,可以通过handler来实现这个功能。</p> |
| <p>最简单的示意代码如下:</p> |
| <pre><code>public class AuthHandler implements Handler { |
| private static Logger LOGGER = LoggerFactory.getLogger(AuthHandler.class); |
| |
| private static Auth auth; |
| |
| static { |
| auth = Invoker.createProxy("auth", "auth", Auth.class); |
| } |
| |
| @Override |
| public void init(MicroserviceMeta microserviceMeta, InvocationType invocationType) { |
| } |
| |
| @Override |
| public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { |
| if (invocation.getHandlerContext().get(EdgeConst.ENCRYPT_CONTEXT) != null) { |
| invocation.next(asyncResp); |
| return; |
| } |
| |
| auth.auth("").whenComplete((succ, e) -> doHandle(invocation, asyncResp, succ, e)); |
| } |
| </code></pre> |
| <p>Auth表示是鉴权微服务提供的接口,Invoker.createProxy("auth", "auth", Auth.class)是透明RPC开发模式中consumer的底层api,与@ReferenceRpc是等效,只不过不需要依赖spring bean机制。</p> |
| <p>Auth接口完全由业务定义,这里只是一个示例。</p> |
| <p>Handler开发完成后,配置到edge service的microservice.yaml中:</p> |
| <pre><code>servicecomb: |
| handler: |
| chain: |
| Consumer: |
| default: auth,…… |
| service: |
| auth: …… |
| </code></pre> |
| <p>这个例子,表示转发请求给所有的微服务都必须经过鉴权,但是调用鉴权微服务时不需要鉴权。</p> |
| <p><strong><em>特别注意:</em></strong> edge service 的定制逻辑,包括 Dispatcher, Handler, HttpServerFilter 等,均在 |
| 事件派发线程 event-loop 中执行, 任何定制逻辑必须不能够存在阻塞逻辑,否则会导致 edge service 出现死锁。 |
| 比如上面鉴权的逻辑,必须使用异步接口,而不能够参考 provider 开发的逻辑那样,使用同步接口。 建议业务使用 |
| 定制逻辑的时候,对 edge service 进行并发测试,死锁问题会在并发数大于 event-loop 线程数量的情况下出现。 |
| (event-loop线程数量默认是CPU核数的两倍, 可以通过 jstack 命令查看线程。)</p> |
| |
| </div> |
| </div><footer> |
| <div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation"> |
| <a href="open-service.html" class="btn btn-neutral float-left" title="介绍"><span class="icon icon-circle-arrow-left"></span> Previous</a> |
| <a href="zuul.html" class="btn btn-neutral float-right" title="使用 `zuul` 和 `spring cloud gateway` 做网关">Next <span class="icon icon-circle-arrow-right"></span></a> |
| </div> |
| |
| <hr/> |
| |
| <div role="contentinfo"> |
| <!-- Copyright etc --> |
| </div> |
| |
| Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. |
| </footer> |
| |
| </div> |
| </div> |
| |
| </section> |
| |
| </div> |
| |
| <div class="rst-versions" role="note" aria-label="Versions"> |
| <span class="rst-current-version" data-toggle="rst-current-version"> |
| |
| |
| <span><a href="open-service.html" style="color: #fcfcfc">« Previous</a></span> |
| |
| |
| <span><a href="zuul.html" style="color: #fcfcfc">Next »</a></span> |
| |
| </span> |
| </div> |
| <script>var base_url = '..';</script> |
| <script src="../js/theme_extra.js" defer></script> |
| <script src="../js/theme.js" defer></script> |
| <script src="../search/main.js" defer></script> |
| <script defer> |
| window.onload = function () { |
| SphinxRtdTheme.Navigation.enable(true); |
| }; |
| </script> |
| |
| </body> |
| </html> |