Unified access indexes from different clusters in Kibana

Unified access indices from different clusters in Kibana #

Now there is such a demand, customers need to divide the data according to the business dimension, the index is split into three different clusters, to split the large cluster into multiple small clusters have many benefits, such as reduced coupling, bringing benefits to cluster availability and stability, but also to avoid the impact of a single business hotspot to affect other services, although splitting the cluster is a very common way to play, but the management is not so convenient, especially when querying data, it may be need to access the three sets of clusters separately APIs, even to switch between three different sets of Kibana to access the cluster’s data, is there a way to seamlessly unite them together?

A gateway! #

The answer is naturally yes, by switching the Elasticsearch address of Kibana to the address of the INFINI Gateway, we can intelligently route requests according to the index, that is, when accessing different business indexes, they will be intelligently routed to different clusters, as shown in the following figure:

Above, we have three different indexes:

  • apm-*
  • erp-*
  • mall-*

Each corresponds to three different sets of Elasticsearch clusters:

  • ES1-APM
  • ES2-ERP
  • ES3-MALL

Now let’s see how to configure the INFINI Gateway to meet this business requirements:

Configure clusters #

First configure the connection information for the three clusters.

elasticsearch:
  - name: es1-apm
    enabled: true
    endpoints:
     - http://192.168.3.188:9206
  - name: es2-erp
    enabled: true
    endpoints:
     - http://192.168.3.188:9207
  - name: es3-mall
    enabled: true
    endpoints:
     - http://192.168.3.188:9208

Configure Flow #

then, we define three flows that are used to access three different Elasticsearch clusters, as shown below:

flow:
  - name: es1-flow
    filter:
      - elasticsearch:
          elasticsearch: es1-apm
  - name: es2-flow
    filter:
      - elasticsearch:
          elasticsearch: es2-erp
  - name: es3-flow
    filter:
      - elasticsearch:
          elasticsearch: es3-mall

Then define a flow for path rule and forwarding, as follows:

  - name: default-flow
    filter:
      - switch:
          remove_prefix: false
          path_rules:
            - prefix: "apm-"
              flow: es1-flow
            - prefix: "erp-"
              flow: es2-flow
            - prefix: "mall-"
              flow: es3-flow
      - flow: #default flow
          flows:
            - es1-flow

Match different indexes based on the index prefix in the request path and forward to different flows.

Configure Router #

Next, we define the routing information as follows:

router:
  - name: my_router
    default_flow: default-flow

Point to the default flow defined above to unify the processing of requests.

Configure Entrypoint #

Finally, we define a service that listening on port 8000 to provide unified access to Kibana, as follows:

entry:
  - name: es_entry
    enabled: true
    router: my_router
    max_concurrency: 10000
    network:
      binding: 0.0.0.0:8000

Full Configuration #

The final complete configuration is as follows:

path.data: data
path.logs: log

entry:
  - name: es_entry
    enabled: true
    router: my_router
    max_concurrency: 10000
    network:
      binding: 0.0.0.0:8000

flow:
  - name: default-flow
    filter:
      - switch:
          remove_prefix: false
          path_rules:
            - prefix: "apm-"
              flow: es1-flow
            - prefix: "erp-"
              flow: es2-flow
            - prefix: "mall-"
              flow: es3-flow
      - flow: #default flow
          flows:
            - es1-flow
  - name: es1-flow
    filter:
      - elasticsearch:
          elasticsearch: es1-apm
  - name: es2-flow
    filter:
      - elasticsearch:
          elasticsearch: es2-erp
  - name: es3-flow
    filter:
      - elasticsearch:
          elasticsearch: es3-mall

router:
  - name: my_router
    default_flow: default-flow

elasticsearch:
  - name: es1-apm
    enabled: true
    endpoints:
     - http://192.168.3.188:9206
  - name: es2-erp
    enabled: true
    endpoints:
     - http://192.168.3.188:9207
  - name: es3-mall
    enabled: true
    endpoints:
     - http://192.168.3.188:9208

Start Gateway #

Start the gateway as follows:

➜  gateway git:(master) ✗ ./bin/gateway -config sample-configs/elasticsearch-route-by-index.yml

   ___   _   _____  __  __    __  _
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2022-04-20 08:23:56, 2023-12-31 10:10:10, 51650a5c3d6aaa436f3c8a8828ea74894c3524b9
[04-21 13:41:21] [INF] [app.go:174] initializing gateway.
[04-21 13:41:21] [INF] [app.go:175] using config: /Users/medcl/go/src/infini.sh/gateway/sample-configs/elasticsearch-route-by-index.yml.
[04-21 13:41:21] [INF] [instance.go:72] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/c9bpg0ai4h931o4ngs3g
[04-21 13:41:21] [INF] [app.go:283] gateway is up and running now.
[04-21 13:41:21] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es2-erp] hosts: [] => [192.168.3.188:9207]
[04-21 13:41:21] [INF] [reverseproxy.go:255] elasticsearch [es3-mall] hosts: [] => [192.168.3.188:9208]
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es2-erp] is available
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es1-apm] is available
[04-21 13:41:21] [INF] [entry.go:312] entry [es_entry] listen at: http://0.0.0.0:8000
[04-21 13:41:21] [INF] [module.go:116] all modules are started
[04-21 13:41:21] [INF] [actions.go:349] elasticsearch [es3-mall] is available
[04-21 13:41:55] [INF] [reverseproxy.go:255] elasticsearch [es1-apm] hosts: [] => [192.168.3.188:9206]

After the gateway successfully started, you can access the target Elasticsearch cluster through the gateway’s IP+ port 8000.

Testing #

Let’s start with the API access test, as follows:

➜  ~ curl http://localhost:8000/apm-2022/_search -v
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /apm-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 05:45:44 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 162
< X-elastic-product: Elasticsearch
< X-Backend-Cluster: es1-apm
< X-Backend-Server: 192.168.3.188:9206
< X-Filters: filters->elasticsearch
<
* Connection #0 to host localhost left intact
{"took":142,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%

You can see that apm-2022 points to the backend ES1-APM cluster.

To continue testing, access to the ERP index as follows:

➜  ~ curl http://localhost:8000/erp-2022/_search -v
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /erp-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:24:46 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 161
< X-Backend-Cluster: es2-erp
< X-Backend-Server: 192.168.3.188:9207
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":12,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":0,"relation":"eq"},"max_score":null,"hits":[]}}%

Great!

Let’s continue testing, access to the mall index as follows:

➜  ~ curl http://localhost:8000/mall-2022/_search -v
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /mall-2022/_search HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 21 Apr 2022 06:25:08 GMT
< content-type: application/json; charset=UTF-8
< Content-Length: 134
< X-Backend-Cluster: es3-mall
< X-Backend-Server: 192.168.3.188:9208
< X-Filters: filters->switch->filters->elasticsearch->skipped
<
* Connection #0 to host localhost left intact
{"took":8,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}%

Perfect!

Another Option #

Besides using the switch filter, it is possible to use the path rules of the router itself, as shown in the following example configuration:

flow:
  - name: default_flow
    filter:
      - echo:
          message: "hello world"
  - name: mall_flow
    filter:
      - echo:
          message: "hello mall indices"
  - name: apm_flow
    filter:
      - echo:
          message: "hello apm indices"
  - name: erp_flow
    filter:
      - echo:
          message: "hello erp indices"
router:
  - name: my_router
    default_flow: default_flow
    rules:
      - method:
          - "*"
        pattern:
          - "/apm-{suffix:.*}/"
          - "/apm-{suffix:.*}/{any:.*}"
        flow:
          - apm_flow
      - method:
          - "*"
        pattern:
          - "/erp-{suffix:.*}/"
          - "/erp-{suffix:.*}/{any:.*}"
        flow:
          - erp_flow
      - method:
          - "*"
        pattern:
          - "/mall-{suffix:.*}/"
          - "/mall-{suffix:.*}/{any:.*}"
        flow:
          - mall_flow

INFINI Gateway has many powerful features, and there are many ways to achieve your need, go explore it by yourself.

Modify Kibana Configuration #

Modify the Kibana configuration file kibana.yml, replace the address of Elasticsearch with the gateway address (HTTP: 192.168.3.200/8000), as shown below:

elasticsearch.hosts: ["http://192.168.3.200:8000"]

Restart the Kibana。

Visit Kibana #

As you can see, in the Kibana developer tool we can already perform read and write operations from three different clusters as if it were one cluster.

Conclusion #

Through the INFINI Gateway, we can be very flexible for online traffic editing, dynamic combine requests of different cluster operations together on the fly.