Elastic:负载均衡在 Elastic Stack 中的应用

在 Elastic Stack 的使用中,我们会经常使用到复杂均衡。如果我们不考虑到这点,那么当我们的一个环节出现问题的话,那么就可能造成 Single point of failure,也就是整个数据的采集就不能工作。还有在多个实例部署的情况下,如何做到负载均衡更好地利用现有的资源。在今天的文章中,我们来讲述如何在数据采集或访问中,采用负载均衡。

典型的 Elastic Stack 架构图

我们先来看一下如下的一个典型的 Elastic Stack 图:

在上面,我们可以看到 Beats 可以直接连接到 Logstash,然后由 Logstash 帮我们加工数据,并最终导入到 Elasticsearch 中。

在没有负载均衡的情况下,是这样的:

我们通常可以在 beats 中这样配置:

1
2
output:
  logstash.hosts: ["mylogstash"]

在没有任何事情发生的时候,一旦建立了这种 TCP 连接,这是一种非常可靠的连接。但是有一种情况就是,当我们的 Logstash 挂掉的话,那么我们可能就会有麻烦。这也就是我们上面提到的单点故障。如果有很多的 beats 都连到一个 Logstash 上的话,那么所有的数据采集将受到影响。

那么我们如和避免这种情况的发生呢?

解决方案是,我们多添加一个 Logstash 的服务器,把配置变为:

在上面,我们多添加了一个 Logstash 的服务器。在我们的实际的使用中如果其中的一个 Logstash 死掉的话,我们可以通过另外一个 Logstash 的服务器完成我们的数据采集的工作。那么我们如何在我们的 beats 中进行配置呢?

方法一

我们在 beats 的配置文件中这么配置:

1
2
output:
   logstash.hosts: ["Logstash1", "Logstash2"]

在这种配置中,beats 在每次发送数据时,随机地挑出一个 Logstash 进行发送数据。如果其中的一个发生错误,那么 beats 将会挑另外一个进行发送。这种方式,没有使用到负载均衡。

方法二:

在这种情况下,我们将使用负载均衡配置。我可以参阅文章https://www.elastic.co/guide/en/beats/filebeat/master/load-balancing.html

1
2
3
output:
  logstash.hosts: ["logstash1", "logstash2"]
  logstash.loadbalance: true

目前针对Filebeat, 负载均衡选项可用于 Redis,Logstash 和 Elasticsearch 输出。 Kafka 输出在内部处理负载平衡。

Beats 在这种情况下,根据负载的情况,均匀地向其中的 Logstash 发送数据。如果其中的一个连接断掉的话,那么 beats 将把它从它的资源池中除去,从而不再使用,直至再次连接成功为止。以指数后退重试以重新连接。

在上面的方法中,有一个很大的问题就是。当我们新增加一个 Logstash 的话,我们需要不停地修改我们的配置文件,从而使得我们的 Beats 能够知道它的存在。在或者,如果我们删除其中的一个 Logstash 的话,那么我们也同样需要来修改我们的 beats 的配置文件。如果我们只是维护一个或两个 beats 的话,那么这个可能并不是问题,毕竟工作量并不大。

但是,问题来了,假如我们有很多很多的 beats,这个工作量将是非常大的。我们该如何操作呢?

运用负载均衡来导入数据

随着 beats 的数量越来越多,一种可行的办法就是使用专有的负载均衡:

如上面所示,我们可以让每个 beat 把数据发向一个专业的负载均衡器,再由它发送至 Logstash。通过这样的改造后,我们的 beat 的输出就变得非常简单:

1
2
output:
  logstash.hosts: ["loadbalancer"]

在这里,每当我们添加一个新的 beat 后,或者我们增加一个新的 Logstash,我们都不需要再次维护 beats 段的修改。所有的配置都在负载均衡的地方完成。

动手实践

在我们的实践中,我采用如下的配置:

负载均衡图:

在上面,beats 收集的数据发送到 Nginx,然后再发送至 Logstash,再传入到 Elasticsearch,并最终在 Kibana 中展示。

安装

Elasticsearch

如果你还没有安装好自己的Elasticsearch,请参阅我之前的文章“如何在Linux,MacOS及Windows上进行安装Elasticsearch”来安装好自己的Elasticsearch。为了能够使得我们能够让 Ubunutu OS 中的 Logstash 也能访问到 Elasticsearch,我们对 config/elasticsearch.yml 文件做如下的修改:

1
2
network.host: 0.0.0.0
discovery.type: single-node

这样我们使得 Elasticsearch 绑定于 Mac OS 上的每一个网路接口上。我们可以分别在 http://localhost:9200/ 地址及 http://192.168.0.3:9200/ 都能看到输出:

Kibana

如果你还没有安装好自己的Kibana,请参阅我之前的文章“如何在Linux,MacOS及Windows上安装Elastic栈中的Kibana”安装好自己的Kibana。我们可以不做任何的修改。安装完后,在浏览器中输入地址http://localhost:5601/

Nginx

Nginx在Ubuntu的默认存储库中可用,因此安装非常简单。

由于这是我们在此会话中与apt打包系统的第一次交互,因此我们将更新本地包索引,以便我们可以访问最新的包清单。 之后,我们可以安装nginx:

1
2
sudo apt-get update
sudo apt-get install nginx

一旦nginx被成功安装,我们可以通过如下的命令来查看nginx服务是否已经被成功启动:

1
sudo service nginx status
1
2
3
4
5
6
7
8
9
10
11
12
$ sudo service nginx status
● nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enable>
     Active: active (running) since Wed 2020-06-17 16:44:00 CST; 5h 5min ago
       Docs: http://nginx.org/en/docs/
    Process: 1761 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, sta>
   Main PID: 1781 (nginx)
      Tasks: 2 (limit: 18985)
     Memory: 3.7M
     CGroup: /system.slice/nginx.service
             ├─1781 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
             └─1782 nginx: worker process

上面显示 nginx 已经被成功安装并正在运行。

为了能够把 nginx 设置为一个负载均衡器,我们对 /etc/nginx/nginx/conf 做如下的配置:

/etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

stream {
    upstream stream_backend {
        server 192.168.0.4:5044;
    }

    server {
        listen        12345;
        proxy_pass    stream_backend;
    }
}

这里的 192.168.0.4 是 Ubuntu OS 的地址。 上面的意思是侦听端口12345,并把它转发至 192.168.0.4:5044。配置好我们的 nginx.conf,我们重新启动 nginx 服务:

1
sudo service nginx restart

安装Logstash2

我们安装我之前文章 “如何安装Elastic栈中的Logstash” 来安装 Logstash。按照上面的配置,我们在 Ubuntu OS 的电脑上安装 Logstash2。针对我们的情况,我们可以直接采用下载本地,并加压缩文件的方式来进行安装:

1
2
tar xzf logstash-7.7.1.tar.gz
cd logstash-7.7.1/

接下来,我们创建如下的 logstash.conf 配置文件:

logstash.conf

1
2
3
4
5
6
7
8
9
10
11
input {
  beats {
    port => 5044
  }
}

output {
  stdout {
    codec => dots
  }
}

在上面,Logstash 侦听端口 5044。如果有数据,我们直接显示 dot,也就是点。

我们使用如下的方式来启动 Logstash:

1
./bin/logstash -f logstash.conf

在接下来的练习中,我们还好安装 Logstash1。

Metricbeat

我们可以打开 Kibana:

点击 Add mertic data:

选择 System metrics

然后根据自己的平台来进行安装。我们需要对 merticbeat.yml 进行修改。

我们启动 metricbeat:

1
./metricbeat -e

上面显示,metricbeat 和 nginx 的连接是成功的。

我们再回到 Logstash 运行的 console 里查看:

我们看到很多的点出现。这个说明,数据从 metricbeat 到 nginx,再传入到 Logstash 是成功的。

安装 Logstash1

在 Mac OS 上的 Logstash1 的安装其实和 Ubuntu OS 上的 Logstash2 安装是一样的。我们也同样建立一个如下的配置文件:

logstash.conf

1
2
3
4
5
6
7
8
9
10
11
input {
  beats {
    port => 5044
  }
}

output {
  stdout {
    codec => dots
  }
}

我们运行这个 Logstash:

1
2
3
4
5
6
7
8
9
10
11
input {
  beats {
    port => 5044
  }
}

output {
  stdout {
    codec => dots
  }
}

我们虽然已经把 Logstash1 已经运行起来了,但是,我们还没通知 nginx 向这个 Logstash 进行转发。我们重新打开 nginx.conf 文件,并添加 Mac OS 的 IP 地址信息:

/etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

stream {
    upstream stream_backend {
        server 192.168.0.4:5044;
        server 192.168.0.3:5044;
    }

    server {
        listen        12345;
        proxy_pass    stream_backend;
    }
}

请注意上面添加的一行:

1
server 192.168.0.3:5044;

也就是说,端口 12345 的信息会负载均衡发送到 192.168.0.3 及 192.168.0.4 两个 Logstash。

经过上面的修,我们重新启动 nginx:

1
sudo service nginx restart

这个时候,我们回到 Mac OS 的 Logstash1的 console 中进行查看,其实,我们会发现,没有任何的输出。难道是我们的配置有问题吗?其实答案很简单。nginx 和 metricbeat 之间的连接是一种 TCP/IP 的连接。一旦连接上,就不会断开。nginx 也不会重新作负载均衡。我们需要对 metricbeat 做一些配置。我们按照如下的方式来重新作练习:

1)在 /etc/nginx/nginx.conf 中去掉 server 192.168.0.3:5044; 然后重新启动 nginx

2) 停止 metricbeat,编辑 metricbeat.yml,并在 output.logstash 的配置部分添加 TTL:

1
2
3
4
5
output.logstash:
  # The Logstash hosts
  hosts: ["192.168.0.4:12345"]
  ttl: "30s"
  pipelining: 0

重新启动 metricbeat:

1
./metricbeat -e

3) 现在应该是和之前一样的效果,只有在 Logstash2 上能看到输出。而在 Logstash1 中没有点输出。

4)重新修改 /etc/nginx/nginx.conf 文件,并添加 server 192.168.0.3:5044;

1
2
3
4
5
6
7
8
9
10
11
stream {
    upstream stream_backend {
        server 192.168.0.4:5044;
        server 192.168.0.3:5044;
    }

    server {
        listen        12345;
        proxy_pass    stream_backend;
    }
}

修改完后,重新启动 nginx 服务:

1
sudo service nginx restart

5) 我们再重新查看 Logstash1 的 console:

这个时候,我们可以看到有一些点开始出现了。这说明我们的 nginx 负载均衡已经起作用了。而且如果按照我们刚才对 metricbeat 的那样配置的话,每当我们添加一个新的 Logstash,我们不需要对任何的 beat 进行额外的配置。负载均衡会自动起做作用。

在我们的练习中,我没有在 Logstash 的 output 中添加 Elasticsearch。这个就留给你们了。