数据库redis

10. Redis 基础

2021-01-21  本文已影响0人  随便写写咯

1. Redis介绍

1.1 Redis简介

Redis 是一个开源的, 遵循BSD协议的, 基于内存的而且目前比较流行的键值数据库(Key-Value Database), 是一个非关系型数据库, Redis提供将内存通过网络远程共享的一种服务, 提供类似功能的还有memchaed, 但相比memcached, Redis还提供了易扩展, 高性能, 具备数据持久性等功能.

1.2 Redis vs Memcached

1.3 Redis单线程工作机制

Redis6版本以前, 由一个单线程处理用户请求, 辅助线程处理数据备份等其他操作.

#由此可见Redis是多线程, l 标记是以多线程工作
redis       1554  0.2  0.5  59152 11024 ?        Ssl  21:06   0:10 /usr/bin/redis-server 0.0.0.0:6379
#通过pstree -p 也可以证明
           ├─redis-server(1554)─┬─{redis-server}(1555)
           │                    ├─{redis-server}(1556)
           │                    └─{redis-server}(1557)
#或者查看/proc/PID/status文件
[22:17:53 root@CentOS-8 ~]#cat /proc/1554/status
Threads:    4

单线程处理优势, 无需考虑加锁的问题, 因为请求是串行处理的, 无需考虑数据冲突

单线程如何实现高效率?

1.4 Redis应用场景

Session共享: 常用于Web集群中的Tomcat或者PHP中多Web服务器Session共享
消息列队: ELK的日志缓存, 部分业务的订阅发布系统
计数器: 访问排行榜, 商品浏览数等和次数有关的数值统计场景
缓存: 数据查询, 电商网站商品信息, 新闻内容

举例: Redis --> MySQL
首次访问时, 先在Redis检查缓存, 如果没有, 则查询后端MySQL, 之后MySQL把数据返回给Redis, 缓存到本地, 并且返还给客户
再次访问, 就可以直接从Redis拿数据

微博/微信社交: 共同好友, 点赞评论
地理位置: 基于地理位置(GEO), 外卖, 附近的人等功能

2. Redis安装部署

2.1. Yum安装

CentOS 7: 来自 Epel 源

CentOS 8: 来自 AppStream 源

安装

CentOS-8
yum -y install redis 

查看包文件

rpm -ql redis
/etc/redis.conf #主配置文件
/usr/lib/systemd/system/redis-sentinel.service #哨兵服务service文件
/usr/lib/systemd/system/redis.service #service文件
/usr/bin/redis-cli #客户端命令
/usr/bin/redis-server #服务端命令, redis主程序

默认监听127.0.0.1:6379

[03:13:30 root@CentOS-8 ~]#ss -ntl
State                   Recv-Q                  Send-Q                                    Local Address:Port                                     Peer Address:Port                  
LISTEN                  0                       128                                           127.0.0.1:6379                                          0.0.0.0:*   

2.2 源码编译

编译安装Redis-5.0.9版本, CentOS-7

  1. 下载源码包
redis-5.0.9.tar.gz
  1. 解压
tar xf redis-5.0.9.tar.gz
  1. 安装依赖包
yum -y install gcc jemalloc-devel
  1. 安装: 由于Redis源码包提供了Makefile文件, 因此无需./configure编译
cd redis-5.0.9/
make PREFIX=/apps/redis install  #指定Redis安装目录
  1. 配置环境变量, 也可以创建软连接
echo 'PATH=/apps/redis/bin:$PATH' > /etc/profile.d/redis.sh
. /etc/profile.d/redis.sh
ln -s /apps/redis/bin/* /usr/bin
  1. 查看安装目录的结构
[03:26:41 root@redis ~]#tree /apps/redis/
/apps/redis/
└── bin
    ├── redis-benchmark
    ├── redis-check-aof
    ├── redis-check-rdb
    ├── redis-cli
    ├── redis-sentinel -> redis-server
    └── redis-server

1 directory, 6 files
  1. 准备相关目录和配置文件
mkdir /apps/redis/{etc,log,data,run}
cd redis-5.0.9/
cp redis.conf /apps/redis/etc #源码包带有配置文件模板, 拷贝到配置文件存放路径即可, 后续要在service文件指定路径. 
  1. 创建redis账号, 设置目录权限
useradd -r -s /sbin/nologin redis
chown redis.redis /apps/redis -R
  1. 前台启动Redis, 测试远程连接
redis-server
LISTEN      0      128                                                   *:6379                                                              *:*  
#连接成功, 只是Redis默认开启了保护模式

[03:31:50 root@CentOS-8 ~]#redis-cli -h 10.0.0.237  #可以通过 -p 指定端口, -a 指定密码, 如果设置了密码的话
10.0.0.237:6379> info
(error) DENIED Redis is running in protected mode because protected mode is enabled
  1. 修改bind ip
bind 0.0.0.0 #只要修改bind ip, 即可符合保护模式要求, 也就是指定bind ip或者设置登录密码都可以满足保护模式要求. 
  1. 前台启动redis, 指定配置文件路径
redis-server /apps/redis/etc/redis.conf 
  1. 远程登录测试
[03:33:53 root@CentOS-8 ~]#redis-cli -h 10.0.0.237
10.0.0.237:6379> ping
PONG
10.0.0.237:6379>
  1. 设置以后台方式运行redis
#修改配置文件
daemonize yes
  1. 启动服务测试
[03:34:34 root@redis ~]#redis-server /apps/redis/etc/redis.conf 
5393:C 20 Jan 2021 03:34:38.506 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
5393:C 20 Jan 2021 03:34:38.506 # Redis version=5.0.9, bits=64, commit=00000000, modified=0, pid=5393, just started
5393:C 20 Jan 2021 03:34:38.506 # Configuration loaded

[03:34:38 root@redis ~]#ss -ntl
State       Recv-Q Send-Q                                    Local Address:Port                                                   Peer Address:Port                            
LISTEN      0      128                                                   *:6379                                                              *:* 
  1. 准备service文件
vim /lib/systemd/system/redis.service
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis #指定用redis用户身份启动
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now redis
  1. 远程测试登录
[03:33:59 root@CentOS-8 ~]#redis-cli -h 10.0.0.237
10.0.0.237:6379> ping
PONG
10.0.0.237:6379> 

2.3 保护模式配置

修改监听ip地址

找到bind 127.0.0.1一行, 尝试直接注释掉, 并重启服务

#bind 127.0.0.1
systemctl restart redis
[13:12:01 root@@redis /etc]#ss -ntl
State               Recv-Q              Send-Q                           Local Address:Port                           Peer Address:Port             
LISTEN              0                   128                                    0.0.0.0:6379   #所有ip地址都可以通过6379端口访问redis                             0.0.0.0:* 

Redis保护模式

由于Redis默认会开启保护模式, 因此如果直接注释掉配置文件中的bind ip绑定, 虽然服务可以重启成功, 并且监听在0.0.0.0:6379, 但是Redis仍然无法远程连接的. 必须指定bind ip或者设置登录密码, 二选一.

[12:18:38 root@CentOS-8 ~]#telnet 10.0.0.237 6379
Trying 10.0.0.237...
Connected to 10.0.0.237.
Escape character is '^]'.
-DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients.

保护模式限定了Redis必须明确指定bind ip或者设置登录口令, 否则只能本地通过127.0.0.1登录

关闭保护模式: 修改配置文件即可

protected-mode no

再次测试远程telnet连接, 成功

[03:45:17 root@CentOS-8 ~]#telnet 10.0.0.237 6379
Trying 10.0.0.237...
Connected to 10.0.0.237.
Escape character is '^]'.

开启保护模式, 同时指定bind ip为 0.0.0.0

protected-mode yes
bind 0.0.0.0
[03:46:24 root@redis ~]#systemctl restart redis
[03:46:31 root@redis ~]#ss -ntl
State       Recv-Q Send-Q                                                                     Local Address:Port                                                                                    Peer Address:Port              
LISTEN      0      128                                                                                    *:6379                                                                                               *:*   
[03:46:05 root@CentOS-8 ~]#telnet 10.0.0.237 6379
Trying 10.0.0.237...
Connected to 10.0.0.237.
Escape character is '^]'.

2.4 搭建单机多实例Redis

由于Redis是单进程工作模式, 因为可以通过单机多实例来充分发挥硬件资源, 一般用于测试环境

多实例需要解决的问题: 端口冲突

多实例需要的准备工作;

范例: 搭建多实例Redis

实例1: 此前编译安装的Redis: 6379
实例2: 6380
实例3: 6381

  1. 准备配置文件

利用编译安装的配置文件作为模板

cp redis.conf redis_6380.conf
cp redis.conf redis_6381.conf
mv redis.conf redis_6379.conf #将编译安装的配置文件也修改成带端口号的后缀, 为了便于区分

修改每个配置文件

6379:

port 6379
pidfile /apps/redis/run/redis_6379.pid
dbfilename dump_6379.rdb  #数据库备份文件,默认情况下, 会在启动redis服务的目录自动生成
logfile "/apps/redis/log/redis_6379.log"
dir /apps/redis/data
appendfilename "appendonly_6379.aof"

6380:

port 6380
pidfile /apps/redis/run/redis_6380.pid
dbfilename dump_6380.rdb  #数据库备份文件, 备份时生成
logfile "/apps/redis/log/redis_6380.log"
dir /apps/redis/data
appendfilename "appendonly_6380.aof"

6381:

port 6381
pidfile /apps/redis/run/redis_6381.pid
dbfilename dump_6381.rdb  #数据库备份文件, 备份时生成
logfile "/apps/redis/log/redis_6381.log"
dir /apps/redis/data
appendfilename "appendonly_6381.aof"

修改完配置文件后, 别忘了给redis权限

chown redis.redis /apps/redis/etc/*

用redis-server启动服务, 检查监听端口

redis-server redis_6379.conf
redis-server redis_6380.conf
redis-server redis_6381.conf
LISTEN      0      128                                                   *:6379                                                              *:*                  
LISTEN      0      128                                                   *:6380                                                              *:*                  
LISTEN      0      128                                                   *:6381                                                              *:* 
  1. 准备service文件

利用编译安装的service文件作为模板

cp redis.service redis_6380.service 
cp redis.service redis_6381.service
mv redis.service redis_6379.service
ExecStart=/apps/redis//bin/redis-server /apps/redis/etc/redis_6379.conf --supervised systemd
ExecStart=/apps/redis//bin/redis-server /apps/redis/etc/redis_6380.conf --supervised systemd
ExecStart=/apps/redis//bin/redis-server /apps/redis/etc/redis_6381.conf --supervised systemd
[04:16:53 root@redis /lib/systemd/system]#ll | grep redis
-rw-r--r--  1 root root  337 Jan 20 04:16 redis_6380.service
-rw-r--r--  1 root root  337 Jan 20 04:16 redis_6381.service
-rw-r--r--  1 root root  337 Jan 20 04:16 redis_6379.service

启动多实例之前, 再次确保/apps/redis整个目录的权限为redis

chown -R redis.redis /apps/redis

重新加载daemon,启动服务, 测试

systemctl daemon-reload
systemctl enable --now redis_6380.service
systemctl enable --now redis_6381.service
LISTEN      0      128                                                   *:6379                                                              *:*                  
LISTEN      0      128                                                   *:6380                                                              *:*                  
LISTEN      0      128                                                   *:6381                                                              *:*  

登录测试

[03:47:28 root@CentOS-8 ~]#redis-cli -h 10.0.0.237 -p 6379
10.0.0.237:6379> ping
PONG
10.0.0.237:6379> exit
[04:18:55 root@CentOS-8 ~]#redis-cli -h 10.0.0.237 -p 6380
10.0.0.237:6380> ping
PONG
10.0.0.237:6380> exit
[04:19:04 root@CentOS-8 ~]#redis-cli -h 10.0.0.237 -p 6381
10.0.0.237:6381> ping
PONG
10.0.0.237:6381> exit

2.5 解决启动时的三个警告提示

默认情况, redis配置文件的参数和内核参数不匹配, 因此还需要修改配置参数, 否则启动时会有警告, 但是并不影响使用

2.5.1 tcp-backlog

31628:M 16 Oct 2020 16:14:54.280 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

backlog参数控制的是三次握手的时候server端收到的client ack确认号之后的队列值, 即全连接队列

因此, 配置文件中的tcp-backlog参数值(默认511)需要小于内核参数值/proc/sys/net/core/somaxconn(默认128)

范例:

#vim /etc/sysctl.conf
net.core.somaxconn = 1024
#sysctl -p
队列溢出是查看现有连接数是否大于backlog,如果大于就丢弃,并overflow数+1,backlog数是有配置的backlog和系统的somaxconn决定的,backlog值取min(somaxconn,backlog)。

redis的配置文件有tcp-backlog,默认的是511

tcp服务里面默认有两个队列,一个是tcp-backlog,用于存放未连接队列,另外一个是somaxconn,用于存放已连接队列。

在完成tcp三次握手之前,首先进入未连接队列,完成tcp三次握手之后正式建立连接,进入已连接队列。因为redis是单进程的,如果主进程出现慢查询的话,会导致已连接队列堆满,并且新accept的连接不能被处理,不能进入到已连接队列,也导致未连接队列堆满,在服务器看到处于未连接队列中的连接状态为SYN_RECV。 新进来的客户端连接将会一直处于SYN_SENT状态等待服务器的ACK应答,最终导致连接超时。

关于TCP三次握手

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据.

处理方法:将配置tcp-backlog设和系统somaxconn设置成8192

2.5.2 vm.overcommit_memory

31628:M 16 Oct 2020 16:14:54.281 # 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.

内核参数说明:

0 - Heuristic overcommit Handling, 默认值, 允许overcommit, 但是明目张胆的overcommit会被拒绝, 比如malloc一次性申请的内存大小超过了系统总内存, 这时就会被拒绝. Heuristic的意思是试探式的, 内核利用某种算法猜测内存申请是否合理, 如果认为不合理就拒绝overcommit
1 - Always overcommit, 允许overcommit, 对内存申请都允许. 内核执行无内存过量使用的处理. 使用这个设置会增大内存超载的可能性, 但也可以增强大量使用内存任务的性能. Redis需要调成1.
2 - Don't overcommit, 禁止overcommit. 内存拒绝等于或者大于总可用swap空间大小以及overcommit_ratio指定的物理RAM比例的内存请求. 如果希望减小内存过度使用的风险, 这个参数是最好的

范例:

#vim /etc/sysctl.conf
vm.overcommit_memory = 1
#sysctl -p

2.5.3 transparent hugepage

31628:M 16 Oct 2020 16:14:54.281 # 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.
警告: 您在内核中启用了透明大页面(THP, 不同于一般内存页的4k为2M)支持. 这将在Redis中造成延迟和内存使用问题. 要解决问题, 请以root用户身份运行命令"echo never > /sys/kernel/mm/transparent_hugepage/enabled", 并将其添加到您的/etc/rc.local中, 以便在服务器重启后保留设置. 禁用THP后, 必须重新启动Redis. 

默认值: [always] madvise never, 需要修改成never

echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
/etc/rc.d/rc.local #执行启动脚本

重启服务, 查看日志, 没有报警

31987:M 16 Oct 2020 17:17:51.140 # Server initialized
31987:M 16 Oct 2020 17:17:51.140 * DB loaded from disk: 0.000 seconds
31987:M 16 Oct 2020 17:17:51.141 * Ready to accept connections

3. Redis配置文件基本参数

  1. bind IP

建议写 bind 0.0.0.0, 这样即使服务器IP改了, 也不需要修改配置文件. 如果需要绑定特定IP, 那么该IP必须是本机有的IP地址.

如果注释掉bind IP, 那么需要取消保护模式, 否则远程连接会失败. 只能本地连接. 或者不取消保护模式, 设置redis密码也可以实现远程连接.

  1. tcp-backlog: backlog参数控制的是三次握手的时候server端收到的client ack确认号之后的队列值, 即全连接队列

因此, 配置文件中的tcp-backlog参数值(默认511)需要小于内核参数值/proc/sys/net/core/somaxconn(默认128)

范例: 可以把内核参数调大

#vim /etc/sysctl.conf
net.core.somaxconn = 1024
#sysctl -p
  1. timeout 0: 客户端和Redis服务器的连接超时时间, 默认是0, 表示永不超时

  2. tcp-keepalive 300: tcp会话保持时间, 默认300s

  3. daemonize no: 默认为no, 即直接运行redis-server程序时不作为守护进程运行, 而是以前台方式运行, 如果想在后台运行, 需改成yes, 当redis作为守护进程运行的时候, 它会写一个pid到默认的/var/run/redis.pid文件, 或者指定的pid存放路径

范例: 修改daemonize 为 yes, 用redis-server启动服务时, 以后台运行

daemonize yes

[21:00:03 root@redis ~]#redis-server /etc/redis.conf  #以后台运行redis, 需要指定配置文件路径, 否则redis-server程序不会调用redis配置文件
[21:00:09 root@redis ~]#ss -ntl
State                     Recv-Q                    Send-Q                                        Local Address:Port                                         Peer Address:Port                    
LISTEN                    0                         128                                                 0.0.0.0:22                                                0.0.0.0:*                       
LISTEN                    0                         128                                                 0.0.0.0:6379                                              0.0.0.0:* 

利用redis-server启动的redis, 可以使用redis-cli shutdown来关闭redis

  1. loglevel notice: 记录日志的级别, 只记录notice以上的日志

  2. logfile "/PATH/redis.log": 日志路径, 范例: logfile "/apps/redis/log/redis_6379.log"

  3. pidfile /var/run/redis_6739.pid: pid文件路径, 可以修改. 但是需要确保redis用户对存放pid文件的目录有写权限, 否则无法创建pid文件.

注意: 用yum安装的redis, 是以redis来运行程序的, 而/var/run的所有者是root, 因此有可能造成启动redis时, pid文件无法生成, 因此可以考虑将pid文件移到一个单独的文件夹, 给redis用户添加相应权限.

  1. databases 16: 设置数据库数量, 默认: 0-15, 共16个库. redis无法自己创建数据库, 而且数据库的名字是定义好的数字0-15. 数据库的数量可以自定义, 但是名字都是从0开始的数字.

范例: 连接到数据库, 选择数据库, 查看信息

redis-cli - select - get

[21:15:24 root@redis ~]#redis-cli
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get keys
(nil)

插入数据时, 如果没有指定数据库名字, 默认插入到0数据库

注意: keys *在生产中禁止使用, 可以查看当前数据库中的所有key, 会造成redis阻塞, 导致其他业务无法访问, 甚至出现宕机事件

redis不像mysql, 有强大的授权机制, 而它只有一个redis账号, 连到数据库就可以做所有的操作, 因此, redis的账户一定要保护好.

  1. maxclients 10000: 默认1万, Redis最大连接客户端数量, 根据生产环境和服务器性能决定

  2. maxmemory <bytes>: Redis使用的最大内存, 单位为bytes字节, 0为不限制, 建议设为物理内存一半, 因为这里的内存,指的是Redis存放的数据能使用的最大内存, 而Redis本身运行, 也需要消耗内存, 生产中如果不限制最大内存使用, 可能会导致OOM事件, 一旦发生, 那么系统可能会将Redis进程直接杀死. 注意: Redis程序本身使用的内存空间和Redis缓冲区使用的内存空间是不计算在maxmemory中的.

  3. requirepass PASSWORD: Redis默认没有密码, 生产环境一定要设置复杂密码. 如果Redis没有设置密码, 并且运行时是以root身份运行, 很有可能遭到黑客攻击. 另外redis是没有用户概念的, 只要有密码就可以连接到redis

注意: 修改密码后, redis-cli连接redis是不会报错的, 但是如果想要执行命令就会提示需要认证. 这时可以使用auth PASSWD, 进行认证, 或者连接redis的时候就是用-a来指定密码, --no-auth-warning取消-a输入密码时的告警提示

4. 慢查询

慢查询说明:

  1. 慢查询发生在redis执行命令阶段
  2. 客户端超时,(比如网络延迟), 不一定是慢查询, 但是慢查询是客户端超时的一个可能因素

根据配置文件定义:

#The following time is expressed in microseconds, so 1000000 is equivalent to one second.
slowlog-log-slower-than 10000: 以微妙为单位的慢查询日志记录, 为负数会禁用慢查询, 为0会记录每个操作命令, 默认为10ms, 10毫妙, 一般一条命令执行都在微妙级. 
slowlog-max-len 128: 默认128, 最多纪录多少条慢日志的保存队列长度, 达到此长度后, 记录新命令会将最旧的命令从命令队列删除, 依次滚动删除, 即先进先出, 队里固定长度, 默认128, 值偏小, 生产建议为1000以上. 
slowlog LEN #查看慢日志的记录条数
slowlog GET [n] #查看慢日志的前n条记录
slowlog RESET #清空慢日志, redis是基于内存的, 可以清空, 并没有磁盘文件保存慢查询日志
上一篇下一篇

猜你喜欢

热点阅读