CentOS7に最新のRedisをインストールする手順

## 作業環境

* CentOS 7(7.9.2009 64bit)
* Redis 6.0.10

## パッケージを最新にする

必須ではないけど、いろいろ最新のほうが望ましいため、yum updateを行っておく。

```
$ sudo yum update -y
```

# gccのバージョンを新しくする

CentOS7に標準でインストールされているgccのバージョンが低いため、最新のredisをmakeするとエラーになってしまう。
そこで、gccのバージョンを新しくする。

* 必要なパッケージをインストール
<pre>
sudo yum install -y centos-release-scl
sudo yum-config-manager --enable rhel-ser
sudo yum install devtoolset-7</pre>
* 新しいgccを有効にする
<pre>scl enable devtoolset-7 bash</pre>
* gccのバージョンを確認
<pre>$ gcc --version
gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</pre>
* 常時新しいgccを使用するために~/.bash_profileの最後に以下を追加
<pre>
# 新しいバージョンのgccを有効にする
source /opt/rh/devtoolset-7/enable
</pre>

## 作業ディレクトリを準備する

ここではホームディレクトリに作業用の一時ディレクトリを作成するものとする。
作業はrootではなく、一般ユーザーで行う。

<pre>
$ mkdir -p ~/build
</pre>

## Redisのソースをダウンロードしてビルドする

<pre>
$ cd ~/build
$ wget https://download.redis.io/releases/redis-6.0.10.tar.gz
$ tar xvzf redis-6.0.10.tar.gz
$ cd redis-6.0.10
$ make

Hint: It's a good idea to run 'make test' ;)

make[1]: Leaving directory '/home/watanabe/build/redis-6.0.10/src'
</pre>

上記の「It's a good idea to run 'make test'」と表示されればビルド成功。

### テストを実行して問題がないか確認する

<pre>
$ make test
...
\o/ All tests passed without errors!

Cleanup: may take some time... OK
</pre>

テストに失敗する場合は、いったんサーバを再起動すると改善する場合がある。
特に、gccのバージョンを最新にした直後にmake testを行った時に失敗する場合がある。

## Redisをインストール

makeのパラメータにPREFIX=パスをセットすると、インストール先を変更できる(デフォルトは/usr/local)
/usr/localでは、他のツールとファイルがごちゃまぜになってしまう。
ここでは、後で簡単に削除できるように/usr/local/redis-6.0.10以下へインストールする事にする。

後々のために、/usr/local/redis -> /usr/local/redis-6.0.10 となるシンボリックリンクも作成する。

<pre>
$ sudo make PREFIX=/usr/local/redis-6.0.10 install
$ sudo ln -s /usr/local/redis-6.0.10 /usr/local/redis
</pre>

シンボリックリンクと実ディレクトリの関係はこうなる。
<pre>
$ ls -l /usr/local/ |grep redis
lrwxrwxrwx   1 root     root       23 Jan 29 10:48 redis -> /usr/local/redis-6.0.10
drwxr-xr-x   3 root     root       17 Jan 29 10:48 redis-6.0.10
</pre>

### Redisのファイル構成

非常にシンプルで、実行ファイルしかない。

<pre>
$ tree /usr/local/redis-6.0.10/
/usr/local/redis-6.0.10/
`-- bin
    |-- redis-benchmark
    |-- redis-check-aof
    |-- redis-check-rdb
    |-- redis-cli
    |-- redis-sentinel -> redis-server
    `-- redis-server

1 directory, 6 files
</pre>

---

## 設定ファイルを修正する

### 修正内容

以下のように修正する。

<pre>
daemonize yes
timeout 60
logfile /var/log/redis.log
dir /usr/local/redis/data
appendonly yes
</pre>

### sedコマンドで置換する。

コピペしやすいように先頭の$は除いてあるので、コピペで実行。
<pre>
cd ~/build/redis-6.0.10
cp -a redis.conf redis.conf.default
sed -i 's/^daemonize no/daemonize yes/' redis.conf
sed -i 's/^timeout 0/timeout 60/' redis.conf
sed -i 's/^logfile ""/logfile "\/var\/log\/redis.log"/' redis.conf
sed -i 's/^dir .\//dir \/usr\/local\/redis\/data/' redis.conf
sed -i 's/^appendonly no$/appendonly yes/' redis.conf
</pre>

### 差分を確認

<pre>
$ diff redis.conf redis.conf.default
112c112
< timeout 60
---
> timeout 0
224c224
< daemonize yes
---
> daemonize no
260c260
< logfile "/var/log/redis.log"
---
> logfile ""
365c365
< dir /usr/local/redis/data
---
> dir ./
1094c1094
< appendonly yes
---
> appendonly no
</pre>

---

## 設定ファイルを配置する

設定ファイルを/usr/local/redis/etcへコピー
デフォルトのファイルもコピーしておく。
<pre>
$ sudo mkdir -p /usr/local/redis-6.0.10/etc
$ sudo cp -a redis.conf.default /usr/local/redis-6.0.10/etc 
$ sudo cp -a redis.conf /usr/local/redis-6.0.10/etc 
</pre>

データディレクトリを作成する
<pre>
$ sudo mkdir /usr/local/redis/data
</pre>

---

## サービスに登録する

ここはrootで作業する。
viで以下のファイルを作成する。

* /usr/lib/systemd/system/redis.service

```text
[Unit]
Description=Redis
After=syslog.target network.target rc-local.service

[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
ExecStop=/usr/local/redis/bin/redis-cli -p 6379 shutdown

[Install]
WantedBy=multi-user.target
```


* サービスに登録する
<pre>
# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
</pre>
* 自動起動が有効になっている事を確認する
<pre>
# systemctl is-enabled redis
enabled
</pre>
* 起動を確認する
<pre>
# systemctl start redis
# systemctl status redis |grep Active
   Active: active (running) since Tue 2017-01-17 14:37:02 JST; 5s ago
</pre>
* 停止を確認する
<pre>
# systemctl stop redis
# systemctl status redis |grep Active
   Active: inactive (dead) since Tue 2017-01-17 14:34:53 JST; 1min 47s ago
</pre>

### 起動停止が行える事を確認したら、再度サービスを起動する。

<pre>
$ systemctl start redis
$ systemctl status redis
● redis.service - Redis
   Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2021-01-29 11:21:34 JST; 4s ago
</pre>

## /etc/sysctl.confにvm.overcommit_memoryの設定をする

redisを起動するとログファイル(/var/log/redis.log)にvm.overcommit_memory = 1を設定しろというメッセージが出ているので、設定する。
具体的には、/etc/sysctl.confの最終行にvm.overcommit_memory = 1を追加する。

<pre>
# cp -a /etc/sysctl.conf /etc/sysctl.conf.`date +%Y%m%d`
# echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
</pre>

設定の確認
<pre>
# /sbin/sysctl -a |grep commit
vm.overcommit_memory = 0       ← 反映されていない
vm.overcommit_ratio = 50
vm.nr_overcommit_hugepages = 0
</pre>

反映する
<pre>
# /sbin/sysctl -p
# /sbin/sysctl -a |grep commit
vm.overcommit_memory = 1       ← 反映された！
vm.overcommit_ratio = 50
vm.nr_overcommit_hugepages = 0
</pre>

## somaxconnの設定

redisを起動すると、ログファイルに以下の警告が出力される。
<pre>
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
</pre>

現在の値を確認する
<pre>
# /sbin/sysctl -a |grep somax
net.core.somaxconn = 128
</pre>

値を変更する
<pre>
# echo 'net.core.somaxconn = 1024' >> /etc/sysctl.conf
# /sbin/sysctl -p
net.core.somaxconn = 1024
vm.overcommit_memory = 1
</pre>

## Transparent Huge Pages(THP)の無効化

redisのログに出ている警告に従って、/etc/rc.localに追記する。
さらに、/etc/rc.local -> /etc/rc.d/rc.localとなっているが実行権限がデフォルトでは付与されていないので、付与しておく。
<pre>
# echo 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
# chmod +x /etc/rc.d/rc.local
</pre>

## ログのローテーション設定

* /etc/logrotate.d/redis

<pre>
/var/log/redis.log {
  daily
  missingok
  rotate 5
  nocompress
  notifempty
  copytruncate
  create 0644 root root
}
</pre>

## サーバを再起動

/etc/rc.localはサーバの起動時にしか反映されないので、サーバを再起動する。
redisを停止してログファイル(/var/log/redis.log)の中身を空にしてから再起動する。
これは、既存のログがあると警告が消えたかどうか分かりづらいため。
ログを空にすれば警告がなくなったかどうか分かりやすい。

<pre>
# systemctl stop redis
# cat /dev/null > /var/log/redis.log
# reboot
</pre>

##
## 再起動後のログを確認する

再起動後に/var/log/redis.logを確認し、警告が出ていなければ完了。
/var/log/redis.logが空の状態で再起動したのでcatコマンドでログ全体を確認する。

<pre>
$ cat /var/log/redis.log
1346:C 29 Jan 2021 11:28:18.007 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1346:C 29 Jan 2021 11:28:18.008 # Redis version=6.0.10, bits=64, commit=00000000, modified=0, pid=1346, just started
1346:C 29 Jan 2021 11:28:18.008 # Configuration loaded
1346:M 29 Jan 2021 11:28:18.012 * Increased maximum number of open files to 10032 (it was originally set to 1024).
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 6.0.10 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1346
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

1346:M 29 Jan 2021 11:28:18.089 # Server initialized
1346:M 29 Jan 2021 11:28:18.091 * Ready to accept connections
</pre>

警告がまったく出ていない状態になれば設定完了