Redis 和 Memcached 是非关系型数据库也称为 NoSQL 数据库, MySQL、 Mariadb、 SQLServer、 PostgreSQL、 Oracle 数据库属于关系型数据(RDBMS, Relational Database Management System)。
  Redis(Remote Dictionary Server)在 2009 年发布, 开发者 Salvatore Sanfilippo 是意大利开发者, 他本想为自己的公司开发一个用于替换 MySQL 的产品 Redis, 但是没有想到他把 Redis 开源后大受欢迎,短短几年, Redis 就有了很大的用户群体,目前国内外使用的公司有知乎>网、新浪微博、 GitHub 等。
  redis 是一个开源的、 遵循 BSD 协议的、 基于内存的而且目前比较流行的键值数据库(key-value database),是一个非关系型数据库,redis 提供将内存通过网络远程共享的一种服务,提供类似功能的还有 memcache,但相比 memcache, redis 还提供了易扩展、高性能、 具备数据持久性等功能。
  Redis 在高并发、低延迟环境要求比较高的环境使用量非常广泛, 目前 redis 在 DBEngine 月排行榜 https://db-engines.com/en/ranking 中一直比较靠前,而且一直是键值型存储类的首位。

编译安装

  redis在centos版本自带的yum源中版本比较低,一般都需要我们编译安装更高版本的redis。

准备源码包

  可以先用下载工具去官网下载好源码包,下载链接为 https://db-engines.com/en/ranking
  出于稳定性要求,一般来说实际生产中不会选用最新版的redis,避免因为漏洞造成服务器的安全隐患,所以本次演示,我们选用目前redis4的最新版本,redis-4.0.14来安装。

编译安装

  tar xf redis-4.0.14..tar.gz
  cd redis-4.0.14
  编译安装redis的依赖包不多,有make和gcc就够了。

1
yum install make gcc -y

  如果是最小化安装的新系统,忘记安装gcc的话直接去尝试编译安装redis,就会遇到报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
make[3]: Entering directory '/root/redis-4.0.14/deps/hiredis'
gcc -std=c99 -pedantic -c -O3 -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb net.c
make[3]: gcc: Command not found
make[3]: *** [Makefile:156: net.o] Error 127
make[3]: Leaving directory '/root/redis-4.0.14/deps/hiredis'
make[2]: *** [Makefile:46: hiredis] Error 2
make[2]: Leaving directory '/root/redis-4.0.14/deps'
make[1]: [Makefile:180: persist-settings] Error 2 (ignored)
CC adlist.o
/bin/sh: cc: command not found
make[1]: *** [Makefile:228: adlist.o] Error 127
make[1]: Leaving directory '/root/redis-4.0.14/src'
make: *** [Makefile:9: install] Error 2

  提示没装gcc,再回头补上,yum install gcc -y,也还是会报错的。

1
2
3
4
5
6
7
8
9
10
11
12
[root@CentOS8 redis-4.0.14]#make PREFIX=/apps/redis install
cd src && make install
make[1]: Entering directory '/root/redis-4.0.14/src'
CC adlist.o
In file included from adlist.c:34:
zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory
#include <jemalloc/jemalloc.h>
^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [Makefile:228: adlist.o] Error 1
make[1]: Leaving directory '/root/redis-4.0.14/src'
make: *** [Makefile:9: install] Error 2

  这是因为上次的编译失败,有残留的文件,我们需要清理下,make distclean,然后重新编译就可以了,make PREFIX=/apps/redis install
  网上也有说可以通过加选项make MALLOC=libc来解决,不过其实是有一些隐患的。首先我们要知道redis 需要使用内存分配器的, 默认是指定内存分配器为 jemalloc ,make MALLOC=libc 就是指定内存分配器为 libc ,而jemalloc 内存分配器在实践中处理内存碎片是要比libc 好的,而且在README.md 文档也说明到了,jemalloc内存分配器也是包含在源码包里面的,可以在deps 目录下看到 jemalloc 目录。
  编译完成后,接下来我们还需要几步操作。
  创建目录结构mkdir /apps/redis/{etc,logs,data,run}
  从源码包中复制配置文件cp redis.conf /apps/redis/etc/
  创建systemctl服务启动脚本,为了避免安全隐患,我们还要将redis服务设为以redis身份启动,所以还要修改目录权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat > /usr/lib/systemd/system/redis.service <<"END"
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
#ExecStart=/usr/bin/redis-server /etc/redis.conf --supervised systemd
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
END

  创建redis用户,并修改redis目录属主属组。

1
2
groupadd -g 379 redis && useradd -u 379 -g 379 redis -s /sbin/nologin
chown redis.redis -R /apps/redis

  修改PATH变量或者直接用软链接的方式(用一个即可,效果一样),方便执行redis命令。
  ln -sv /apps/redis/bin/* /usr/local/bin/(软链接)
  echo "PATH=/apps/redis/bin:$PATH" > /etc/profile.d/redis.sh;. /etc/profile.d/redis.sh(改PATH变量)

修改内核参数

  这时redis服务就其实已经搭建完成了,已经可以通过服务脚本进行启动了。可是如果直接启动会有一些[warning]信息,而且很有可能在高并发的时候导致redis崩溃。

1
2
3
4
13636:M 13 Nov 10:37:06.195 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
13636:M 13 Nov 10:37:06.195 # Server initialized
13636:M 13 Nov 10:37:06.195 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
13636:M 13 Nov 10:37:06.195 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

  我们可以通过修改一些内核参数来避免这一风险。

  • TCP backlog 参数控制的是三次握手的时候 server 端收到 client ack 确认号之后的队列值,redis默认为511。我们需要将内核的net.core.somaxconn值(系统默认128)更改为大于511,或将redis的队列之修改小于128.
  • 将vm.overcommit_memory值改为1
    0、表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
    1、表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
    2、表示内核允许分配超过所有物理内存和交换空间总和的内存
  • transparent hugepage:
    开启大页内存动态分配,需要关闭让 redis 负责内存管理。

  所以,我们执行下面操作

1
2
3
4
cat >> /etc/sysctl.conf << END
net.core.somaxconn = 512
vm.overcommit_memory = 1
END
1
echo never > /sys/kernel/mm/transparent_hugepage/enabled

  至此,redis就正式调试完成,可以正常使用了。

附:一键编译安装redis脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/bin/bash
DST="/apps"
#[ -d $DST ] || { echo "install into $DST fail,No such file or directory" ;exit 10;}
[ -a redis-*.tar.* ] || { echo ' the absence of redis.tar.gz' ;exit 1;}
[ -a /usr/lib/systemd/system/redis.service ] && { echo 'redis.service is exist,redis is aready installed' ;exit 2;}
[ -d $DST/redis* ] && { echo "redis is aready installed into $DST/redis" ;exit 3;}
id redis &>/dev/null && { echo 'user redis is exist,redis is aready installed' ; exit 4;} || { groupadd -g 379 redis && useradd -u 379 -g 379 redis -s /sbin/nologin || { echo user 379 is exist ;exit 5; } }
mkdir -p $DST/redis
yum install -y make gcc
#yum install -y make gcc wget
#wget http://download.redis.io/releases/redis-4.0.14.tar.gz
tar xf redis-*.tar.*
PTH=`find . -name "redis*" -type d |head -n1`
cd $PTH
make PREFIX=$DST/redis install
mkdir $DST/redis/{etc,logs,data,run}
cp redis.conf /apps/redis/etc/
chown redis.redis -R /apps/redis
cat > /usr/lib/systemd/system/redis.service << END
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
#ExecStart=/usr/bin/redis-server /etc/redis.conf --supervised systemd
ExecStart=$DST/redis/bin/redis-server $DST/redis/etc/redis.conf --supervised systemd
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
END

ln -sv $DST/redis/bin/* /usr/local/bin/

cat >> /etc/sysctl.conf << END
net.core.somaxconn = 512
vm.overcommit_memory = 1
END

echo never > /sys/kernel/mm/transparent_hugepage/enabled

systemctl enable --now redis

一个低调的男人