使用Go的redigo库尝试进行稳健的Redis和Pub/Sub通信的发布
首先
本文是「and factory Advent Calendar 2020」第18天的文章。
昨天是 @ichi-nakashima 先生的【React Hooks】从组件中提取带有状态的逻辑的技巧。
Redis提供了Pub/Sub功能。
我认为Redis一般被用作KVS(键值存储),但它也具备Pub/Sub(发布/订阅)功能,因此我想用它来与Go进行交互。
Redis的发布/订阅功能是什么?
在Redis中,”Publish”(发布)和”Subscribe”(订阅)分别表示创建一个频道,并且可以对该频道进行”Publish”(发布)和”Subscribe”(订阅)操作(类似于发送和接收消息)。
-
- 公式ドキュメント
- 日本語翻訳ドキュメント(非公式)
本次将搭建一个稳定的Redis,然后尝试从Go中实施Publish操作向该Redis发布数据。
搭建Redis服务器。
我已经在Vagrant+虚拟机上的CentOS7环境中自行安装了Redis。
以下是安装过程(添加EPEL仓库→安装Redis)的日志。
首先添加EPEL仓库
(*关于EPEL,请参考Qiita上的CentOS等相关资料。)
[vagrant@localhost ~]$ sudo yum install epel-release
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.tsukuba.wide.ad.jp
* extras: ftp.tsukuba.wide.ad.jp
* updates: download.nus.edu.sg
Resolving Dependencies
--> Running transaction check
---> Package epel-release.noarch 0:7-11 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
===================================================================================================================================================================
Package Arch Version Repository Size
===================================================================================================================================================================
Installing:
epel-release noarch 7-11 extras 15 k
Transaction Summary
===================================================================================================================================================================
Install 1 Package
Total download size: 15 k
Installed size: 24 k
Is this ok [y/d/N]: y
Downloading packages:
epel-release-7-11.noarch.rpm | 15 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : epel-release-7-11.noarch 1/1
Verifying : epel-release-7-11.noarch 1/1
Installed:
epel-release.noarch 0:7-11
Complete!
下一步是安装Redis。
[vagrant@localhost ~]$ sudo yum install redis -y
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
epel/x86_64/metalink | 6.4 kB 00:00:00
* base: ftp.tsukuba.wide.ad.jp
* epel: download.nus.edu.sg
* extras: ftp.tsukuba.wide.ad.jp
* updates: download.nus.edu.sg
epel | 4.7 kB 00:00:00
(1/3): epel/x86_64/group_gz | 95 kB 00:00:01
(2/3): epel/x86_64/updateinfo | 1.0 MB 00:00:02
(3/3): epel/x86_64/primary_db | 6.8 MB 00:00:01
Resolving Dependencies
--> Running transaction check
---> Package redis.x86_64 0:3.2.12-2.el7 will be installed
--> Processing Dependency: libjemalloc.so.1()(64bit) for package: redis-3.2.12-2.el7.x86_64
--> Running transaction check
---> Package jemalloc.x86_64 0:3.6.0-1.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
===================================================================================================================================================================
Package Arch Version Repository Size
===================================================================================================================================================================
Installing:
redis x86_64 3.2.12-2.el7 epel 544 k
Installing for dependencies:
jemalloc x86_64 3.6.0-1.el7 epel 105 k
Transaction Summary
===================================================================================================================================================================
Install 1 Package (+1 Dependent package)
Total download size: 648 k
Installed size: 1.7 M
Downloading packages:
warning: /var/cache/yum/x86_64/7/epel/packages/jemalloc-3.6.0-1.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY0 B/s | 0 B --:--:-- ETA
Public key for jemalloc-3.6.0-1.el7.x86_64.rpm is not installed
(1/2): jemalloc-3.6.0-1.el7.x86_64.rpm | 105 kB 00:00:02
(2/2): redis-3.2.12-2.el7.x86_64.rpm | 544 kB 00:00:02
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 293 kB/s | 648 kB 00:00:02
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Importing GPG key 0x352C64E5:
Userid : "Fedora EPEL (7) <epel@fedoraproject.org>"
Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5
Package : epel-release-7-11.noarch (@extras)
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : jemalloc-3.6.0-1.el7.x86_64 1/2
Installing : redis-3.2.12-2.el7.x86_64 2/2
Verifying : redis-3.2.12-2.el7.x86_64 1/2
Verifying : jemalloc-3.6.0-1.el7.x86_64 2/2
Installed:
redis.x86_64 0:3.2.12-2.el7
Dependency Installed:
jemalloc.x86_64 0:3.6.0-1.el7
Complete!
由于Redis安装已经完成,现在启动它。
[vagrant@localhost ~]$ sudo systemctl start redis.service
启用Redis的自动启动。
[vagrant@localhost ~]$ sudo systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
最后,确认一下Redis的状态。
[vagrant@localhost ~]$ sudo systemctl status redis.service
● redis.service - Redis persistent key-value database
Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/redis.service.d
└─limit.conf
Active: active (running) since Mon 2020-07-13 09:43:21 UTC; 31s ago
Main PID: 22002 (redis-server)
CGroup: /system.slice/redis.service
└─22002 /usr/bin/redis-server 127.0.0.1:6379
Jul 13 09:43:21 localhost.localdomain systemd[1]: Starting Redis persistent key-value database...
Jul 13 09:43:21 localhost.localdomain systemd[1]: Started Redis persistent key-value database.
为了确认,使用redis-cli命令执行ping操作,以确定是否返回PONG。
※这个ping命令经常被用于通信确认的命令。
[vagrant@localhost ~]$ redis-cli ping
PONG
只需编辑/etc/redis.conf文件并设置好IP地址等信息,就能完成Redis的安装。
[vagrant@localhost ~]$ sudo vi /etc/redis.conf
加强Redis的防护(设置密码)
[vagrant@localhost ~]$ echo "secretkey" | sha256sum
92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a -
[vagrant@localhost ~]$ sudo vi /etc/redis.conf
由於有“SECURITY”一項,請在其下方添加“requirepass”並填寫密碼。
################################## SECURITY ###################################
# Require clients to issue AUTH <PASSWORD> before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
requirepass 92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a
在此情况下,我们使用sha256sum生成的哈希值作为密码进行设置,只要长度足够长即可。
编辑/etc/redis.conf后,重新启动Redis,并从redis-cli开始以无密码的状态执行命令。
[vagrant@localhost ~]$ sudo systemctl restart redis.service
[vagrant@localhost ~]$ redis-cli
127.0.0.1:6379> set key 10
(error) NOAUTH Authentication required.
确认出现了上述的认证错误。
接下来,输入auth指令,并使用之前设定的密码来执行。
127.0.0.1:6379> auth 92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a
OK
只要OK出现,就表示已经通过了认证,可以执行命令,然后就会正常运行。
127.0.0.1:6379> set key 10
OK
127.0.0.1:6379> get key
"10"
127.0.0.1:6379> quit
Go语言的示例代码
样品代码编写了将消息发布到设置了密码的Redis的过程。(*设置密码并非必需,仅作为一种预防措施)
package main
import (
"fmt"
"github.com/gomodule/redigo/redis"
)
// RedisPublish : コマンドをRedisへパブリッシュする
func RedisPublish(message string) (int, error) {
conn, redisAuthPass, err := ConnectionRedis()
if err != nil {
fmt.Println(err)
return 0, err
}
defer conn.Close()
// パス認証
if redisAuthPass != "" {
_, err = conn.Do("AUTH", redisAuthPass)
if err != nil {
fmt.Println(err)
return 0, err
}
}
// パブリッシュ
res, err := redis.Int(conn.Do("PUBLISH", "test_channel", message))
if err != nil {
fmt.Println(err)
return 0, err
}
return res, err
}
// ConnectionRedis : Redisと接続し接続情報とAuthパスを返す
func ConnectionRedis() (redis.Conn, string, error) {
// RedisのAUTHパス
AuthPass := "92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a"
// RedisのIPアドレス
RedisIPAddress := "192.168.33.100"
// Redisのポート番号
RedisPort := "6379"
// 接続
conn, err := redis.Dial("tcp", RedisIPAddress+":"+RedisPort)
if err != nil {
fmt.Println(err)
return nil, "", err
}
return conn, AuthPass, err
}
我认为实际上 AUTH路径等会根据环境的不同而改变,所以最好不要在源代码中写死,而是在.env等文件中进行描述并进行读取。
参考:【Go】使用Golang的库“godotenv”来使用.env文件 – Qiita
进一步加强Redis的稳定性。
个人认为,连接到Redis时,只需要认证密码就足够了,但为了确保安全,还可以采取以下措施。
更改端口号
将Redis的默认端口号是6379变更为其他数字可以在一定程度上提高安全性。
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
# port 6379
port 6597
修改后需要重新启动Redis。
重要指令的修改
通过在下面的redis.conf中追加替代命令名称并重新启动,可以将诸如CONFIG、SHUTDOWN、FLUSHDB等可能导致问题的命令替换为其他字符串。
# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to slaves may cause problems.
rename-command CONFIG configconfig
rename-command FLUSHDB SF_FLUSHDB
rename-command SHUTDOWN RENAME_SD
确认以下命令是否有更改。
[vagrant@localhost ~]$ sudo systemctl restart redis.service
[vagrant@localhost ~]$ redis-cli
127.0.0.1:6379> auth 92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a // 上で設定したパス
OK
127.0.0.1:6379> config get requirepass
(error) ERR unknown command 'config' // configというコマンドは無い(上で変更したため)
127.0.0.1:6379> configconfig get requirepass
1) "requirepass"
2) "92d4e0a2ad853e81e6d4bf147618aae5a06f201e6e72a67794a542409c9d125a"
127.0.0.1:6379> exit
更改Redis数据目录的权限
将权限更改为770,只允许Redis用户和Redis群组访问。
[vagrant@localhost ~]$ ls -l /var/lib | grep redis
drwxr-x---. 2 redis redis 22 Jul 13 13:31 redis
[vagrant@localhost ~]$ sudo chmod 770 /var/lib/redis
[vagrant@localhost ~]$ ls -l /var/lib | grep redis
drwxrwx---. 2 redis redis 22 Jul 13 13:31 redis
结束
-
- なんか走り書きしたら雑なまとめになってしまった感がある・・・
-
- ちなみにSubscribは今度時間あれば書くかもしれません・・・(予定は未定です)
- あとまだRedisは構成ファイルの権限変更したりなどで強固にできますがここでは割愛します(DigitalOceanさんの参考記事をどうぞ)
请参照以下网址。
-
- How to Install and Secure Redis in CentOS 7 | DigitalOcean
-
- Redigoを使う(6) パブリッシュ/サブスクライブ – Qiita
- RedisのPub/Subがわからない人はRedisを使って理解しよう | アールエフェクト