INFINI Gateway:Elasticsearch 极限网关入门手册

1,390 阅读13分钟

最近,我有幸接触到 medcl 大神的杰作:极限网关(INFINI GATEWAY)。INFINI Gateway 有很多优点,也有很多应用的场景。你可以在官方网站上进行阅读。简单说来,极限网关INFINI Gateway)是一个面向 Elasticsearch 的高性能应用网关,它包含丰富的特性,使用起来也非常简单。极限网关工作的方式和普通的反向代理一样,我们一般是将网关部署在 Elasticsearch 集群前面, 将以往直接发送给 Elasticsearch 的请求都发送给网关,再由网关转发给请求到后端的 Elasticsearch 集群。因为网关位于在用户端和后端 Elasticsearch 之间,所以网关在中间可以做非常多的事情, 比如可以实现索引级别的限速限流、常见查询的缓存加速、查询请求的审计、查询结果的动态修改等等。

INFINI Gateway 它是如何和其它软件栈进行集成的呢?根据官方的介绍,网关通常是以这样的形式来进行接入的:

如上所示,INFINI 网关针对所有的请求是透明的。我们原本的发向 Elasticsearch 的请求,现在只要提交给网关就可以了。对于客户端开发者来说,你无需了解网关后面是如何连接 Elasticsearch 的。网关位于 Elasticsearch 的前端。所有的请求都发向网关,再由网关进行转发到 Elasticsearch。当然它不是简单的转发,它可以把请求分发至各个 Elasticsearch 节点或不同的 Elasticsearch 集群,也可以针对请求依据一些规则进行修改或者拒绝等操作,或者针对 _bulk 请求进行分析来提高摄入数据的速度。网关还可以实现负载均衡的功能,限流,使用 cache,甚至针对请求进行分析。也可以依据一定的条件进行修改或聚合来自其它数据源的数据。根据测评,极限网关相比同类主流网关类产品速度快 20% 以上。它对 Elasticsearch 做了细致的优化,并使得写入和查询的速度得到成倍的提升。

如上所示,在上面的架构中还采用了 VIP(浮动 IP)。我们可以在系统中部署2个 INFINI Gateway。一旦其中的一个由于一些原因不能正常工作,那么另外一个就会自动接管,从而避免 single point of failure。

在今天的展示中,我将使用最新的 Elastic Stack 8.1 来进行展示。

安装

Elastic Stack

如果你还没安装好自己的 Elasticsearch 及 Kibana,那么请参阅文章:

特别地,你可以参考如下的文章来安装好 Elastic Stack 8.1:

当我们安装好自己的 Elasticsearch 后,我们可以使用如下的方式来进行查看:

curl -k -u elastic:_3DAof2=LryludRa5Zho -XGET "https://192.168.0.3:9200/"


1.  $ curl -k -u elastic:_3DAof2=LryludRa5Zho -XGET "https://192.168.0.3:9200/"
2.  {
3.    "name" : "liuxgm.local",
4.    "cluster_name" : "elasticsearch",
5.    "cluster_uuid" : "SNZ_-EOOR8-tdb-I-BG_jA",
6.    "version" : {
7.      "number" : "8.1.1",
8.      "build_flavor" : "default",
9.      "build_type" : "tar",
10.      "build_hash" : "d0925dd6f22e07b935750420a3155db6e5c58381",
11.      "build_date" : "2022-03-17T22:01:32.658689558Z",
12.      "build_snapshot" : false,
13.      "lucene_version" : "9.0.0",
14.      "minimum_wire_compatibility_version" : "7.17.0",
15.      "minimum_index_compatibility_version" : "7.0.0"
16.    },
17.    "tagline" : "You Know, for Search"
18.  }


请注意上面的 _3DAof2=LryludRa5Zho 是我的集群超级用户 elastic 的密码,而 192.168.0.3 是我的 Elasticsearch 的访问地址。

INFINI Gateway

安装 INFINI Gateway 也非常简单。我们需要去 release.infinilabs.com 去下载我们需要的版本。 

 我们选择 gateway:

也许我比较喜欢尝鲜,我选择 snapshot。这里有每天的一个 build。它含有最新的功能,虽然可能会有 bug:

对于我的苹果电脑 Apple chipset 来说,我选择如上所示的 mac-arm6 版本。我们使用如下的命令来进行解压缩:

unzip gateway-1.6.0_SNAPSHOT-591-mac-arm64.zip 


1.  $ pwd
2.  /Users/liuxg/gateway
3.  $ ls -al
4.  total 49976
5.  drwxr-xr-x    6 liuxg  staff       192 Apr  6 09:44 .
6.  drwxr-xr-x+ 159 liuxg  staff      5088 Apr  6 09:43 ..
7.  -rw-r--r--@   1 liuxg  staff   6176162 Mar 24 15:21 gateway-1.6.0_SNAPSHOT-591-mac-arm64.zip
8.  -rwxr-xr-x@   1 liuxg  staff  19401090 Mar 23 19:06 gateway-mac-arm64
9.  -rw-r--r--@   1 liuxg  staff      4290 Mar 23 19:04 gateway.yml
10.  drwxr-xr-x@  21 liuxg  staff       672 Mar 20 23:42 sample-configs


如上所示,当解压缩后,它含有一个默认的 gateway.yml 配置文件。它还含有一个 sample-configs 目录。这个目录含有多个实例配置文件。我们在命令行中运行 gateway:

gateway-mac-arm64 --help


1.  $ pwd
2.  /Users/liuxg/gateway
3.  $ ls -al
4.  total 49976
5.  drwxr-xr-x    6 liuxg  staff       192 Apr  6 09:44 .
6.  drwxr-xr-x+ 159 liuxg  staff      5088 Apr  6 09:43 ..
7.  -rw-r--r--@   1 liuxg  staff   6176162 Mar 24 15:21 gateway-1.6.0_SNAPSHOT-591-mac-arm64.zip
8.  -rwxr-xr-x@   1 liuxg  staff  19401090 Mar 23 19:06 gateway-mac-arm64
9.  -rw-r--r--@   1 liuxg  staff      4290 Mar 23 19:04 gateway.yml
10.  drwxr-xr-x@  21 liuxg  staff       672 Mar 20 23:42 sample-configs
11.  $ ./gateway-mac-arm64 --help
12.  Usage of ./gateway-mac-arm64:
13.    -config string
14.      	the location of config file, default: gateway.yml (default "gateway.yml")
15.    -debug
16.      	run in debug mode, gateway will quit with panic error
17.    -log string
18.      	the log level, options: trace,debug,info,warn,error (default "info")
19.    -service string
20.      	service management, options: install,uninstall,start,stop
21.    -v	version


如上所示,我们可以把 gateway 以 service 的方式来进行运行,这样当我们的系统启动后,我们不再需要手动来启动 gateway。在 macOS 下,我们可以这样运行:

sudo ./gateway-mac-arm64 -service install


1.  $ sudo ./gateway-mac-arm64 -service install
2.  Password:
3.  Success


我们可以通过如下的方式来禁止以服务的方式来运行:

sudo ./gateway-mac-arm64 -service uninstall


1.  $ sudo ./gateway-mac-arm64 -service uninstall
2.  Success


当然,我们也可以使用 start 及 stop 选项来启动或停止服务的运行。 

这样我们的安装就完成了。

运行 Gateway 的方式

我们有两种方式来运行 Gateway:

./gateway-mac-arm64

如果以这样的方式来运行 gateway,那么它的默认配置文件是在该目录下的 gateway.yml 文件:



1.  $ pwd 
2.  /Users/liuxg/gateway
3.  $ ls
4.  gateway-1.6.0_SNAPSHOT-591-mac-arm64.zip log
5.  gateway-mac-arm64                        sample-configs
6.  gateway.yml


另外,我们也可以通过如下的方式来进行运行:

./gateway-mac-arm64 -config ./sample-configs/hello_world.yml 

在上面,我们指定了一个配置文件。



1.  $ ./gateway-mac-arm64 -config ./sample-configs/hello_world.yml 

3.     ___   _   _____  __  __    __  _       
4.    / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
5.   / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
6.  / /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
7.  \____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

9.  [GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
10.  [GATEWAY] 1.6.0_SNAPSHOT, 2022-03-23 11:04:26, 2023-12-31 10:10:10, 6c3c047b27d353696da1454fc71bcc564103bf2f
11.  [04-06 10:23:58] [INF] [app.go:174] initializing gateway.
12.  [04-06 10:23:58] [INF] [app.go:175] using config: /Users/liuxg/gateway/sample-configs/hello_world.yml.
13.  [04-06 10:23:58] [INF] [instance.go:72] workspace: /Users/liuxg/gateway/data/gateway/nodes/c96fjfl9so256esepqp0
14.  [04-06 10:23:58] [INF] [app.go:283] gateway is up and running now.
15.  [04-06 10:23:58] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
16.  [04-06 10:23:58] [INF] [entry.go:302] entry [my_es_entry] listen at: http://0.0.0.0:8000
17.  [04-06 10:23:58] [INF] [module.go:116] all modules are started


上面的 hello_world.yml 文件非常简单:

sample-configs/hello_world.yml



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 200000
9.      network:
10.        binding: 0.0.0.0:8000

12.  flow:
13.    - name: hello_world
14.      filter:
15.        - echo:
16.            message: "hello world"
17.  router:
18.    - name: my_router
19.      default_flow: hello_world


解释:

  • 上面的 path.data 定义的是 data 的路径。比如在当前的 gateway 安装目录下,含有一个叫做 data 的目录。

  • 上面的 path.logs 定义的是 日志的路径。如上所示,我们可以看到一个叫做 log 的目录。
  • entry:定义网关的请求入口,极限网关支持 HTTP 和 HTTPS 两种模式,HTTPS 可以自动生成证书。可以有多个 entry。
  • router:义请求的路由规则,根据 Method 和请求地址来进行路由到指定的 Flow 处理流程里面去。
  • flow:定义数据的处理逻辑,每个请求会经过一系列的 Filter 操作,Flow 用来将这些 Filter 组织起来。
  • filter:由若干个不同的 Filter 组件构成,每个 Filter 在设计的时候只处理一件事情,通过多个 Filter 组成变成一个 Flow。

整个极限网关的数据流是这样的:

从上面的流中,我们可以看出来,数据是从 entry 进入,然后由 router 流向 flow。每个 flow 又含有各个不同的 filters。每个 filter 都有自己独特的功能。

我们下面来做一个简单的测试。如上面 gateway 启动的画面显示所示,我们看到 gateway 是在端口 0.0.0.0:8000 侦听的。0.0.0.0 意味着它绑定了当前电脑的所有网络接口。我们可以通过如下的命令来获得所有当前电脑的网络接口:

ifconfig

一般来说,它绑定了当前电脑的 localhost 及 privateIP 地址。我们使用如下的方式来访问 gateway:

1.  $ curl http://localhost:8000
2.  hello world$ 

从上面,我们可以看出来。这个是一个简单的 echo 命令。它返回 hello world。这说明我们的 gateway 的安装是没有任何问题的。细心的开发者发现 hello world 是没有换行符的。我们可以重新修正 hello_world.yml 文件如下:

sample-configs/hello_world.yml



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 200000
9.      network:
10.        binding: 0.0.0.0:8000

12.  flow:
13.    - name: hello_world
14.      filter:
15.        - echo:
16.            message: "hello world\n"
17.  router:
18.    - name: my_router
19.      default_flow: hello_world


我们在上面的 message 中添加了一个换行符。重新启动 gateway,并再次运行上面的 curl 指令:



1.  $ curl http://localhost:8000
2.  hello world


这次,我们可以看到自动换行了。

如何连接到 Elasticsearch 和 Kibana

连接到 Elasticsearch 集群

我们可以参阅在安装目录中的 sample-configs/elasticsearch-proxy.yml 文件。如果你想创建多个节点的集群,请参阅我之前的文章 “Elasticsearch:在多个机器上创建多节点的 Elasticsearch 集群 - Elastic Stack 8.0”。我们可以通过如下的命令来验证集群含有的节点:

curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "https://192.168.0.3:9200/_cat/nodes"


1.  $ curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "https://192.168.0.3:9200/_cat/nodes"
2.  192.168.0.3  3 100 15 4.41           cdfhilmrstw * liuxgm.local
3.  192.168.0.8 19  97  6 0.57 0.35 0.30 cdfhilmrstw - liuxg


在上面,它显示是有两个节点组成的集群。我们可以修改 elasticsearch-proxy.yml 文件如下:

sample-configs/elasticsearch-proxy.yml



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 10000
9.      network:
10.        binding: 0.0.0.0:8000

12.  flow:
13.    - name: es-flow
14.      filter:
15.        - elasticsearch:
16.            elasticsearch: es-server

18.  router:
19.    - name: my_router
20.      default_flow: es-flow

22.  elasticsearch:
23.    - name: es-server
24.      enabled: true
25.      endpoints:
26.        - https://192.168.0.3:9200
27.        - https://192.168.0.8:9200
28.      basic_auth:
29.        username: elastic
30.        password: u7-KUuNhF2DcGCCtugU0


请注意上面的 password 配置。你需要根据自己的设置而改变。

我们使用如下的方法来启动 gateway:

./gateway-mac-arm64 -config ./sample-configs/elasticsearch-proxy.yml 


1.  $ ./gateway-mac-arm64 -config ./sample-configs/elasticsearch-proxy.yml 

3.     ___   _   _____  __  __    __  _       
4.    / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
5.   / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
6.  / /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
7.  \____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

9.  [GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
10.  [GATEWAY] 1.6.0_SNAPSHOT, 2022-03-23 11:04:26, 2023-12-31 10:10:10, 6c3c047b27d353696da1454fc71bcc564103bf2f
11.  [04-06 12:26:45] [INF] [app.go:174] initializing gateway.
12.  [04-06 12:26:45] [INF] [app.go:175] using config: /Users/liuxg/gateway/sample-configs/elasticsearch-proxy.yml.
13.  [04-06 12:26:45] [INF] [instance.go:72] workspace: /Users/liuxg/gateway/data/gateway/nodes/c96fjfl9so256esepqp0
14.  [04-06 12:26:45] [INF] [app.go:283] gateway is up and running now.
15.  [04-06 12:26:45] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
16.  [04-06 12:26:45] [INF] [entry.go:302] entry [my_es_entry] listen at: http://0.0.0.0:8000
17.  [04-06 12:26:45] [INF] [module.go:116] all modules are started
18.  [04-06 12:26:45] [INF] [actions.go:280] elasticsearch [es-server] is available


如上所示,它显示  elasticsearch [es-server] is available 这个信息。如果你没有看到这个信息,则表明你的配置是有问题的。

为了能够通过 gateway 访问 Elasticsearch,我们通过如下的方式来进行访问。首先,我们把 Elasticsearch 安装目录下的证书文件拷贝过。这个证书在如下的地址:



1.  $ pwd
2.  /Users/liuxg/elastic/elasticsearch-8.1.1
3.  $ ls config/certs/
4.  http.p12      http_ca.crt   transport.p12


在上面,显示的 http_ca.crt 就是所需要的证书。我们拷贝到下述命令运行的目录中,然后运行:



1.  $ pwd
2.  /Users/liuxg/gateway
3.  $ ls
4.  data                                     http_ca.crt
5.  gateway-1.6.0_SNAPSHOT-591-mac-arm64.zip log
6.  gateway-mac-arm64                        sample-configs
7.  gateway.yml
8.  $ curl --cacert ./http_ca.crt -u elastic:u7-KUuNhF2DcGCCtugU0 http://0.0.0.0:8000
9.  {
10.    "name" : "liuxg",
11.    "cluster_name" : "elasticsearch",
12.    "cluster_uuid" : "53aivEciQ-28pjjkYR-qlQ",
13.    "version" : {
14.      "number" : "8.1.2",
15.      "build_flavor" : "default",
16.      "build_type" : "deb",
17.      "build_hash" : "31df9689e80bad366ac20176aa7f2371ea5eb4c1",
18.      "build_date" : "2022-03-29T21:18:59.991429448Z",
19.      "build_snapshot" : false,
20.      "lucene_version" : "9.0.0",
21.      "minimum_wire_compatibility_version" : "7.17.0",
22.      "minimum_index_compatibility_version" : "7.0.0"
23.    },
24.    "tagline" : "You Know, for Search"
25.  }


如果你看到上面的输出则标明你的配置是成功的。我们可以通过如下的方法来获得所有的节点:



1.  $ curl --cacert ./http_ca.crt -u elastic:u7-KUuNhF2DcGCCtugU0 http://0.0.0.0:8000/_cat/nodes
2.  192.168.0.3  4 99 12 4.25           cdfhilmrstw * liuxgm.local
3.  192.168.0.8 21 98  4 0.05 0.06 0.12 cdfhilmrstw - liuxg


由于是自签名证书,我们也可以使用如下的方式来获得:



1.  $ curl -k -u elastic:u7-KUuNhF2DcGCCtugU0 http://0.0.0.0:8000/_cat/nodes
2.  192.168.0.3  4 99 15 3.93           cdfhilmrstw * liuxgm.local
3.  192.168.0.8 27 98  4 0.01 0.05 0.11 cdfhilmrstw - liuxg


或者:



1.  $ curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 http://0.0.0.0:8000/_cat/nodes
2.  192.168.0.8 28 98  4 0.01 0.04 0.10 cdfhilmrstw - liuxg
3.  192.168.0.3  4 99 15 8.63           cdfhilmrstw * liuxgm.local


之前没有网关的情况下,我们的请求都发向 Elasticsearch 的集群。现在有了网关的存在,我们直接把请求发向网关的地址就可以了。

连接到 Kibana

如同在文章一开始的架构图中所示,我们也可以把 Kibana 接入到 gateway 上去。我们按照通常的方法来安装 Kibana。具体步骤可以参阅文章  “Elasticsearch:在多个机器上创建多节点的 Elasticsearch 集群 - Elastic Stack 8.0”。为了测试方便,我们需要在 config/kibana.yml 文件中做如下的改动:

server.host: "0.0.0.0"

把 Kibana 绑定于电脑所有的网络接口上。我们可以通过 localhost:5601 及 privateIP:5601 的格式进行访问。

我们创建如下的一个 gateway.yml 文件:



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 10000
9.      network:
10.        binding: 0.0.0.0:8000
11.    - name: my_kibana_entry
12.      enabled: true
13.      router: my_kibana_router
14.      network: 
15.        binding: 0.0.0.0:5602

17.  flow:
18.    - name: es-flow
19.      filter:
20.        - elasticsearch:
21.            elasticsearch: es-server
22.    - name: logout_flow
23.      filter:
24.        - set_response:
25.            status: 401
26.            body: "Success logout!"
27.        - drop:
28.    - name: replace_logo_flow
29.      filter:
30.        - redirect:
31.            uri: https://elasticsearch.cn/uploads/event/20211120/458c74ca3169260dbb2308dd06ef930a.png
32.    - name: kibana_flow
33.      filter:
34.        - basic_auth:
35.            valid_users:
36.              elastic: u7-KUuNhF2DcGCCtugU0  # super user elastic account
37.        - http:
38.            schema: "http" #https or http
39.            host: "192.168.0.3:5601"

41.  router:
42.    - name: my_router
43.      default_flow: es-flow
44.    - name: my_kibana_router
45.      default_flow: kibana_flow
46.      rules:
47.        - method:
48.            - GET
49.            - POST
50.          pattern:
51.            - "/_logout"
52.          flow:
53.            - logout_flow
54.        - method:
55.            - GET
56.          pattern:
57.            - "/plugins/kibanaReact/assets/illustration_integrations_lightmode.svg"
58.          flow:
59.            - replace_logo_flow

61.  elasticsearch:
62.    - name: es-server
63.      enabled: true
64.      endpoints:
65.        - https://192.168.0.3:9200
66.        - https://192.168.0.8:9200
67.      basic_auth:
68.        username: elastic
69.        password: u7-KUuNhF2DcGCCtugU0


请注意我在上面使用了超级用户 elastic 来配置 Kibana。在实际的使用中,我们可以使用创建的账号来访问 Kibana。

我们使用如下的方法来启动 gateway:

./gateway-mac-arm64 

我们可以看到:



1.  $ ./gateway-mac-arm64 

3.     ___   _   _____  __  __    __  _       
4.    / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
5.   / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
6.  / /_\\/  _  \/ / //__   \  /\  /  _  \/ \ 
7.  \____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/ 

9.  [GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
10.  [GATEWAY] 1.6.0_SNAPSHOT, 2022-03-23 11:04:26, 2023-12-31 10:10:10, 6c3c047b27d353696da1454fc71bcc564103bf2f
11.  [04-06 13:36:39] [INF] [app.go:174] initializing gateway.
12.  [04-06 13:36:39] [INF] [app.go:175] using config: /Users/liuxg/gateway/gateway.yml.
13.  [04-06 13:36:39] [INF] [instance.go:72] workspace: /Users/liuxg/gateway/data/gateway/nodes/c96fjfl9so256esepqp0
14.  [04-06 13:36:39] [INF] [app.go:283] gateway is up and running now.
15.  [04-06 13:36:39] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
16.  [04-06 13:36:39] [INF] [entry.go:302] entry [my_es_entry] listen at: http://0.0.0.0:8000
17.  [04-06 13:36:39] [INF] [entry.go:302] entry [my_kibana_entry] listen at: http://0.0.0.0:5602
18.  [04-06 13:36:39] [INF] [module.go:116] all modules are started
19.  [04-06 13:36:39] [INF] [actions.go:280] elasticsearch [es-server] is available


从上面我们可以看到有两个 entry:my_es_entry 及 my_kibana_entry。

如何调试

在上面,我只对 gateway 的一个安装做了简单的介绍。在 gateway 的官方网站中,有许多的过滤器。这些是在请求发向 Elasticsearh 之前可以在网关做很多额外工作的地方。在开发的过程中,有一个良好的调试工具会给我们的开发带来很多的好处。在上面,我们除了可以使用 echo 来输出一些文字之外,我们还可以通过 dump 指令来查看请求及响应的内容。

下面,我们来做一个简单的展示。首先我们在 Elasticsearch 中创建如下的一个索引:



1.  PUT twitter/_doc/1
2.  {
3.    "name": "liuxg",
4.    "company": "elastic"
5.  }


我们可以做如上所示的搜索:



1.  GET twitter/_search
2.  {
3.    "query": {
4.      "match": {
5.        "name": "liuxg"
6.      }
7.    }
8.  }


我们按照上面的方法点击 Copy as cURL。我们把拷贝下来的内容放入到下面的 curl 指令中去:



1.  curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "http://0.0.0.0:8000/twitter/_search" -H 'Content-Type: application/json' -d'
2.  {
3.    "query": {
4.      "match": {
5.        "name": "liuxg"
6.      }
7.    }
8.  }'


上面的结果为:



1.  $ curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "http://0.0.0.0:8000/twitter/_search" -H 'Content-Type: application/json' -d'
2.  > {
3.  >   "query": {
4.  >     "match": {
5.  >       "name": "liuxg"
6.  >     }
7.  >   }
8.  > }'
9.  {"took":2,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":0.2876821,"hits":[{"_index":"twitter","_id":"1","_score":0.2876821,"_source":{
10.    "name": "liuxg",
11.    "company": "elastic"
12.  }
13.  }]}


显然这个是我们想要的结果。

到目前位置,结果非常完美。我们可以使用 dump 过滤器来展示很多的细节。我们接着修改上面的 gateway.yml 文件。

gateway.yml



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 10000
9.      network:
10.        binding: 0.0.0.0:8000
11.    - name: my_kibana_entry
12.      enabled: true
13.      router: my_kibana_router
14.      network: 
15.        binding: 0.0.0.0:5602

17.  flow:
18.    - name: es-flow
19.      filter:
20.        - echo:
21.            message: "Before ES request\n"
22.        - dump:
23.            uri: true
24.            request_header: true
25.            request_body: true
26.            response_body: true
27.            status_code: true 
28.            context: 
29.              - _ctx.id
30.              - _ctx.tls
31.              - _ctx.remote_addr
32.              - _ctx.local_addr
33.              - _ctx.request.host
34.              - _ctx.request.method
35.              - _ctx.request.uri
36.              - _ctx.request.path
37.              - _ctx.request.body
38.              - _ctx.request.body_length
39.              - _ctx.request.query_args.from
40.              - _ctx.request.query_args.size
41.              - _ctx.request.header.Accept
42.              - _ctx.request.user
43.              - _ctx.response.status
44.              - _ctx.response.body
45.              - _ctx.response.content_type
46.              - _ctx.response.body_length
47.              - _ctx.response.header.Env
48.        - elasticsearch:
49.            elasticsearch: es-server
50.        - echo:
51.            message: "After ES request\n"
52.        - dump:
53.            uri: true
54.            request_header: true
55.            request_body: true
56.            response_body: true
57.            status_code: true 
58.            context: 
59.              - _ctx.id
60.              - _ctx.tls
61.              - _ctx.remote_addr
62.              - _ctx.local_addr
63.              - _ctx.request.host
64.              - _ctx.request.method
65.              - _ctx.request.uri
66.              - _ctx.request.path
67.              - _ctx.request.body
68.              - _ctx.request.body_length
69.              - _ctx.request.query_args.from
70.              - _ctx.request.query_args.size
71.              - _ctx.request.header.Accept
72.              - _ctx.request.user
73.              - _ctx.response.status
74.              - _ctx.response.body
75.              - _ctx.response.content_type
76.              - _ctx.response.body_length
77.              - _ctx.response.header.Env

79.    - name: logout_flow
80.      filter:
81.        - set_response:
82.            status: 401
83.            body: "Success logout!"
84.        - drop:
85.    - name: replace_logo_flow
86.      filter:
87.        - redirect:
88.            uri: https://elasticsearch.cn/uploads/event/20211120/458c74ca3169260dbb2308dd06ef930a.png
89.    - name: kibana_flow
90.      filter:
91.        - basic_auth:
92.            valid_users:
93.              elastic: u7-KUuNhF2DcGCCtugU0  # super elastic account
94.        - http:
95.            schema: "http" #https or http
96.            host: "192.168.0.3:5601"

98.  router:
99.    - name: my_router
100.      default_flow: es-flow
101.    - name: my_kibana_router
102.      default_flow: kibana_flow
103.      rules:
104.        - method:
105.            - GET
106.            - POST
107.          pattern:
108.            - "/_logout"
109.          flow:
110.            - logout_flow
111.        - method:
112.            - GET
113.          pattern:
114.            - "/plugins/kibanaReact/assets/illustration_integrations_lightmode.svg"
115.          flow:
116.            - replace_logo_flow

118.  elasticsearch:
119.    - name: es-server
120.      enabled: true
121.      endpoints:
122.        - https://192.168.0.3:9200
123.        - https://192.168.0.8:9200
124.      basic_auth:
125.        username: elastic
126.        password: u7-KUuNhF2DcGCCtugU0


在上面,请注意 echodump 过滤器的部分。我们分别在 Elasticsearch 请求前后 dump 请求及响应的值。我们重新运行 gateway:

./gateway-mac-arm64 

我们在 gateway 的 console 里可以看到如下的输出:

 

接下来,我们再创建一个文档:



1.  PUT twitter/_doc/2
2.  {
3.    "name": "zhang san",
4.    "company": "elastic"
5.  }


如果我们使用如下的方式来搜索的话,应该是两个文档:



1.  GET twitter/_search?filter_path=**.hits
2.  {
3.    "query": {
4.      "match": {
5.        "company": "elastic"
6.      }
7.    }
8.  }


上面返回的结果将会是:



1.  {
2.    "hits" : {
3.      "hits" : [
4.        {
5.          "_index" : "twitter",
6.          "_id" : "1",
7.          "_score" : 0.13353139,
8.          "_source" : {
9.            "name" : "liuxg",
10.            "company" : "elastic"
11.          }
12.        },
13.        {
14.          "_index" : "twitter",
15.          "_id" : "2",
16.          "_score" : 0.13353139,
17.          "_source" : {
18.            "name" : "zhang san",
19.            "company" : "elastic"
20.          }
21.        }
22.      ]
23.    }
24.  }


接下来,我们来尝试修改请求,不管在任何情况下,返回的结果只有一个。我们修改 gateway.yml 文件如下:

gateway.yml



1.  path.data: data
2.  path.logs: log

4.  entry:
5.    - name: my_es_entry
6.      enabled: true
7.      router: my_router
8.      max_concurrency: 10000
9.      network:
10.        binding: 0.0.0.0:8000
11.    - name: my_kibana_entry
12.      enabled: true
13.      router: my_kibana_router
14.      network: 
15.        binding: 0.0.0.0:5602

17.  flow:
18.    - name: es-flow
19.      filter:
20.        - echo:
21.            message: "Before ES request\n"
22.        - request_body_json_set:
23.            path:
24.              - size -> 1
25.        - dump:
26.            uri: true
27.            request_header: true
28.            request_body: true
29.            response_body: true
30.            status_code: true 
31.            context: 
32.              - _ctx.id
33.              - _ctx.tls
34.              - _ctx.remote_addr
35.              - _ctx.local_addr
36.              - _ctx.request.host
37.              - _ctx.request.method
38.              - _ctx.request.uri
39.              - _ctx.request.path
40.              - _ctx.request.body
41.              - _ctx.request.body_length
42.              - _ctx.request.query_args.from
43.              - _ctx.request.query_args.size
44.              - _ctx.request.header.Accept
45.              - _ctx.request.user
46.              - _ctx.response.status
47.              - _ctx.response.body
48.              - _ctx.response.content_type
49.              - _ctx.response.body_length
50.              - _ctx.response.header.Env
51.        - elasticsearch:
52.            elasticsearch: es-server
53.        - set_response_header:
54.            headers:
55.              - Env -> Dev
56.        - echo:
57.            message: "After ES request\n"
58.        - dump:
59.            uri: true
60.            request_header: true
61.            request_body: true
62.            response_body: true
63.            status_code: true 
64.            context: 
65.              - _ctx.id
66.              - _ctx.tls
67.              - _ctx.remote_addr
68.              - _ctx.local_addr
69.              - _ctx.request.host
70.              - _ctx.request.method
71.              - _ctx.request.uri
72.              - _ctx.request.path
73.              - _ctx.request.body
74.              - _ctx.request.body_length
75.              - _ctx.request.query_args.from
76.              - _ctx.request.query_args.size
77.              - _ctx.request.header.Accept
78.              - _ctx.request.user
79.              - _ctx.response.status
80.              - _ctx.response.body
81.              - _ctx.response.content_type
82.              - _ctx.response.body_length
83.              - _ctx.response.header.Env

85.    - name: logout_flow
86.      filter:
87.        - set_response:
88.            status: 401
89.            body: "Success logout!"
90.        - drop:
91.    - name: replace_logo_flow
92.      filter:
93.        - redirect:
94.            uri: https://elasticsearch.cn/uploads/event/20211120/458c74ca3169260dbb2308dd06ef930a.png
95.    - name: kibana_flow
96.      filter:
97.        - basic_auth:
98.            valid_users:
99.              elastic: u7-KUuNhF2DcGCCtugU0  # super elastic account
100.        - http:
101.            schema: "http" #https or http
102.            host: "192.168.0.3:5601"

104.  router:
105.    - name: my_router
106.      default_flow: es-flow
107.    - name: my_kibana_router
108.      default_flow: kibana_flow
109.      rules:
110.        - method:
111.            - GET
112.            - POST
113.          pattern:
114.            - "/_logout"
115.          flow:
116.            - logout_flow
117.        - method:
118.            - GET
119.          pattern:
120.            - "/plugins/kibanaReact/assets/illustration_integrations_lightmode.svg"
121.          flow:
122.            - replace_logo_flow

124.  elasticsearch:
125.    - name: es-server
126.      enabled: true
127.      endpoints:
128.        - https://192.168.0.3:9200
129.        - https://192.168.0.8:9200
130.      basic_auth:
131.        username: elastic
132.        password: u7-KUuNhF2DcGCCtugU0


在上面,我们在请求之前,通过 request_body_json_set 过滤器把请求里的 body 进行修改。把 size 设置为 1。

 1.        - request_body_json_set:
2.            path:
3.              - size -> 1

这样我们的请求就变成了:



1.  GET twitter/_search?filter_path=**.hits
2.  {
3.    "size": 1, 
4.    "query": {
5.      "match": {
6.        "company": "elastic"
7.      }
8.    }
9.  }


 虽然,在客户端,我们任然可以通过如下的方式来进行请求:



1.  curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "http://0.0.0.0:8000/twitter/_search?filter_path=**.hits" -H 'Content-Type: application/json' -d'
2.  {
3.    "query": {
4.      "match": {
5.        "company": "elastic"
6.      }
7.    }
8.  }'


但是我们得到的结果是:



1.  $ curl --insecure -u elastic:u7-KUuNhF2DcGCCtugU0 -XGET "http://0.0.0.0:8000/twitter/_search?filter_path=**.hits" -H 'Content-Type: application/json' -d'
2.  {
3.    "query": {
4.      "match": {
5.        "company": "elastic"
6.      }
7.    }
8.  }'
9.  {"hits":{"hits":[{"_index":"twitter","_id":"1","_score":0.18232156,"_source":{"name":"liuxg","company":"elastic"}}]}}After ES request


我们只看到一个结果,而不之前的两个尽管我们的请求没有设置 size 的值。

另外,我们也可以干预返回的响应。我们在请求之后,也添加了如下的过滤器:

 1.        - set_response_header:
2.            headers:
3.              - Env -> Dev

在我们的 gateway 运行的 console 中,我们可以看到:

显然,我们针对 response 做了修改。 

我们在这里可以看到许多关于请求及响应的详细情况。我们可以根据这些 context,请求的类型,请求的 body,响应的 body 结合一些条件可以做出非常多的用户案例。比如在文章 “使用极限网关来处置 Elasticsearch 的 Apache Log4j 漏洞” 中介绍的那样,可以修复漏洞。拒绝一些请求。再比如,在文章 “在线查询修复的实现” 中,它实现对请求的修复。当然也可以对 response 进行修改。

结论

INFINI 网关置于 Elasticsearch 集群的前端。它是一个轻量级的高可用的网关。它可对客户端的请求动态地进行截获及分析。它含有丰富的过滤器供开发者使用。我们可以充分利用这些过滤器对来自客户端的请求进行分析,组装,拒绝,也可以针对响应做更改。当然,它还有很多其它的功能供开发者使用,比如,轻松实现跨集群搜索及备份。针对一些请求进行限流。有很多功能需要我们一起共同挖掘。