一、部署redis

1、下载redis

[root@linux-node2 ~]# wget http://download.redis.io/releases/redis-4.0.6.tar.gz
[root@linux-node2 ~]# tar -zxvf redis-4.0.6.tar.gz
[root@linux-node2 ~]# mv redis-4.0.6 /usr/loca/src
[root@linux-node2 ~]# cd /usr/local/src/redis-4.0.6
[root@linux-node2 redis-4.0.6]# make
[root@linux-node2 redis-4.0.6]# ln -sv /usr/local/src/redis-4.0.6 /usr/local/redis
[root@linux-node2 redis-4.0.6]# cd /usr/local/redis

2、配置redis

[root@linux-node2 redis]# vim redis.conf 
bind 192.168.56.12
daemonize yes
save ""
requirepass 123456    #开启认证
[root@linux-node2 redis]# cp /usr/local/src/redis-4.0.6/src/redis-server /usr/bin/
[root@linux-node2 redis]# cp /usr/local/src/redis-4.0.6/src/redis-cli /usr/bin/
[root@linux-node2 redis]# redis-server /usr/local/redis/redis.conf 
26617:C 02 Jan 10:35:26.801 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
26617:C 02 Jan 10:35:26.801 # Redis version=4.0.6, bits=64, commit=00000000, modified=
26617:C 02 Jan 10:35:26.801 # Configuration loaded

3、测试redis

[root@linux-node2 ~]# netstat -tulnp |grep 6379
tcp        0      0 192.168.56.12:6379      0.0.0.0:*               LISTEN      26618/redis-server  
[root@linux-node2 redis]# redis-cli -h 192.168.56.12
192.168.56.12:6379> KEYS *
(error) NOAUTH Authentication required.
192.168.56.12:6379> auth 123456
OK
192.168.56.12:6379> KEYS *
(empty list or set)
192.168.56.12:6379> quit

二、部署logstash

1.安装logstash

curl -L -O https://artifacts.elastic.co/downloads/logstash/logstash-7.3.0.tar.gz
tar -xzvf logstash-7.3.0.tar.gz

要了解有关安装、配置和运行Logstash的更多信息,请阅读官网文档。

2.启动测试

cd logstash-7.3.0
#执行启动命令,控制台输入、输出
./bin/logstash -e 'input{stdin{}}output{stdout{}}'
#控制台输入
hello
#控制台输出
{
          "host" => "i-1CB808BE",
      "@version" => "1",
       "message" => "hello",
    "@timestamp" => 2021-02-01T08:53:28.482Z
}

3.配置logstash

进入/config,自定义配置文件my-logstash.conf

\cp logstash-sample.conf my-logstash.conf

my-logstash.conf 

# Sample Logstash configuration for creating a simple
# Beats -> Logstash -> Elasticsearch pipeline.
#配置文档说明
#http://doc.yonyoucloud.com/doc/logstash-best-practice-cn/filter/mutate.html
input {
	file {
		path => [
			# 这里填写需要监控的文件
			"/home/logs/test.log"
		] 
		type => "systemlog"
		#stat_interval => "2" #logstash 每隔多久检查一次被监听文件状态(是否有更新),默认是 1 秒。
	}
}
filter{
	grok {
		#日志正则表达式 引用用法  %{XXX:xxx} 或 %{XXX}
		#https://github.com/elastic/logstash/blob/v1.4.2/patterns/grok-patterns
		#TIMESTAMP_ISO8601	%{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
		#GREEDYDATA	.*
		#NOTSPACE \S+
		#SPACE \s*   空格
		#LOGLEVEL 日志级别正则表达式
		
		# 正则匹配截取
		match => { 
			#2021-02-01 13:47:37.269 [http-nio-7050-exec-20] INFO  c.i.exhibition.limit.SlidingTimeWindowInterceptor - slidingTimeWindow sum = 7
			#"message" => "\s*%{TIMESTAMP_ISO8601:time}\s*%{NOTSPACE:rest}\s*%{GREEDYDATA:log_message}" 
			"message" => "\s*%{TIMESTAMP_ISO8601:time}\s*%{NOTSPACE:rest}\s*%{LOGLEVEL:level}\s*%{GREEDYDATA:log_message}" 
		}
	}
	date {
	  match => ["time", "yyyy-MM-dd HH:mm:ss.SSS"]
	  target => "@timestamp"
	  timezone => "Asia/Shanghai"
	}
	# 时间加8
	ruby { 
		code => "event.set('timestamp', event.get('@timestamp').time.localtime + 8*60*60)" 
	}
	# 修改时间值
	mutate {
		#重命名某个字段,如果目的字段已经存在,会被覆盖掉
		rename => {"timestamp" => "@timestamp"}
	}
	# 条件判断
	# 判断level是否存在 添加log字段
	if [level] {
		mutate{
			add_field => {"log" => "%{level} %{log_message}"}
		}
	}
	# 判断log是否存在 覆盖 日志信息
	if [log] {
		#数据修改
		mutate {
			#重命名某个字段,如果目的字段已经存在,会被覆盖掉
			rename => {"log" => "message"}
		}
	}
	#  判断rest是否存在 覆盖 线程名 i-1CB808BE -> [http-nio-7050-exec-20]
	if [rest] {
		#数据修改
		mutate {
			#重命名某个字段,如果目的字段已经存在,会被覆盖掉
			rename => {"rest" => "host"}
		}
	}
	# 输出redis: @timestamp host message
}
output {
	# 输出到控制台
	stdout { 
		codec => rubydebug 
	}
	# 如果type=systemlog 输出到redis
	if [type] == "systemlog" {
		redis {
			codec => plain
			host => "xxx.xxx.xxx.xxx"     
			port => 6379              # redis端口号
			db => 2                   # redis数据库编号
			data_type => "channel"    # 使用发布/订阅模式
			key => "test"              #通道名称
			password => "xxx"
		}
	}
}

redis配置项

以上所有配置项都是可选的,没有必须的。(以下4个红色配置是最重要的4个配置

  • 批处理类(仅用于data_type为list)
  • batch:设为true,通过发送一条rpush命令,存储一批的数据
  • 默认为false:1条rpush命令,存储1条数据
  • 设为true之后,1条rpush会发送batch_events条数据或发送batch_timeout秒(取决于哪一个先到达)
  • batch_events:一次rpush多少条
  • 默认50条
  • batch_timeout:一次rpush最多消耗多少s
  • 默认5s
  • 编码类
  • codec:对输出数据进行codec,避免使用logstash的separate filter
  • 拥塞保护(仅用于data_type为list)
  • congestion_interval:每多长时间进行一次拥塞检查
  • 默认1s
  • 设为0,表示对每rpush一个,都进行检测
  • congestion_threshold:list中最多可以存在多少个item数据
  • 默认是0:表示禁用拥塞检测
  • 当list中的数据量达到congestion_threshold,会阻塞直到有其他消费者消费list中的数据
  • 作用:防止OOM
  • data_type
  • list:使用rpush
  • channel:使用publish
  • db:使用redis的数据库,默认使用0号
  • host:数组
  • eg.["127.0.0.1:6380", "127.0.0.1"]
  • 可以指定port,会覆盖全局port
  • port:全局port,默认6379
  • key:list或channel的名字
  • 支持动态key,例如:logstash-%{type}
  • password:redis密码,默认不使用密码
  • reconnect_interval:失败重连的间隔,默认为1s
  • timeout:连接超时,默认5s

4.启动

./bin/logstash -f config/my-logstash.conf

启动成功 日志

[2021-01-29T17:26:31,718][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9600}

标准的 service 方式

采用 RPM、DEB 发行包安装的读者,推荐采用这种方式。发行包内,都自带有 sysV 或者 systemd 风格的启动程序/配置,你只需要直接使用即可。
以 RPM 为例,/etc/init.d/logstash 脚本中,会加载 /etc/init.d/functions 库文件,利用其中的 daemon 函数,将 logstash 进程作为后台程序运行。
所以,你只需把自己写好的配置文件,统一放在 /etc/logstash/ 目录下(注意目录下所有配置文件都应该是 .conf 结尾,且不能有其他文本文件存在。因为 logstash agent 启动的时候是读取全文件夹的),然后运行 service logstash start 命令即可。

最基础的 nohup 方式

这是最简单的方式,也是 linux 新手们很容易搞混淆的一个经典问题:
command
command > /dev/null
command > /dev/null 2>&1
command &
command > /dev/null &
command > /dev/null 2>&1 &
command &> /dev/null
nohup command &> /dev/null
请查找以上命令的异同……
想要维持一个长期后台运行的 logstash,你需要同时在命令前面加 nohup,后面加 &。
nohup command /dev/null 2>&1 &

更优雅的 SCREEN 方式

screen 算是 linux 运维一个中高级技巧。通过 screen 命令创建的环境下运行的终端命令,其父进程不是 sshd 登录会话,而是 screen 。这样就可以即避免用户退出进程消失的问题,又随时能重新接管回终端继续操作。

创建独立的 screen 命令如下:

screen -dmS elkscreen_1

接管连入创建的 elkscreen_1 命令如下:

screen -r elkscreen_1

然后你可以看到一个一模一样的终端,运行 logstash 之后,不要按 Ctrl+C,而是按 Ctrl+A+D 键,断开环境。想重新接管,依然 screen -r elkscreen_1 即可。

如果创建了多个 screen,查看列表命令如下:

screen -list

最推荐的 daemontools 方式

不管是 nohup 还是 screen,都不是可以很方便管理的方式,在运维管理一个 ELK 集群的时候,必须寻找一种尽可能简洁的办法。所以,对于需要长期后台运行的大量程序(注意大量,如果就一个进程,还是学习一下怎么写 init 脚本吧),推荐大家使用一款 daemontools 工具。

daemontools 是一个软件名称,不过配置略复杂。所以这里我其实是用其名称来指代整个同类产品,包括但不限于 python 实现的 supervisord,perl 实现的 ubic,ruby 实现的 god 等。

以 supervisord 为例,因为这个出来的比较早,可以直接通过 EPEL 仓库安装。

yum -y install supervisord --enablerepo=epel

在 /etc/supervisord.conf 配置文件里添加内容,定义你要启动的程序:

[program:elkpro_1]
environment=LS_HEAP_SIZE=5000m
directory=/opt/logstash
command=/opt/logstash/bin/logstash -f /etc/logstash/pro1.conf --pluginpath /opt/logstash/plugins/ -w 10 -l /var/log/logstash/pro1.log
[program:elkpro_2]
environment=LS_HEAP_SIZE=5000m
directory=/opt/logstash
command=/opt/logstash/bin/logstash -f /etc/logstash/pro2.conf --pluginpath /opt/logstash/plugins/ -w 10 -l /var/log/logstash/pro2.log

然后启动 service supervisord start 即可。

logstash 会以 supervisord 子进程的身份运行,你还可以使用 supervisorctl 命令,单独控制一系列 logstash 子进程中某一个进程的启停操作:

supervisorctl stop elkpro_2

三、登陆redis中查看

1.date_type => list

[root@linux-node2 ~]# redis-cli -h 192.168.56.12
192.168.56.12:6379> KEYS *
(error) NOAUTH Authentication required.
192.168.56.12:6379> AUTH 123456
OK
192.168.56.12:6379> 
192.168.56.12:6379> select 1
OK
192.168.56.12:6379[1]> KEYS *
1) "test"
192.168.56.12:6379[1]> LLEN test    #查看key的长度
(integer) 248
192.168.56.12:6379[1]> LLEN test
(integer) 249
192.168.56.12:6379[1]> LPOP test    #展示一条记录会减少一条
"{\"@version\":\"1\",\"host\":\"linux-node1\",\"path\":\"/var/log/messages\",\"@timestamp\":\"2018-01-02T03:04:40.424Z\",\"type\":\"systemlog\",\"tags\":[\"_geoip_lookup_failure\"]}"
192.168.56.12:6379[1]> LLEN test
(integer) 248

2.date_type => channel

redis发布订阅缺陷

redis实现了发布订阅(publish/subscribe)的功能,在通常的情况下是不推荐使用的,如果想使用消息队列这种功能,最好还是使用专业的各种MQ中间件,例如rabbitMQ,rockedMQ,activitedMQ等。

概要说一下就是,PUBLISH和SUBSCRIBE的缺陷在于客户端必须一直在线才能接收到消息,断线可能会导致客户端丢失消息,旧版的redis可能会由于订阅者消费不够快而变的不稳定导致崩溃,甚至被管理员杀掉。

第一个原因是和redis系统的稳定性有关。对于旧版的redis来说,如果一个客户端订阅了某个或者某些频道,但是它读取消息的速度不够快,那么不断的积压的消息就会使得redis输出缓冲区的体积越来越大,这可能会导致redis的速度变慢,甚至直接崩溃。也可能会导致redis被操作系统强制杀死,甚至导致操作系统本身不可用。新版的redis不会出现这种问题,因为它会自动断开不符合client-output-buffer-limit pubsub配置选项要求的订阅客户端

第二个原因是和数据传输的可靠性有关。任何网络系统在执行操作时都可能会遇到断网的情况。而断线产生的连接错误通常会使得网络连接两端中的一端进行重新连接。如果客户端在执行订阅操作的过程中断线,那么客户端将会丢失在断线期间的消息,这在很多业务场景下是不可忍受的。

[root@linux-node2 ~]# redis-cli -h 192.168.56.12
192.168.56.12:6379> KEYS *
(error) NOAUTH Authentication required.
192.168.56.12:6379> AUTH 123456
OK
192.168.56.12:6379> 
192.168.56.12:6379> select 1
OK
192.168.56.12:6379[1]> SUBSCRIBE test #订阅test 消息channel通道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "test"
3) (integer) 1

四、写入messages日志测试

[root@linux-node1 conf.d]# echo "helloword" >> /home/logs/test.log

 redis date_type => channel  收到消息

127.0.0.1:6379> SUBSCRIBE test
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "test"
3) (integer) 1
1) "message"
2) "test"
3) "2021-01-29T11:14:17.092Z i-1CB808BE helloword"