Redis

作者: 运维开发_西瓜甜 | 来源:发表于2019-02-10 22:23 被阅读36次

    一、安装

    1. 官网下载源码

    image.png

    2. 安装依赖包

    yum install gcc tcl   
    

    3. 下载源码包

    wget http://download.redis.io/releases/redis-4.0.10.tar.gz
    

    3. 解压安装

    tar -xf redis-4.0.10.tar.gz
    cd redis-4.0.10
    make && make install
    
    1. 配置 redis
    mkdir /etc/redis
    cd redis-4.0.10/
    cp redis.conf /etc/redis/6379.conf
    cp utils/redis_init_script /etc/init.d/redis
    chmod 755 /etc/init.d/redis
    

    编辑配置文件 /etc/redis/6379.conf

    daemonize yes   # 守护进程的方式启动服务
    

    守护进程的方式启动服务时,即使执行启动服务命令的终端关闭,服务仍然可以在后台运行。

    centos7 正统配置 systemd 管理 redis 服务

    1. /lib/systemd/system目录下创建一个脚本文件redis.service,里面的内容如下:
    [Unit]
    Description=Redis
    After=network.target
    
    [Service]
    Type=simple
    EnvironmentFile=-/etc/redis/6379.conf
    ExecStart=/usr/local/bin/redis-server  --daemonize no
    ExecStop=/usr/local/bin/redis-cli shutdown
    
    [Install]
    WantedBy=multi-user.target
    

    [Unit] 表示这是基础信息配置块
    Description 是描述
    After 开启自启动时候的顺序, 指定的服务必须先于次此服务启动,一般是网络服务启动后启动
    [Service] 表示这里是服务信息配置块
    Type 指定启动服务的类型, simple 是默认的方式
    EnvironmentFile 指定服务器的时用到的配置文件
    ExecStart 是启动服务的命令
    ExecStop 是停止服务的指令
    [Install] 表示这是是安装信息配置块
    WantedBy 是以哪种方式启动:multi-user.target表明当系统以多用户方式(默认的运行级别)启动时,这个服务需要被自动运行。

    关于 server 文件的详细参数介绍参考这里

    1. 使用 systemd 操作

    刷新配置,让 systemd 识别刚刚添加的 redis 服务

    systemctl daemon-reload
    

    启动服务

    systemctl start redis
    

    设置监听地址

    shell> vi /etc/redis/63779.conf
    # bind 127.0.0.1 192.168.1.10             
    

    bind 参数若都注释掉,则会监听服务器上的所有 ip
    可以指定一个或者多个,打开注释。
    注意此配置项可能在 71 行左右。默认是 bind 127.0.0.1

    检查并测试

    检查默认端口 6379 是否监听
    ``

    image.png
    shell> redis-cli
    127.0.0.1:6379> info
    # Server
    redis_version:4.0.10
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:cfb22f7d67db356d
    ... 略 ...
    

    手动使用命令指定配置文件启动服务

    /usr/local/bin/redis-server /etc/redis/6379.conf
    

    客户端指定端口访问

    redis-cli -p 6379
    

    手动停止服务

    redis-cli -p 6379 shutdown
    

    通用命令

    二、数据类型

    1. 数据类型的基本介绍

    image.png

    2. 数据类型的基本操作

    a.String

    set

    127.0.0.1:6379> help set
    SET key value [EX seconds] [PX milliseconds] [NX|XX]
    

    在 Redis 中设置值,默认,不存在则创建,存在则修改
    参数:
    ex,过期时间(秒)
    px,过期时间(毫秒)
    nx,假如设置为True,则只有 name 不存在时,当前 set 操作才执行
    xx,假如设置为True,则只有 name 存在时,当前 set 操作才执行

    Example

    127.0.0.1:6379> set name shark EX 10
    OK
    127.0.0.1:6379> get name
    "shark"
    

    setnx

    127.0.0.1:6379> help setnx
      SETNX key value
    

    设置值,只有name 不存在时,执行设置操作(添加)

    Example

    127.0.0.1:6379> setnx age 10
    (integer) 1
    127.0.0.1:6379> get age
    "10"
    127.0.0.1:6379> setnx age 20
    (integer) 0
    127.0.0.1:6379> get age
    "10"
    127.0.0.1:6379>
    

    setex

    127.0.0.1:6379> help setex
      SETEX key seconds value
    

    设置 key 和 value,并且指的过期时间(单位: 秒)

    Example

    127.0.0.1:6379> setex name 5 shark
    OK
    

    get

    获取一个 key 的 value

    127.0.0.1:6379> get name
    "shark"
    

    ttl

    查看一个 key 的过期时间

    127.0.0.1:6379> ttl age
    (integer) -1
    
    • -1 永不过期
    • -2 已经过期

    expire

    设置一个 key 的过期时间(单位: 秒)

    127.0.0.1:6379> EXPIRE age 10
    (integer) 1
    127.0.0.1:6379> ttl age
    (integer) 7
    

    persist key

    移除 key 的过期时间

    mset

    一次添加多个值

    127.0.0.1:6379> mset name shark age 10
    OK
    

    mget

    一次获取多个 key 的值

    127.0.0.1:6379> MGET name age
    1) "shark"
    2) "10
    

    inrc

    对一个 key 的值自增 1

    127.0.0.1:6379> incr age
    (integer) 11
    

    decr

    对一个 key 的值自减 1

    127.0.0.1:6379> DECR age
    (integer) 10
    

    append

    向一个 key 的值后面追加内容

    127.0.0.1:6379> get n
    "10"
    127.0.0.1:6379> APPEND n 10
    (integer) 4
    127.0.0.1:6379> get n
    "1010"
    

    getrange

    127.0.0.1:6379> GETRANGE n 0 -1
    "1010"
    

    del

    删除 一个或者多个 key

    127.0.0.1:6379> del name age
    (integer) 2
    

    EXISTS

    判断一个 key 是否存在, 返回 1 表示存在, 0 表示不存在

    
    

    TYPE

    返回key存储的类型,如果不存在则返回none

    type key
    

    keys

    通过通配符来获取匹配到的 key
    一般不在生产环境中使用此命令

    • * 匹配所有
    • ? 匹配任意一个
    127.0.0.1:6379> keys *
    1) "num"
    2) "age"
    3) "n"
    127.0.0.1:6379> keys n*
    1) "num"
    2) "n"
    127.0.0.1:6379> keys a[f-g]
    (empty list or set)
    127.0.0.1:6379> keys a[e-g]?
    1) "age"
    

    scan

    dbsize

    返回数据库种 key 的总数

    dbsize
    

    EXPIRE

    设置key的过期时间,如果key不存在则返回0,否则返回1.如果key已经存在过期时间则再设置会覆盖之前的过期时间

    b. List 操作

    lpush

    向列表左端添加元素,values是按左到右依次插入的,返回值为列表中元素个数,列表元素可以重复

    最后加入到元素,在列表的第一位

    127.0.0.1:6379> LPUSH list a b c
    (integer) 3
    127.0.0.1:6379> LPUSH list a b c
    (integer) 6
    

    rpush

    向列表右端依次的添加元素,最后加入的元素在列表的最后位置

    127.0.0.1:6379> RPUSH list d e f
    (integer) 9
    

    LINDEX

    通过元素在列表中的位置获取到这个元素,位置称为索引号/下标,

    位置支持正整数和负整数

    列表中元素的位置中,第一位是 0,最后一位是列表总长度减 1 或者是 -1

    千锋云计算
    127.0.0.1:6379> LINDEX list 0
    "c"
    

    LRANGE

    获取列表表一个区间的值

    127.0.0.1:6379> LRANGE list 0 2
    1) "c"
    2) "b"
    3) "a"
    

    LPUSHX

    向列表左端添加元素,只有key存在时才可以添加

    127.0.0.1:6379> EXISTS list1 
    (integer) 0
    127.0.0.1:6379> LPUSHX list1 a
    (integer) 0
    127.0.0.1:6379> LPUSHX list g
    (integer) 10
    

    RPUSHX

    向列表右端添加元素,其他与LPUSHX相同

    LPOP

    将左端列表元素弹出,会将其从列表中删除,如果key不存在则返回(nil)

    127.0.0.1:6379> LPOP list
    "g"
    127.0.0.1:6379> LPOP list
    "c"
    

    RPOP

    将右端列表元素弹出,其他同LPOP

    LLEN

    返回列表的长度,如果列表不存在则返回0

    127.0.0.1:6379> LLEN list
    (integer) 8
    127.0.0.1:6379> LLEN list1
    (integer) 0
    

    LREM

    lrem  key count value
    

    删除列表中指定的值,返回值为删除的元素的个数,count值有以下几种:

    • count > 0: 从列表的头开始,向尾部搜索,移除与value相等的元素,移除count个
    • count < 0: 从列表尾部开始,向头部搜索,移除与value相等的元素,移除-count个
    • count == 0: 移除列表中所有与value相等的

    c. Hash

    image.png

    HSET key field value

    将哈希表key中的域 (field) 设置成指定的value,如果key不存在则新建一个hash表,如果域不存在则新建域,如果域已存在则更新域,如果field不存在返回1表示新建,存在则返回0表示更新

    127.0.0.1:6379> HSET userinfo username 'shark'
    (integer) 1
    127.0.0.1:6379> HSET userinfo userpsw '123456'
    (integer) 1
    127.0.0.1:6379> HSET userinfo userpsw '654321'
    (integer) 0
    

    HGET key field

    获取哈希表key中的域field的值,如果key或者field不存在则返回(nil)

    127.0.0.1:6379> HGET userinfo2 username
    (nil)
    127.0.0.1:6379> HGET userinfo username
    "stronger"
    127.0.0.1:6379> HGET userinfo email
    (nil)
    

    HSETNX key field value

    将哈希表中的域field设置成指定的值,只有field不存在时才可以成功,如果field存在操作无效,返回0

    127.0.0.1:6379> HGET userinfo username
    "stronger"
    127.0.0.1:6379> HSETNX userinfo username 'fish'
    (integer) 0
    127.0.0.1:6379> HGET userinfo username
    "stronger"
    

    HMSET key field vale [field value]

    同时将多个field-value设定到hash表中,如果field已存在值则会被覆盖掉

    127.0.0.1:6379> HMSET userinfo email 'yangdm@gmail.com' sex 'male'
    OK
    

    HMGET key field [field]

    同时获得key存储的hansh表中多个field的值,如果不存在则返回(nil)

    127.0.0.1:6379> HMGET userinfo email sex age
    1) "yangdm@gmail.com"
    2) "male"
    3) (nil)
    

    HGETALL key

    返回key存储的所有field及value

    127.0.0.1:6379> HGETALL userinfo
    1) "username"
    2) "stronger"
    3) "userpsw"
    4) "654321"
    5) "email"
    6) "yangdm@gmail.com"
    7) "sex"
    8) "male"
    127.0.0.1:6379> HGETALL userinfo2
    (empty list or set)
    

    HKEYS key

    返回hash的所有域

    127.0.0.1:6379> HKEYS userinfo
    1) "username"
    2) "userpsw"
    3) "email"
    4) "sex"
    

    HVALS key

    返回hash的所有域的值

    127.0.0.1:6379> HVALS userinfo
    1) "stronger"
    2) "654321"
    3) "yangdm@gmail.com"
    4) "male"
    

    HEXISTS key field

    检测key中存储的hash中field是否存在,存在返回1,否则返回0

    127.0.0.1:6379> HEXISTS userinfo username
    (integer) 1
    127.0.0.1:6379> HEXISTS userinfo age
    (integer) 0
    

    HLEN key

    返回key中存储的hash表中field的数量

    127.0.0.1:6379> HLEN userinfo
    (integer) 4
    

    HINCRBY key field increment

    给key中存储的hash表field增加increment,如果此field不存在,则创建值为0的field,然后增加increment。操作的字段必须是整数,参照字符串处理

    127.0.0.1:6379> HINCRBY userinfo age 10
    (integer) 10
    

    HINCRBYFLOAT key field increment

    给key中存储的hash表field增加increment,可以为浮点数,参照字符串处理

    127.0.0.1:6379> HINCRBYFLOAT userinfo salary 150.56
    "150.56"
    

    HDEL key field [field]

    删除key中存储的hash表的field,可以删除一个或多个,成功返回被移除域的数量

    127.0.0.1:6379> HKEYS userinfo
    1) "username"
    2) "userpsw"
    3) "email"
    4) "sex"
    5) "age"
    6) "salary"
    127.0.0.1:6379> HDEL userinfo salary age
    (integer) 2
    127.0.0.1:6379> HKEYS userinfo
    1) "username"
    2) "userpsw"
    3) "email"
    4) "sex"
    
    Set

    Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

    Redis 中集合是通过哈希表实现的。

    // 向集合中添加一个或者多个元素
    SADD key member [member ...]
    
    // 获取集合中元素的个数
    SCARD key
    
    // 返回所有集合的差集,就是存在于第一个集合中,且不存在于其他集合中的成员
    SDIFF key [key ...]
     
    // 交集,就是所有集合共有的元素
    SINTER key [key ...]
     
    // 并集, 就是所有集合的元素合并在一起,并去重
    SUNION key [key ...]
     
    // 返回一个集合中的所有成员
    SMEMBERS key
    

    Example

    127.0.0.1:6379> sadd s1 a b
    (integer) 2
    127.0.0.1:6379> sadd s2 a b c d
    (integer) 4
    127.0.0.1:6379> sadd s3 c d e f
    (integer) 4
    
    127.0.0.1:6379> sdiff s2 s1
    1) "d"
    2) "c"
    
    127.0.0.1:6379> SINTER s1 s2
    1) "b"
    2) "a"
    
    127.0.0.1:6379> SUNION s1 s2 s3
    1) "b"
    2) "c"
    3) "d"
    4) "f"
    5) "a"
    6) "e"
    
    127.0.0.1:6379> SMEMBERS s1
    1) "b"
    2) "a"
    
    Sort Set 操作

    有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

    // 向有序集合添加一个或多个成员,或者更新已存在成员的分数
    ZADD key score1 member1 [score2 member2]
    
    // 获取有序集合的元素个数
    ZCARD key 
    

    三、Redis 的认证连接

    // 在配置文件中找到以下配置项,大约在第 `500` 行
    shell> vi /etc/redis/6379.conf
    requirepass mypassword
    

    mypassword 就是密码了,更改好后重启服务

    使用设置好的密码认证

    // 使用 auth 进行密码认证
    127.0.0.1:6379> info
    NOAUTH Authentication required.
    127.0.0.1:6379> auth  mypassword
    OK
    127.0.0.1:6379> info
    # Server
    redis_version:4.0.10
    ...略...
    

    或者在 shell 命令行里使用 -a 选项指定密码,会出现警告信息

    [root@localhost ~]# redis-cli  -a foobared info
    Warning: Using a password with '-a' option on the command line interface may not be safe.
    # Server
    redis_version:4.0.10
    ...略...
    

    四、php-redis

    开始在 PHP 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 PHP redis 驱动,且你的机器上能正常使用 PHP。

    安装 phpredis 驱动

    点我进入下载页面,,注意选择版本

    1. 下载解压后,进入解压后的目录

    [root@s2 ~]# wget https://github.com/phpredis/phpredis/archive/4.2.0.tar.gz
    shell> 
    shell> cd php7-redis
    

    2. 安装 php

    安装 php , 只需要使用 YUM 安装 php-devel 即可。

    yum install php-devel
    

    3. 执行如下命令,生成配置工具

    在解压后的 php 目录中执行如下命令

    shell> phpize
    
    image.png

    4. 使用生成的配置工具命令 configre 进行配置并编译安装

    [root@s2 phpredis-4.2.0]# find / -name php-config
    /usr/bin/php-config
    [root@s2 phpredis-4.2.0]# ./configure --with-php-config=/usr/bin/php-config
       ... 略...
    checking whether to build shared libraries... yes
    checking whether to build static libraries... no
    configure: creating ./config.status
    config.status: creating config.h
    config.status: executing libtool commands
    
    [root@s2 phpredis-4.2.0]# make && make install
      ...略...
    Build complete.
    Don't forget to run 'make test'.
    
    Installing shared extensions:     /usr/lib64/php/modules/
    

    5. 测试安装是否成功

    [root@s2 phpredis-4.2.0]# php -v
    PHP 5.4.16 (cli) (built: Oct 30 2018 19:30:51)
    Copyright (c) 1997-2013 The PHP Group
    Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
    

    6. 在php.ini中添加 extension=redis.so

    [root@s2 phpredis-4.2.0]# find / -name php.ini
    /etc/php.ini
    [root@s2 phpredis-4.2.0]# vi /etc/php.ini
    [root@s2 phpredis-4.2.0]# tail /etc/php.ini
    ;mcrypt.modes_dir=
    
    [dba]
    ;dba.default_handler=
    
    ; Local Variables:
    ; tab-width: 4
    ; End:
    
    extension=redis.so
    [root@s2 phpredis-4.2.0]# php -m | grep redis
    redis
    
    

    7. php -m | grep redis或者phpinfo查看安装是否成功

    [root@s2 phpredis-4.2.0]# php -m | grep redis
    redis
    

    五、持久化存储

    1. 持久化存储的方式介绍

    Redis 分别提供了 RDB 和 AOF 两种持久化机制:

    • RDB 将数据库的快照(snapshot)以二进制的方式保存到磁盘中。

    • AOF 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。

    2. RDB

    a. 什么是RDB

    和 MySQL 中的 mysqldump 差不多一个道理。

    image.png

    b. 什么情况下会触发 RDB

    第一种情况,主动执行 save 命令(同步,阻塞 ,就是save 命令执行完毕后才能执行后续的其他命令操作)

    千锋云计算

    阻塞

    千锋云计算
    保存 RDB 文件的策略

    每次创建新的文件,并且替换原来旧文件(假如存在旧的文件)

    第二种情况,主动执行 ·bgsave` 命令 (异步,非阻塞 )

    image.png
    • 文件策略和 save 相同

    第三种情况,自动触发

    自动触发,就是通过对 Redis 的配置文件重相关选项的修改,当达到某个配置好的条件后,自动生成 RDB 文件
    ,其内部使用的是 bgsave 命令。

    配置文件中相关选项的默认值如下表:

    配置 seconds changes 含义
    save 900 1 每隔 900 秒检查一次,假如至少有 1 条数据改变,就生成新的 RDB 文件
    save 300 10 每隔 300 秒检查一次,假如至少有 10 条数据改变,就生成新的 RDB 文件
    save 60 10000 每隔 60 秒检查一次,假如至少有 10000 条数据改变,就生成新的 RDB 文件

    每次检查都会建立一个新的检查点,以便用于下次检查作为参考信息。

    关于 RDB 文件的配置信息

    配置内容 含义
    dbfilename dump.rdb 默认文件名
    dir ./ 默认文件保存位置
    stop-writes-on-bgsave-error yes 假如 bgsave 执行中发生错误,是否停止写入,默认是 yes , 表示假如出错,就停止写入。
    rdbcompression yes 是否使用压缩
    rdbchecksum yes 是否进行数据的校验

    建议的最佳配置

    关闭自动生成 RDB 文件
    在配置文件中注释掉如下内容

    #save 900 1
    #save 300 10
    #save 60    10000
    

    使用不同端口号进行区分,因为,有可能会在同一台主机上开启多个 Redis 实例。
    防止多个实例产生的数据信息写到一个文件中。
    dbfilename dump-${port}.rdb

    指定一个大硬盘的路径
    dir /redis_data

    假如出现错误,停止继续写入
    stop-writes-on-bgsave-error yes

    采用压缩
    rdbcompression yes

    进行校验
    rdbchecksum yes

    实验

    修改配置文件中的相关选项,使其成为如下内容中显示的值:

    dbfilename dump-6379.rdb
    dir /redis_data   # 此目录需要自己创建
    stop-writes-on-bgsave-error yes
    rdbcompression yes
    rdbchecksum yes
    

    假如你的 Redis 服务器允许客户端可以从非本机访问,应该在配置文件中,把 protected-mode 的值设置问 no

    这样的话,客户端就可以从其他主机访问 Redis 服务器了,并且不允许密码。

    重启服务后,在 Rdis 命令行客户端中输入 save 命令。

    [root@s1 ~]# redis-cli
    127.0.0.1:6379> save
    OK
    127.0.0.1:6379>
    

    该命令将在配置文件重配置的指定目录中创建 dump-6379.rdb文件。

    恢复数据时,只需要保证此文件完好,并且在配置文件中指定的目录下即可。这样 Rdis 启动时就会把此文件中的数据恢复到当前的服务器中。

    bgsave 命令基本一样,就是 bgsave 命令不会产生阻塞

    127.0.0.1:6379> bgsave
    Background saving started
    127.0.0.1:6379>
    

    查看当前服务器的数据文件目录

    127.0.0.1:6379> CONFIG GET dir
    1) "dir"
    2) "/"
    

    2. AOF

    什么是 AOF

    AOF 文件保存了 Redis 的数据库状态, 而文件里面包含的都是符合 Redis 通讯协议格式的命令文本。

    image.png

    AOF 保存的模式

    Redis 目前支持三种 AOF 保存模式,它们分别是:

    1. AOF_FSYNC_NO :不保存。
    2. AOF_FSYNC_EVERYSEC :每一秒钟保存一次。(生产中一般选这种)
    3. AOF_FSYNC_ALWAYS :每执行一个命令保存一次

    不保存

    在这种模式下, SAVE 只会在以下任意一种情况中被执行:

    Redis 被关闭
    AOF 功能被关闭
    系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
    这三种情况下的 SAVE 操作都会引起 Redis 主进程阻塞。

    每执行一个命令保存一次

    在这种模式下,每次执行完一个命令之后, WRITE 和 SAVE 都会被执行。

    另外,因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。

    AOF 三种保存模式的比较

    因为阻塞操作会让 Redis 主进程无法持续处理请求, 所以一般说来, 阻塞操作执行得越少、完成得越快, Redis 的性能就越好。

    模式 1 的保存操作只会在AOF 关闭或 Redis 关闭时执行, 或者由操作系统触发, 在一般情况下, 这种模式只需要为写入阻塞, 因此它的写入性能要比后面两种模式要高, 当然, 这种性能的提高是以降低安全性为代价的: 在这种模式下, 如果运行的中途发生停机, 那么丢失数据的数量由操作系统的缓存冲洗策略决定。

    模式 2 在性能方面要优于模式 3 , 并且在通常情况下, 这种模式最多丢失不多于 2 秒的数据, 所以它的安全性要高于模式 1 , 这是一种兼顾性能和安全性的保存方案。

    模式 3 的安全性是最高的, 但性能也是最差的, 因为服务器必须阻塞直到命令信息被写入并保存到磁盘之后, 才能继续处理请求。

    综合起来,三种 AOF 模式的操作特性可以总结如下:

    模式 WRITE 是否阻塞? SAVE 是否阻塞? 停机时丢失的数据量
    AOF_FSYNC_NO 阻塞 阻塞 操作系统最后一次对 AOF 文件触发 SAVE 操作之后的数据。
    AOF_FSYNC_EVERYSEC 阻塞 不阻塞 一般情况下不超过 2 秒钟的数据。
    AOF_FSYNC_ALWAYS 阻塞 阻塞 最多只丢失一个命令的数据。

    AOF 方式下的数据还原

    Redis 读取 AOF 文件并还原数据库的详细步骤如下:

    创建一个不带网络连接的伪客户端(fake client)。
    读取 AOF 所保存的文本,并根据内容还原出命令、命令的参数以及命令的个数。
    根据命令、命令的参数和命令的个数,使用伪客户端执行该命令。
    执行 2 和 3 ,直到 AOF 文件中的所有命令执行完毕。
    完成第 4 步之后, AOF 文件所保存的数据库就会被完整地还原出来。

    注意, 因为 Redis 的命令只能在客户端的上下文中被执行, 而 AOF 还原时所使用的命令来自于 AOF 文件, 而不是网络, 所以程序使用了一个没有网络连接的伪客户端来执行命令。

    当程序读入这个 AOF 文件时, 它首先执行 SELECT 0 命令 —— 这个 SELECT 命令是由 AOF 写入程序自动生成的, 它确保程序可以将数据还原到正确的数据库上。

    注意:
    为了避免对数据的完整性产生影响, 在服务器载入数据的过程中, 只有和数据库无关的订阅与发布功能可以正常使用, 其他命令一律返回错误。

    AOF 的重写机制

    为什么需要重写机制

    AOF 文件通过同步 Redis 服务器所执行的命令, 从而实现了数据库状态的记录, 但是, 这种同步方式会造成一个问题: 随着运行时间的流逝, AOF 文件会变得越来越大。

    1. 对同一个键的状态的多次不同操作,而最终得到一个结果。比如对列表的添加删除元素。

    2. 被频繁操作的键。比如累加

    重新机制是如何实现的

    实际上, AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取, 它针对的是数据库中键的当前值,也就是源数据从目前的内存中获取。

    考虑这样一个情况, 如果服务器对键 list 执行了以下四条命令:

    RPUSH list 1 2 3 4      // [1, 2, 3, 4]
    
    RPOP list               // [1, 2, 3]
    
    LPOP list               // [2, 3]
    
    LPUSH list 1            // [1, 2, 3]
    

    那么当前列表键 list 在数据库中的值就为 [1, 2, 3] 。

    如果我们要保存这个列表的当前状态, 并且尽量减少所使用的命令数, 那么最简单的方式不是去 AOF 文件上分析前面执行的四条命令, 而是直接读取 list 键在数据库的当前值, 然后用一条 RPUSH 1 2 3 命令来代替前面的四条命令。

    除了列表之外,集合、字符串、有序集、哈希表等键也可以用类似的方法来保存状态。

    根据键的类型, 使用适当的写入命令来重现键的当前值, 这就是 AOF 重写的实现原理。

    基本都步骤

    for  遍历所有数据库:
          if  如果数据库为空:
                 那么跳过这个数据库
          else:
                写入 SELECT 命令,用于切换数据库
                for  选择一个库后,遍历这个库的所有键
                       if 如果键带有过期时间,并且已经过期,那么跳过这个键
                       if 根据数据的类型,进行相关操作。
    

    AOF 重写的实现方式

    方式 区别
    bgrewriteaof 命令 不需要重启服务,不便于统一管理
    配置文件实现 需要重启服务,便于进行统一管理

    bgrewriteaof

    image.png

    配置文件实现

    image.png

    触发条件,必须同时满足如下条件

    image.png

    配置示例

    // 要想使用 AOF 的全部功能,需要设置为  yes
    appendonly yes
    
    // AOF 文件名,路径才看之前的 `dir` 配置项
    appendfilename "appendonly.aof"
    
    // AOF 的策略
    appendfsync everysec
    
    
    // 当执行 AOF 重新时,是否继续执行平常的 AOF 操作。
    // 这里设置文件  yes , 表示不执行
    no-appendfsync-on-rewrite no
    
    // AOF 文件容量的增长率
    auto-aof-rewrite-percentage 100
    
    // AOF 文件的最低容量,就是当前文件的大小大于此值时,就会进行重写。当然这只是其中一个条件。
    auto-aof-rewrite-min-size 64mb
    
    

    当然这些配置项是支持在线设置的

    image.png

    添加键值对数据,观察 AOF 文件

    这里在命令行中设置,以便立刻生效

    [root@s1 ~]# redis-cli
    127.0.0.1:6379> config get appendonly
    1) "appendonly"
    2) "no"
    127.0.0.1:6379> config set appendonly yes
    OK
    127.0.0.1:6379> config get appendonly
    1) "appendonly"
    2) "yes"
    

    进行简单的数据添加操作

    127.0.0.1:6379> set hello world
    OK
    127.0.0.1:6379> set hello python
    OK
    127.0.0.1:6379> set hello redis
    OK
    127.0.0.1:6379> incr nums
    (integer) 1
    127.0.0.1:6379> incr nums
    (integer) 2
    127.0.0.1:6379> incr nums
    (integer) 3
    127.0.0.1:6379> incr nums
    (integer) 4
    127.0.0.1:6379> rpush li a
    (integer) 1
    127.0.0.1:6379> rpush li b
    (integer) 2
    127.0.0.1:6379> rpush li b
    (integer) 3
    127.0.0.1:6379> rpush li c
    (integer) 4
    127.0.0.1:6379> exit
    

    查看 AOF 文件

    [root@s1 ~]# head appendonly.aof
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    SET
    $5
    hello
    

    主动触发重新

    先备份一份目前的 AOF 文件

    [root@s1 ~]# cp /appendonly.aof{,.bak}
    

    执行命令 bgrewriteaof

    127.0.0.1:6379> config get appendonly
    1) "appendonly"
    2) "yes"
    127.0.0.1:6379> BGREWRITEAOF
    Background append only file rewriting started
    

    最后对比两个文件的内容的不同之处。

    RDB 和 AOF

    区别

    image.png

    如何抉择

    从服务器开启 RDB

    始终开启 AOF

    不要使用主机的全部内存

    六、主从复制

    image.png

    Rdis 的主从复制特点

    image.png

    1. 配置主从

    实现方式同样有两种: 命令方式和配置文件方式

    命令方式

    只需要在从服务器上执行如下命令即可

    slaveof  主服务器的IP  端口号
    

    slaveof 命令是异步的,不阻塞。
    并且此时,从服务器现有的数据会先被清空,之后再同步主服务器的数据。

    停止一台从服务器的复制操作,在此台服务器上执行如下命令

    slaveof no   one
    

    配置文件的方式如下

    只需要在从服务器上配置即可

    修改配置文件
    假如主服务器 IP 是: 172.16.153.178
    端口是: 6379

    # slaveof <masterip> <masterport>
    slaveof  172.16.153.178 6379
    
    // 配置此服务器只提供读取操作
    slave-read-only yes
    

    之后重启从主机的 Redis 服务

    查看主从信息

    127.0.0.1:6379> info  replication
    

    七、主从 + Sentinel 哨兵模式

    Redis Sentinel是Redis官方的高可用性解决方案。

    Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:

    • 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。

    • 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。

    • 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

    Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

    虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。

    此种模式下,客户端要访问的 服务 IP 不是主节点,而是 sentiner 服务器的 IP。

    架构图

    image.png

    Redis Sentinel 故障转移

    image.png

    架构的扩展应用

    image.png

    1. 配置主从

    a. 快速生成主节点的配置文件

    编译全新文件 /etc/redis/redis-6389.conf, 添加如下内容

    port 6380
    daemonize yes
    pidfile /var/run/redis-6380.pid
    logfile /var/log/redis-6389.log
    dir /redis/data/
    

    b. 快速生成从节点的配置文件

    [root@s1 ~]# sed 's/6380/6381/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6381.conf
    [root@s1 ~]# sed 's/6380/6382/g' /etc/redis/redis-6380.conf > /etc/redis/redis-6382.conf
    
    
    

    查看配置文件内容,检验配置结果

    [root@s1 ~]# cat /etc/redis/redis-6381.conf
    port 6381
    daemonize yes
    pidfile /var/run/redis-6381.pid
    logfile /var/log/redis-6381.log
    dir /redis/data/
    [root@s1 ~]# cat /etc/redis/redis-6382.conf
    port 6382
    daemonize yes
    pidfile /var/run/redis-6382.pid
    logfile /var/log/redis-6382.log
    dir /redis/data/
    [root@s1 ~]#
    

    c. 配置主从关系

    [root@s1 ~]# echo "slaveof  172.16.153.178 6380" >> /etc/redis/redis-6381.conf
    [root@s1 ~]# echo "slaveof  172.16.153.178 6380" >> /etc/redis/redis-6382.conf
    [root@s1 ~]#
    
    
    

    d. 启动服务,并验证进程

    [root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6380.conf
    [root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6381.conf
    [root@s1 ~]# /usr/local/bin/redis-server /etc/redis/redis-6382.conf
    [root@s1 ~]# ps -ef |grep redis
    root       4335      1  0 19:30 ?        00:00:03 /usr/local/bin/redis-server *:6380
    root       4490      1  0 20:17 ?        00:00:00 /usr/local/bin/redis-server *:6381
    root       4495      1  0 20:17 ?        00:00:00 /usr/local/bin/redis-server *:6382
    root       4500   3755  0 20:17 pts/0    00:00:00 grep --color=auto redis
    [root@s1 ~]#
    
    
    

    假如日志中出现如下警告信息

    4668:S 17 Feb 20:28:42.107 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
    4668:S 17 Feb 20:28:42.107 # Server initialized
    4668:S 17 Feb 20:28:42.108 # 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.
    4668:S 17 Feb 20:28:42.108 * DB loaded from disk: 0.000 seconds
    4668:S 17 Feb 20:28:42.110 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
    
    解决办法

    The TCP backlog...
    方法1: 临时设置生效:

    shell> sysctl -w net.core.somaxconn=1024
    

    方法2: 永久生效:
    修改/etc/sysctl.conf文件,增加一行

    net.core.somaxconn=1024
    

    然后执行命令

    sysctl -p
    

    WARNING overcommit_memory ...

    方法1: 临时设置生效:

    shell> sysctl -w vm.overcommit_memory=1
    

    方法2: 永久生效:
    修改/etc/sysctl.conf文件,增加一行

    vm.overcommit_memory=1
    

    然后执行命令

    sysctl -p
    

    e. 查看主从复制信息

    image.png

    2. 配置 sentinel

    获取程序

    Sentinel 程序可以在编译后的 src 文档中发现, 它是一个命名为 redis-sentinel 的程序。

    运行一个 Sentinel 所需的最少配置如下所示:

    Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。

    运行一个 Sentinel 所需的最少配置如下所示:

    // 监控一个 Redis 服务器
    // 名称为 mymaster ,IP 为 127.0.0.1 端口为 6379
    // 最后的 2  是指最少有 2 给 Sentinel 实例同意一台 redis 服务器宕机,才会执行故障转义。
    sentinel monitor mymaster 127.0.0.1 6379 2
    
    // Sentinel 认为 Redis 服务器已经断线所需的毫秒数。
    sentinel down-after-milliseconds mymaster 60000
    
    // 
    sentinel failover-timeout mymaster 180000
    
    // 开始故障转义时,最多允许有多少个从服务器同时对新的主服务器进行同步数据。数字越小,完成整个故障转义所用的时间越长。
    sentinel parallel-syncs mymaster 1
    

    a. 获取并修改配置文件

    快速创建三个 sentinel 配置文件
    进入到 Redis 源码的目录下,执行如下命令


    image.png

    修改监听端口

    image.png

    之后在每个 sentinel 配置文件中添加守护进程方式运行,
    并修改dir 配置项的目录,

    daemonize yes
    dir /redis/data/
    

    最后别忘了修改监控的主服务器的 IP 和端口正确的 6380

    最终其中一个的配置文件应该是这样的


    image.png

    b. 启动服务并验证

    启动服务的语法:

    shell> redis-sentinel   sentinel的配置文件
    
    image.png image.png

    可以使用以下命令查看哨兵的信息

    [root@s1 ~]# redis-cli -p 27001 info
    ...略...
    # Sentinel
    sentinel_masters:1
    sentinel_tilt:0
    sentinel_running_scripts:0
    sentinel_scripts_queue_length:0
    sentinel_simulate_failure_flags:0
    master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=2,sentinels=3
    [root@s1 ~]#
    
    
    

    3. 客户端如何连接使用 Sentinel

    客户端需要知道所有 Sentinel 所有节点的 IP和一个 Master Name。

    第一步从所有的 Sentinel 列表中得到一个有效的 Sentinel 节点。

    image.png

    第二步向得到的 Sentinel 节点发送查询一个已知的 Master Name 的信息到请求,并得到 Master 节点的信息

    image.png

    第三步向 Master 节点验证 Maset 角色的真实性

    image.png

    第四步 客户端 和 Sentiel 之间建立发布订阅关系。

    客户端订阅 Sentinel 的频道,一旦 Master 的 IP 信息有变化,客户端就会通过此频道发布的信息得知。


    image.png

    4. 故障演练

    停止 Master 节点的服务

    [root@s1 ~]# redis-cli -p 6380 shutdown
    

    不断的刷新其中一个 Sentinel 节点的信息,观察最后一行信息的变化

    [root@s1 ~]# redis-cli -p 27001 info
    ...略...
    master0:name=mymaster,status=ok,address=127.0.0.1:6382,slaves=2,sentinels=3
    
    
    

    八、 集群

    1. 数据分区介绍

    image.png

    a. 数据分区的方式

    image.png

    两者的对比

    image.png

    b. 哈希分区的三种方式

    • 节点取余

    • 一致性哈希

    • 虚拟槽哈希

    ① 节点取余(不推荐使用)

    image.png
    问题: 当向集群重添加一个节点时,数据迁移率太大

    迁移前

    image.png

    迁移后

    image.png
    建议添加节点时,采用多倍扩容的方式
    多倍扩容

    ② 一致性哈希分区方式

    基本规则,顺时针的方式式


    image.png

    一致性哈希的扩容

    扩容前

    image.png

    扩容后

    image.png

    特点总结

    image.png

    ③ 虚拟槽分区方式(Redis Cluster 使用了此方式)

    虚拟槽的分配
    image.png

    2.Redis 集群的优势

    自动分割数据到不同的节点上。
    整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

    九、缓存设计和优化

    jalksjdfkj

    klajsdfklj

    lkjasdlkjf

    罗卡角六点十分几

    相关文章

      网友评论

        本文标题:Redis

        本文链接:https://www.haomeiwen.com/subject/dxnteqtx.html