CentOS 7.9 / Debian 11 源码编译redis 7.0.5

CentOS 7.9 / Debian 11 源码编译redis 7.0.5

如果你手上没有合适的干净的Linux系统,可以用docker容器来编译

# centos7
docker pull centos:centos7.9.2009

# debian 11(bullseye是系统代号)
docker pull debian:bullseye

下载解压

由于Redis是一个开源的软件,它的源码在github上就有,所以我们下载的时候去它的github的Releases中下载你需要的版本就行。

Releases中复制源码包链接,用wget下载

wget https://github.com/redis/redis/archive/refs/tags/7.0.5.tar.gz

解压→进入解压后的文件夹→查看文件夹中的文件

tar -zxf 7.0.5.tar.gz
cd redis-7.0.5

关于编译

C/C++语言编写的程序,源码编译都是用make命令编译,然后用make install命令安装,但关键是在编译之前需要生成一个“Makefile”文件,然后make命令才能根据这个Makefile来编译,目前生成Makefile的方法有两种:

  • 1、AutoTools方式:如果源码中有configure文件,那就代表用的是AutoTools(包含autoconf,autotools,libtool)方式,configure文件就是编写程序的人用autoconfautomake这两个工具生成的,我们执行./configure即可生成Makefile,当然configure也是有很多参数的,你可以执行./configure --help来查找有哪些参数,结合程序官方文档或网上资料,给定你需要的参数再来执行configure命令,一般来说会有一个--prefix=/path/to/xxx/用于指定把编译好的程序安装到哪个文件夹中;
  • 2、cmake方式:cmake会根据源码包中的CMakeLists.txt文件生成Makefile。

以上两种方式,无论是哪种,都需要gcc(C语言编译器,是GNU Compiler Collection的缩写,中文翻译GNU编译器集合),如果你的程序是C++写的,还需要g++(C++编译器),并且还需要pkg-config(用于自动给编译器添加合适的编译选项)。

编译

根据关于编译中的说法,编译一个软件,首先我们需要生成一个Makefile文件,但是我们用ls -l查看一下前面解压好的源码文件,可以发现它里面已经有一个Makefile文件了

total 264
-rw-rw-r--  1 root root  37069 Sep 22 03:42 00-RELEASENOTES
-rw-rw-r--  1 root root     51 Sep 22 03:42 BUGS
-rw-rw-r--  1 root root   5027 Sep 22 03:42 CODE_OF_CONDUCT.md
-rw-rw-r--  1 root root   2634 Sep 22 03:42 CONTRIBUTING.md
-rw-rw-r--  1 root root   1487 Sep 22 03:42 COPYING
drwxrwxr-x  7 root root   4096 Sep 22 03:42 deps
-rw-rw-r--  1 root root     11 Sep 22 03:42 INSTALL
-rw-rw-r--  1 root root    151 Sep 22 03:42 Makefile
-rw-rw-r--  1 root root   6888 Sep 22 03:42 MANIFESTO
-rw-rw-r--  1 root root  22441 Sep 22 03:42 README.md
-rw-rw-r--  1 root root 106545 Sep 22 03:42 redis.conf
-rwxrwxr-x  1 root root    279 Sep 22 03:42 runtest
-rwxrwxr-x  1 root root    283 Sep 22 03:42 runtest-cluster
-rwxrwxr-x  1 root root   1578 Sep 22 03:42 runtest-moduleapi
-rwxrwxr-x  1 root root    285 Sep 22 03:42 runtest-sentinel
-rw-rw-r--  1 root root   1695 Sep 22 03:42 SECURITY.md
-rw-rw-r--  1 root root  14005 Sep 22 03:42 sentinel.conf
drwxrwxr-x  4 root root   4096 Sep 22 03:42 src
drwxrwxr-x 11 root root   4096 Sep 22 03:42 tests
-rw-rw-r--  1 root root   3055 Sep 22 03:42 TLS.md
drwxrwxr-x  8 root root   4096 Sep 22 03:42 utils

所以,这就不需要用./configurecmake的方式来生成Makefile文件了,而是直接make就可以,但由于没有./configure来配置参数,所以参数需要直接传给make,具体有哪些参数呢?你只能看源码文件夹中的Readme.md文件了。

我总结了一下,大概有以下选项

# 开启tls,主要是让客户端和服务器端连接时可以使用tls协议(体现为连接时使用`rediss://`协议)
BUILD_TLS=yes

# 生成systemd的service文件,主要是能让你使用systemctl来管理redis的启动停止重启
USE_SYSTEMD=yes

# 指定安装目录
PREFIX=/usr/local/redis/

假设我三个选项都使用(你可以只挑你想要的选项),那么编译语句如下(如果在docker里面,就不要用USE_SYSTEMD)

# 编译
make BUILD_TLS=yes USE_SYSTEMD=yes

# 安装,PREFIX选项用于指定安装位置,必须放在make install中,放在make中是不会起作用的
make install PREFIX=/usr/local/redis/

其实,make和make install是可以结合起来的,不是用&&,而是直接make install

make BUILD_TLS=yes PREFIX=/usr/local/redis/ USE_SYSTEMD=yes install

安装依赖

但是上面语句不能直接运行,需要先安装依赖,make和gcc是编译C语言程序必须的,而openssl11是因为启用了tls,以下是centos7系统安装依赖

yum update -y
yum install -y epel-release
yum update -y

yum install -y make
yum install -y gcc

# 如果你使用了BUILD_TLS=yes,需要安装openssl   
yum install -y openssl11 openssl11-devel

# 如果你使用了USE_SYSTEMD=yes选项,在centos7中要安装systemd-devel
yum install -y systemd-devel

如果你是debian系统(我这里用的debian 11),则要安装这些依赖

apt update -y

apt install -y make
apt install -y gcc
# 如果没有会提示not found,但不影响最终编译
apt install -y pkg-config

# 如果你使用了BUILD_TLS=yes,需要安装openssl   
apt install -y openssl libssl-dev

# 如果你使用了USE_SYSTEMD=yes选项,在debian中要安装libsystemd-dev
apt install -y libsystemd-dev

解决错误

安装完依赖后,再次运行编译安装语句(如果在docker中则去掉最后一个选项USE_SYSTEMD=yes)

make BUILD_TLS=yes PREFIX=/usr/local/redis/ USE_SYSTEMD=yes install

如果是在debian中,上边的编译安装应该已经完成了,但如果在centos7中,很不幸,编译会失败,它会报两个错误

ssl.c:46:25: fatal error: openssl/ssl.h: No such file or directory
 #include <openssl/ssl.h>

 zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory
 #include <jemalloc/jemalloc.h>

找不到ssl.h是因为程序默认是去/usr/include/下找要包含的标准头文件的,而openssl/ssl.h是在redis代码里include指令指定的,但是我们去/usr/include/下查找openssl,你会发现只有openssl11(而不是“openssl”),这是因为我们安装的是openssl11,所以它肯定找不到,我们只需要做一个软链接到相同目录就行,相当于给它换个名字

ln -s /usr/include/openssl11/openssl/ /usr/include/openssl

如果以下命令能输出ssl.h,则说明上述软链接正确了

ls -l /usr/include/openssl/ | grep ssl.h

然后清理一下再重新make,但是要用make distclean而不是用make clean来清理,主要是因为它里面带一些依赖包,deps文件夹中,它们的缓存也要被同时清理。

清理之后,我们再来重新编译(如果在docker中则去掉最后一个选项USE_SYSTEMD=yes)

make BUILD_TLS=yes PREFIX=/usr/local/redis/ USE_SYSTEMD=yes install

这次你会发现它又报另一个错

/usr/bin/ld: cannot find -lssl
/usr/bin/ld: cannot find -lcrypto
collect2: error: ld returned 1 exit status
make[1]: *** [redis-server] Error 1
make[1]: Leaving directory `/root/redis-compile/redis-7.0.5/src'
make: *** [all] Error 2

我们看上边的报错,主要是前两行,找不到-lssl-lcrypto,这两个是什么呢?-l表示它是动态链接库,动态链接库都是以“lib”开头,以“.so”结尾的文件,而中间部分就是除去“-l”的部分,即-lssl-lcrypto对应的动态链接库名称分别为“libssl.so”和“libcrypto.so”,也就是说编译的时候无法找到“libssl.so”和“libcrypto.so”这两个文件。

此时我们可以用find / -name libssl.so全局搜索一下,发现它是个软链接,位于/usr/lib64/openssl11/中,如下所示

[root@52fa920152b6 redis-7.0.5]# ls -l /usr/lib64/openssl11/
total 0
lrwxrwxrwx 1 root root 22 Oct 13 19:24 libcrypto.so -> ../libcrypto.so.1.1.1k
lrwxrwxrwx 1 root root 19 Oct 13 19:24 libssl.so -> ../libssl.so.1.1.1k

但由于它们在openssl11文件夹中,是无法被编译器搜索到的,我也尝试过把/usr/lib64/openssl11/这个地址写入到/etc/ld.so.conf文件中并执行ldconfig,但是没有用,一样报找不到-lssl-lcrypto

所以我们换种方法,直接把它们做个软链接到/usr/lib64/,名字必须是libcrypto.solibssl.so,而之前的/usr/lib64/openssl11/就可以删掉了,我觉得它没啥用了

ln -s /usr/lib64/libcrypto.so.1.1.1k /usr/lib64/libcrypto.so
ln -s /usr/lib64/libssl.so.1.1.1k /usr/lib64/libssl.so
rm -rf /usr lib64/openssl11

现在我们用make distclean清理一下,然后再次重新编译(如果在docker中则去掉最后一个选项USE_SYSTEMD=yes)

make BUILD_TLS=yes PREFIX=/usr/local/redis/ USE_SYSTEMD=yes install

可以发现已经不报错了,最后几句如下

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

    INSTALL redis-server
    INSTALL redis-benchmark
    INSTALL redis-cli

由于我们指定安装到/usr/local/redis/中,redis编译好的可执行文件会被安装到redis目录下的bin目录中

root@459873c023b6:~/redis3-7.0.5# ls -l /usr/local/redis/
total 4
drwxr-xr-x 2 root root 4096 Oct 15 14:10 bin
root@459873c023b6:~/redis3-7.0.5# ls -l /usr/local/redis/bin/
total 29336
-rwxr-xr-x 1 root root  7569488 Oct 15 14:10 redis-benchmark
lrwxrwxrwx 1 root root       12 Oct 15 14:10 redis-check-aof -> redis-server
lrwxrwxrwx 1 root root       12 Oct 15 14:10 redis-check-rdb -> redis-server
-rwxr-xr-x 1 root root  7513992 Oct 15 14:10 redis-cli
lrwxrwxrwx 1 root root       12 Oct 15 14:10 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 14948984 Oct 15 14:10 redis-server

如果没有指定安装目录,则会直接安装到/usr/local/bin/

[root@52fa920152b6 redis-7.0.5]# ls -l /usr/local/bin/ | grep redis
-rwxr-xr-x 1 root root  5228768 Oct 13 20:15 redis-benchmark
lrwxrwxrwx 1 root root       12 Oct 13 20:15 redis-check-aof -> redis-server
lrwxrwxrwx 1 root root       12 Oct 13 20:15 redis-check-rdb -> redis-server
-rwxr-xr-x 1 root root  5445536 Oct 13 20:15 redis-cli
lrwxrwxrwx 1 root root       12 Oct 13 20:15 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 11482712 Oct 13 20:15 redis-server

疑问

  • 疑问一:使用指定安装目录的安装方式,为什么redis目录下只有一个bin,没有etc?因为etc一般是放配置文件用的。没错,这也正是redis这个make install的缺陷,其实你解压源码后,源码文件夹下就已经有一个redis.conf配置文件了,只不过安装的时候是不会把它安装过去的,你需要自己在redis目录下建一个etc文件夹并把配置文件复制进去;
  • 疑问二:使用了USE_SYSTEMD=yes选项,但是好像也没什么作用呀,也没有redis.service文件生成?是的,github提issue问过,有个redis源码贡献者回答如下,反正就是说不会生成redis.servcie文件
    > This flag only controls compilation: it enables systemd support logic and linking against libsystemd.
    > 意思是这个选项只是用于启用了systemd相关的支持逻辑以及针对libsystemd的链接。

配置systemd启动方式

前面疑问里说过,使用USE_SYSTEMD=yes并不会自动生成redis.service,所以我们必须自己创建这个文件,这个文件从哪儿来呢?很简单,你用包管理器安装一个redis,它会自动有一个redis.service文件在/etc/systemd/system/下。

以下是我在debian 11中用apt install redis安装后,在/etc/systemd/system/下找到的redis.service文件中的内容,如果你源码安装指定了位置,那改改ExecStart中的路径就行了

[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=notify
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf --supervised systemd --daemonize no
PIDFile=/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=2755

UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWritePaths=-/var/lib/redis
ReadWritePaths=-/var/log/redis
ReadWritePaths=-/var/run/redis

NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".
ProtectSystem=true
ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target
Alias=redis.service

这样的话就可以用systemctl start redis的方式来启动了。

配置非sysemd启动方式

如果没有用USE_SYSTEMD=yes,可以运行redis源码目录下的utils/install_server.sh来安装,它会自动安装一个SysV启动脚本到/etc/init.d/中,它做的事情如下

[root@52fa920152b6 utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379]
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
打赏

订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

CentOS 7.9 / Debian 11 源码编译redis 7.0.5