• Redis3.2.0


    一、 Redis入门

    1. 互联网项目架构演变

      随着访问量上升,大部分使用MySQL架构的网站在数据库上都开始出现性能问题,Web程序不能再仅仅专注在功能上,同时也在追求性能。开始使用缓存技术缓解数据库压力,优化数据库的结构和索引。刚开始时比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大,文件缓存中的数据不能在多台Web服务器之间共享,大量的小文件IO也带来了比较高的IO压力。在这种情况下,Memcache就成了一款非常有效的解决方案。

      Memcache作为一个独立的分布式缓存服务器,为多个Web服务器提供了一个共享的高性能缓存服务,在Memcache服务器上,又发展了根据hash算法来进行多台Memcache缓存服务的扩展,然后又出现了一致性hash来解决增加或减少缓存服务器导致重新hash带来的大量缓存失效问题。 

      由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysqlmaster-slave模式成为这个时候的网站标配了

      在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM

      同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但性能也不能很好满足互联网的要求,只是在高可靠性上提供了非常大的保证。

      MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如10004KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

      现在的互联网架构

      目前互联网的新要求:3V3

        大数据时代的3V

          Volume:海量,数据量极大

          Variety:多样,数据类型:文本、图片、音频、视频……,终端设备:PC、移动端、嵌入式设备……

          Velocity:实时,直播,金融证券……

        互联网时代的3

          高可扩,不断优化现有的功能,不断开发新的功能;

          高性能,不能让用户感觉到等待的时间;

          高并发,同时处理并发请求的能力,如双十一的秒杀、抢购火车票;提升硬件,优化系统,优化项目,将费时的操作进入异步处理;

    2. NoSQL

      不仅仅是SQL—关系型数据库的强大助力 :

      NOSQL数据库的优势:

    • 易扩展

        – NoSQL数据库种类繁多,但它们都有一个共通的特点:就是去除关系型数据库的关系型特点。数据之间无关系,这样就变得非常容易扩展,而相对应的来看:关系型数据库修改表结构非常困难。这就为项目架构设计提供了更大的扩展空间。

    • 大数据量高性能:

        – NoSQL数据库都具有非常高的读写性能,尤其在大数据量的情况下,表现同样优秀。这得益于NoSQL数据库中数据之间没有关系,数据库结构简单。

        – 从缓存角度来看,MySQLQuery Cache是表级别的粗粒度缓存,假设存储了100条数据,其中有一条数据修改了,整个缓存失效,效率很低。而NoSQL数据库的缓存是记录级的细粒度缓存,任何一条记录的修改都不影响其他记录,效率很高。

    • 多样灵活的数据模型

        – NoSQL数据库无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增减修改字段简直就是一个噩梦。

    3. Redis

    3.1 简介

      Redis:Remote Dictionary Server(远程字典服务器)

      官网介绍: 

    3.2 安装

      ①将Redistar包上传到opt目录,下载地址:https://pan.baidu.com/s/1ieup5969PI9iLiIeNi4NEw   提取码:jw2i 

      ②将redis-3.2.5.tar.gz解压缩,并且对其重命名

    tar -zxvf /opt/software/redis-3.2.5.tar.gz -C /opt/module/
    mv /opt/module/redis-3.2.5 /opt/module/redis

      ③安装gcc环境,我们需要将源码编译后再安装,因此需要安装c语言的编译环境!不能直接make!

        第一种方式:可以上网

    sudo yum install -y gcc-c++

        第二种:不能上网,确保插入了安装光盘!挂载安装光盘,然后进入Packages中,依次执行以下命令:

    rpm -ivh mpfr-2.4.1-6.el6.x86_64.rpm

    rpm -ivh cpp-4.4.7-17.el6.x86_64.rpm

    rpm -ivh ppl-0.10.2-11.el6.x86_64.rpm

    rpm -ivh cloog-ppl-0.15.7-1.2.el6.x86_64.rpm

    rpm -ivh gcc-4.4.7-17.el6.x86_64.rpm

        之后查看安装是否成功:

    rpm –qa|grep gcc

        常见错误:在没有安装gcc环境下,如果执行了make,不会成功!安装环境后,第二次make有可能报错:Jemalloc/jemalloc.h:没有那个文件

        解决: 运行 make distclean之后再make

      ④编译,执行make命令!

    cd /opt/module/redis/
    make

      ⑤编译完成后,安装,执行make install命令!(必须是root权限,不然会报错)

    cd /opt/module/redis/src/

    sudo make install

      ⑥文件会被安装到 /usr/local/bin目录

    cd /usr/local/bin

      ⑦可以将redisbin目录,加入到环境变量中

    sudo vim /etc/profile.d/my_env.sh
    #REDIS_HOME
    export REDIS_HOME=/usr/local/
    export PATH=$PATH:$REDIS_HOME/bin
    source /etc/profile.d/my_env.sh

    bin目录常用命令

    Redis-benchmark

    压力测试。标准是每秒80000次写操作,110000次读操作 (服务启动起来后执行,类似安兔兔跑分)

    Redis-check-aof

    修复有问题的AOF文件

    Redis-check-dump

    修复有问题的dump.rdb文件

    Redis-sentinel

    启动哨兵,集群使用

    redis-server

    启动服务器

    redis-cli

    启动客户端

    3.3 启动

    3.3.1 服务端启动

      将配置文件,保留一份副本,再进行启动,命令:

    redis-server  配置文件地址
    #我这里直接写绝对路径
    redis-server /opt/module/redis/redis.conf

      但是这样的话,发现命令窗口被占用了,很不方便。当然你可以再启动一个会话窗口。

      解决:修改配置文件,改为守护进程,在后台运行

    vim /opt/module/redis/redis.conf
    #设置为yes,表示后台启动
    daemonize yes

      后台启动后,查看服务: 

    redis-server /opt/module/redis/redis.conf
    ps -ef | grep redis | grep -v grep

    sudo netstat -nlpt | grep 27226

    3.3.2 客户端登录

    命令

    说明

    举例

    备注

    redis-cli

    启动客户端

    redis-cli p 端口号

    连接指定的端口号

    直接执行的话,默认端口号就是6379

    ping

    测试联通

    回复pong代表联通

    exit

    退出客户端

    redis-cli shutdown

    停止服务器

    redis-cli -h 127.0.0.1 -p 6379 shutdown

    停止指定ip指定端口号的服务器

    redis是通过客户端发送停止服务器的命令

    二、Redis基本操作

    1. 数据库连接操作

    命令

    说明

    举例

    备注

    select <dbid>

    切换数据库

    select 1:切换到1号库

    开启redis服务后,一共有160-15)个库,默认在0号库

    flushdb

    清空当前库

    dbsize

    查看数据库数据个数

    flushall

    通杀全部库

    2. key的操作

      Redis中的数据以键值对(key-value)为基本存储方式,其中key都是字符串

    表达式

    描述

    KEYS  pattern

    查询符合指定表达式的所有key,支持*,?等

    TYPE   key

    查看key对应值的类型

    EXISTS  key

    指定的key是否存在,0代表不存在,dr

    DEL  key

    删除指定key

    RANDOMKEY

    在现有的KEY中随机返回一个

    EXPIRE  key  seconds

    为键值设置过期时间,单位是秒,过期后key会被redis移除

    TTL key

    查看key还有多少秒过期,-1表示永不过期,-2表示已过期

    RENAME  key  newkey

    重命名一个keyNEWKEY不管是否是已经存在的都会执行,如果NEWKEY已经存在则会被覆盖

    RENAMENX  key  newkey

    只有在NEWKEY不存在时能够执行成功,否则失败

    3. 常用五大数据类型

      Redis中的数据以键值对(key-value)为基本存储方式,其中key都是字符串,这里探讨数据类型都是探讨value的类型。

     

     

    key

    value

    string

    字符串

    list

    可以重复的集合

    set

    不可以重复的集合

    hash

    类似于Map<String,String>

    zsetsorted  set

    带分数的set

    4. String操作

      String类型是Redis中最基本的类型,它是key对应的一个单一值。二进制安全,不必担心由于编码等问题导致二进制数据变化。所以redisstring可以包含任何数据,比如jpg图片或者序列化的对象。

    Redis中一个字符串值的最大容量是512M

    #可输入如下指令查询string的相关操作命令
    help @string

    SET  key  value

    添加键值对

    GET  key

    查询指定key的值

    APPEND  key  value

    将给定的value追加到原值的末尾

    STRLEN  key

    获取值的长度

    SETNX  key  value

    只有在 key 不存在时设置 key 的值

    INCR  key

    指定key的值自增1,只对数字有效

    DECR  key

    指定key的值自减1,只对数字有效

    INCRBY  key  num

    自增num

    DECRBY  key  num

    自减num  

    MSET  key1 value1 key2 value2…

    同时设置多个key-value

    MGET  key1 key2

    同时获取一个或多个value

    MSETNX key1 value1 key2 value2

    key不存在时,设置多个key-value

    GETRANGE  key起始索引 结束索引

    获取指定范围的值,都是闭区间

    SETRANGE  key起始索引 value

    从起始位置开始覆写指定的值

    GETSET  key  value

    以新换旧,同时获取旧值

    SETEX  key  过期时间  value

    设置键值的同时,设置过期时间,单位秒

    5. list操作

      在Javalist 一般是单向链表,如常见的Arraylist,只能从一侧插入。Redis中,list是双向链表。可以从两侧插入。可以简单理解为两端开口的,两端都可以进出。

      常见操作:

        遍历:遍历的时候,是从左往右取值;

        删除:弹栈,POP;

        添加:压栈,PUSH ;

      Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

    #可输入如下指令查询list的相关操作命令
    help @list

    LPUSH/RPUSH key value1 value2…

    从左边/右边压入一个或多个值

    头尾效率高,中间效率低

    LPOP/RPOP key

    从左边/右边弹出一个值

    值在键在,值光键亡

    弹出=返回+删除

    LRANGE key start stop

    查看指定区间的元素

    正着数:0,1,2,3,...

    倒着数:-1,-2,-3,...

    LINDEX key index

    按照索引下标获取元素(从左到右)

    LLEN key

    获取列表长度

    LINSERT key BEFORE|AFTER value newvalue

    在指定value的前后插入newvalue

    LREM key n value

    从左边删除n个value

    LSET key index value

    把指定索引位置的元素替换为另一个值

    LTRIM key start stop

    仅保留指定区间的数据

    RPOPLPUSH list1 list2

    从list1右边弹出一个值,左侧压入到list2

    6. set操作

      set是无序的,且是不可重复的。

    #可输入如下指令查询set的相关操作命令
    help @set

    SADD key member [member ...]

    将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。

    SMEMBERS key

    取出该集合的所有值

    SISMEMBER key value

    判断集合<key>是否为含有该<value>值,有返回1,没有返回0

    SCARD key

    返回集合中元素的数量

    SREM key member [member ...]

    从集合中删除元素

    SPOP key [count]

    从集合中随机弹出count个数量的元素,count不指定就弹出1

    SRANDMEMBER key [count]

    从集合中随机返回count个数量的元素,count不指定就返回1

    SINTER key [key ...]

    将指定的集合进行“交集”操作

    SINTERSTORE dest key [key ...]

    取交集,另存为一个set

    SUNION key [key ...]

    将指定的集合执行“并集”操作

    SUNIONSTORE dest key [key ...]

    取并集,另存为set

    SDIFF key [key ...]

    将指定的集合执行“差集”操作

    SDIFFSTORE dest key [key ...]

    取差集,另存为set

    7. hash操作

      Hash数据类型的键值对中的值是“单列”的,不支持进一步的层次结构。

    key

    field:value

    "k01":"v01"

    "k02":"v02"

    "k03":"v03"

    "k04":"v04"

    "k05":"v05"

    "k06":"v06"

    "k07":"v07"

      从前到后的数据对应关系:

    JSON:
      stu:{"stu_id":10,"stu_name":"tom","stu_age":30}
    Java:
    public class Student {
    private Integer stuId;//10
    private String stuName;//"tom"
    private Integer stuAge;//30
    ...
    }
    Student stu=new Student()’
    stu.setStuId=10;
    stu.setStuName=”tom”;
    stu.setStuAge=30;

      Redis hash:

    key

    value(hash)

    stu

    stu_id

    10

    stu_name

    tom

    stu_age

    30

      常用操作:

    #可输入如下指令查询hash的相关操作命令
    help @hash

    HSET key field value

    key中的field赋值value

    HMSET key field value [field value ...]

    为指定key批量设置field-value

    HSETNX key field value

    当指定key的field不存在时,设置其value

    HGETALL key

    获取指定key的所有信息(fieldvalue

    HKEYS key

    获取指定key的所有field

    HVALS key

    获取指定key的所有value

    HLEN key

    指定keyfield个数

    HGET key field

    key中根据field取出value

    HMGET key field [field ...]

    为指定key获取多个filed的值

    HEXISTS key field

    指定key是否有field

    HINCRBY key field increment

    为指定keyfield加上增量increment

    8. zset操作

      zset是一种特殊的setsorted set),在保存value的时候,为每个value多保存了一个score信息。根据score信息,可以进行排序。这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了

    #可输入如下指令查询zset的相关操作命令
    help @sorted_set

    ZADD key  [score member ...]

    添加

    ZSCORE key member

    返回指定值的分数

    ZRANGE key start stop [WITHSCORES]

    返回指定区间的值,可选择是否一起返回scores

    ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

    在分数的指定区间内返回数据,从小到大排列

    ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

    在分数的指定区间内返回数据,从大到小排列

    ZCARD key

    返回集合中所有的元素的数量

    ZCOUNT key min max

    统计分数区间内的元素个数

    ZREM key member

    删除该集合下,指定值的元素

    ZRANK key member

    返回该值在集合中的排名,从0开始

    ZINCRBY key increment member

    为元素的score加上增量

    三、Redis配置文件

    1.单位说明

      注意:(1)1k1kb是不同的;(2)单位的大小写不敏感!

    2. include

      可以将公共的配置放入到一个公共的配置文件中,然后通过子配置文件引入父配置文件中的内容!将配置按照模块分开!

    3. network

    属性

    含义

    备注

    bind

    限定访问的主机地址

    如果没有bind,就是任意ip地址都可以访问。生产环境下,需要写自己应用服务器的ip地址。

    protected-mode

    安全防护模式

    如果没有指定bind指令,也没有配置密码,那么保护模式就开启,只允许本机访问。

    port

    端口号

    默认是6379

    tcp-backlog

    网络连接过程中,某种状态的队列的长度

    redis是单线程的,指定高并发时访问时排队的长度。超过后,就呈现阻塞状态。可以理解是一个请求到达后至到接受进程处理前的队列长度。(一般情况下是运维根据集群性能调控)高并发情况下,此值可以适当调高。

    timeout

    超时时间

    默认永不超时

    tcp-keepalive

    对客户端的心跳检测间隔时间

    4. general

    属性

    含义

    备注

    daemonize

    是否为守护进程模式运行

    守护进程模式可以在后台运行

    pidfile

    进程id文件保存的路径

    配置PID文件路径,当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/redis/run/redis_6379.pid 文件里面

    loglevel

    定义日志级别

    debug(记录大量日志信息,适用于开发、测试阶段)

      verbose(较多日志信息)

      notice(适量日志信息,使用于生产环境)

      warning(仅有部分重要、关键信息才会被记录)

    logfile

    日志文件的位置

    当指定为空字符串时,为标准输出,如果redis以守护进程模式运行,那么日志将会输出到/dev/null

    syslog-enabled

    是否记录到系统日志

    要想把日志记录到系统日志服务中,就把它改成 yes

    syslog-ident

    设置系统日志的ID

    syslog-facility

    指定系统日志设置

    必须是 USER 或者是 LOCAL0-LOCAL7 之间的值

    databases

    设置数据库数量

    5. 其他

    属性

    含义

    备注

    requirepass

    设置密码

    maxclients

    最大连接数

    maxmemory

    最大占用多少内存

    一旦占用内存超限,就开始根据缓存清理策略移除数据如果Redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,

    那么Redis则会针对那些需要申请内存的指令返回错误信息,比如SETLPUSH等。

    maxmemory-policy noeviction

    缓存清理策略

    1volatile-lru:使用LRU算法移除key,只对设置了过期时间的键

    2allkeys-lru:使用LRU算法移除key

    3volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键

    4allkeys-random:移除随机的key

    5volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key

    6noeviction:不进行移除。针对写操作,只是返回错误信息

    maxmemory-samples

    样本数

    样本数越小,准确率越低,但是性能越好。LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小。一般设置37的数字。

    四、持久化

      Redis主要是工作在内存中。内存本身就不是一个持久化设备,断电后数据会清空。所以Redis在工作过程中,如果发生了意外停电事故,如何尽可能减少数据丢失。

      Redis提供了不同级别的持久化方式:

        1)RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储

        2)AOF持久化方式记录每次对服务器写的操作指令,当服务器重启时,会重新执行这些指令来恢复原始数据,AOF命令以redis协议追加保存每次写操作指令至aof文件末尾,Redis还能对aof文件进行后台重写,使得aof文件的体积不至于过大

        3)若你只希望数据在服务器运行时存在,也可以不使用任何持久化方式

        4)你也可以同时开启两种持久化方式,在这种情况下,当Redis重启时会优先载入aof文件来恢复原始的数据,因为在通常情况下,aof文件保存的数据集要比rdb文件保存的数据集完整

    1. RDB

    1.1 RDB简介

      RDB:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。RDB是默认开启的!

      工作机制:每隔一段时间,就把内存中的数据保存到硬盘上的指定文件中。

      Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

      RDB的缺点是最后一次持久化后的数据可能丢失。

    1.2 RDB保存策略

      save 900 1   : 900 秒内如果至少有 1 key 的值变化,则保存

      save 300 10  : 300 秒内如果至少有 10 key 的值变化,则保存

      save 60 10000  :60 秒内如果至少有 10000 key 的值变化,则保存

      save “”  就是禁用RDB模式;

    1.3 RDB常用属性配置

    属性

    含义

    备注

    save

    保存策略

    dbfilename

    RDB快照文件名

    dir

    RDB快照保存的目录

    必须是一个目录,不能是文件名。最好改为固定目录。默认为./代表执行redis-server命令时的当前目录!

    stop-writes-on-bgsave-error

    是否在备份出错时,继续接受写操作

    如果用户开启了RDB快照功能,那么在redis持久化数据到磁盘时如果出现失败,默认情况下,redis会停止接受所有的写请求

    rdbcompression

    对于存储到磁盘中的快照,可以设置是否进行压缩存储。

    如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,

        可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。

    rdbchecksum

    是否进行数据校验

    在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,

     如果希望获取到最大的性能提升,可以关闭此功能。

    1.4 RDB数据丢失的情况

      两次保存的时间间隔内,服务器宕机,或者发生断电问题。

    1.5 RDB的触发

      ①基于自动保存的策略

      ②执行save,或者bgsave命令!执行时,是阻塞状态。

      ③执行flushall命令,也会产生dump.rdb,但里面是空的,没有意义。

      ④当执行shutdown命令时,也会主动地备份数据。

    1.6 RDB的优缺点

       优点:

        1)RDB是一个非常紧凑的文件,它保存了某个时间点的数据集,非常适用于数据集的备份,比如:你可以在每个小时保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出现问题,也可以根据需求恢复到不同版本的数据集

        2)RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复

        3)RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能

        4)与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些

      缺点:

        1)若你希望在redis意外停止工作(例如电源中断)的情况丢失的数据最少的话,那么RDB不适合你,虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,通常每隔5分钟或者更久做一次完整的保存,万一在redis意外宕机,可能会丢失几分钟的数据

        2)RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大时,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求,若数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是可以调节重写日志文件的频率来提高数据集的耐久度

    2. AOF

    2.1 AOF简介

      AOF是以日志的形式来记录每个写操作,将每一次对数据进行修改,都把新建、修改数据的命令保存到指定文件中。Redis重新启动时读取这个文件,重新执行新建、修改数据的命令恢复数据。默认不开启,需要手动开启,AOF文件的保存路径,同RDB的路径一致。

      AOF在保存命令的时候,只会保存对数据有修改的命令,也就是写操作!RDB和AOF存的不一致的情况下,按照AOF来恢复。因为AOF是对RDB的补充。备份周期更短,也就更可靠。

    2.2 AOF保存策略

      appendfsync always:每次产生一条新的修改数据的命令都执行保存操作;效率低,但是安全!

      appendfsync everysec:每秒执行一次保存操作。如果在未保存当前秒内操作时发生了断电,仍然会导致一部分数据丢失(即1秒钟的数据)。

      appendfsync no:从不保存,将数据交给操作系统来处理。更快,也更不安全的选择。

      推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

    2.3 AOF常用属性

    属性

    含义

    备注

    appendonly

    是否开启AOF功能

    默认是关闭的

    appendfilename

    AOF文件名称

    appendfsync

    AOF保存策略

    官方建议everysec

    no-appendfsync-on-rewrite

    在重写时,是否执行保存策略

    执行重写,可以节省AOF文件的体积;而且在恢复的时候效率也更高。

    auto-aof-rewrite-percentage

    重写的触发条件

    当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写

    auto-aof-rewrite-min-size

    设置允许重写的最小aof文件大小

    避免了达到约定百分比但尺寸仍然很小的情况还要重写

    aof-load-truncated

    截断设置

    如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load

    2.4 AOF文件的修复

      如果AOF文件中出现了残余命令,会导致服务器无法重启。此时需要借助redis-check-aof工具来修复!

      命令: redis-check-aof  --fix 文件

    2.5 AOF的优缺点

      优点:

        1)备份机制更稳健,丢失数据概率更低

        2)可读的日志文本,通过操作AOF稳健,可以处理误操作

      缺点:

        1)比起RDB占用更多的磁盘空间

        2)恢复备份速度要慢

        3)每次读写都同步的话,有一定的性能压力

        4)存在个别Bug,造成恢复不能

    3. 备份建议

    3.1 如何看待数据“绝对”安全

      Redis作为内存数据库从本质上来说,如果不想牺牲性能,就不可能做到数据的“绝对”安全。RDBAOF都只是尽可能在兼顾性能的前提下降低数据丢失的风险,如果真的发生数据丢失问题,尽可能减少损失。在整个项目的架构体系中,Redis大部分情况是扮演“二级缓存”角色。

      二级缓存适合保存的数据:

        1)经常要查询,很少被修改的数据。

        2)不是非常重要,允许出现偶尔的并发问题。

        3)不会被其他应用程序修改。

      如果Redis是作为缓存服务器,那么说明数据在MySQL这样的传统关系型数据库中是有正式版本的。数据最终以MySQL中的为准。

    3.2 官方建议

      官方推荐两个都用;如果对数据不敏感,可以选单独用RDB;不建议单独用AOF,因为可能出现Bug;如果只是做纯内存缓存,可以都不用

    五、事务

    1. 事务简介

      1)Redis中事务,不同于传统的关系型数据库中的事务。

      2)Redis中的事务指的是一个单独的隔离操作。

      3)Redis的事务中的所有命令都会序列化、按顺序地执行且不会被其他客户端发送来的命令请求所打断。

      4)Redis事务的主要作用是串联多个命令防止别的命令插队

    2. 事务常用命令

    #可输入如何指令查看事务的操作命令
    help @transactions

    MULTI

    标记一个事务块的开始

    EXEC

    执行事务中所有在排队等待的指令并将链接状态恢复到正常 当使用WATCH 时,只有当被监视的键没有被修改,且允许检查设定机制时,EXEC会被执行

    DISCARD

    刷新一个事务中所有在排队等待的指令,并且将连接状态恢复到正常。

    如果已使用WATCHDISCARD将释放所有被WATCHkey

    WATCH

    标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)

    3. 事务的常见演示

    3.1 简单组队

      MULTI开启组队,EXEC依次执行队列中的命令。

      DISCARD中途取消组队

    3.2 组队失败

    3.2.1 自作自受

      此种情况,语法符合规范,Redis只有在执行中,才可以发现错误。而在Redis中,并没有回滚机制,因此错误的命令,无法执行,正确的命令会全部执行!

    3.2.2 殃及池鱼

      在编译的过程中,Redis检测出来了错误的语法命令,因此它认为这条组队,一定会发生错误,因此全体取消;

    3.3.3 官方说明

      为什么Redis不支持回滚(roll back)?

      若使用关系式数据库的经验,那么"redis在事务失败时不进行回滚,而是继续执行余下的命令"这种做法可能会让你感觉有点奇怪。下面是这种做法的优点:

        1)Redis命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上,也就是说,从实用性角度看,失败的命令是由编程错误造成的,而这些错误应该在开发过程中被发现,而不应该出现在生产环境中

        2)因为不需要对回滚进行支持,所以Redis的内部可以保持简单且快速

      有种观点认为Redis处理事务的做法会产生bug,然而需要注意的是,在通常情况下,回滚并不能解决编程错误带来的问题。例如:本来想通过incr命令将键的值加1,却不小心加上了2,又或者对错误类型的键执行了incr,回滚是没有办法处理这些情况的

    4.

    4.1 悲观锁 

      执行操作前假设当前的操作肯定(或有很大几率)会被打断(悲观)。基于这个假设,我们在做操作前就会把相关资源锁定,不允许自己执行期间有其他操作干扰。

      Redis不支持悲观锁Redis作为缓存服务器使用时,以读操作为主,很少写操作,相应的操作被打断的几率较少。不采用悲观锁是为了防止降低性能。

    4.2 乐观锁

      执行操作前假设当前操作不会被打断(乐观)。基于这个假设,我们在做操作前不会锁定资源,万一发生了其他操作的干扰,那么本次操作将被放弃。

    5. Redis中的锁策略

      Redis采用了乐观锁策略(通过watch操作)。乐观锁支持读操作,适用于多读少写的情况!

      在事务中,可以通过watch命令来加锁;使用 UNWATCH可以取消加锁;

      如果在事务之前,执行了WATCH(加锁),那么执行EXEC 命令或 DISCARD 命令后,锁会自动释放,即不需要再执行 UNWATCH

    六、主从复制

    1. 主从简介

      配置多台Redis服务器,以主机和备机的身份分开。主机数据更新后,根据配置和策略,自动同步到备机的master/salver机制,Master以写为主,Slave以读为主,二者之间自动同步数据。

      目的:

        1)读写分离提高Redis性能;

        2)避免单点故障,容灾快速恢复

      原理:每次从机联通后,都会给主机发送sync指令,主机立刻进行存盘操作,发送RDB文件,给从机从机收到RDB文件后,进行全盘加载。之后每次主机的写操作命令,都会立刻发送给从机,从机执行相同的命令来保证主从的数据一致!

      注意:主库接收到SYNC的命令时会执行RDB过程即使在配置文件中禁用RDB持久化也会生成,但是如果主库所在的服务器磁盘IO性能较差那么这个复制过程就会出现瓶颈,庆幸的是,Redis2.8.18版本开始实现了无磁盘复制功能(不过该功能还是处于试验阶段),设置repl-diskless-sync yes。即Redis在与从数据库进行复制初始化时将不会将快照存储到磁盘而是直接通过网络发送给从数据库避免了IO性能差问题

    2. 主从准备

      除非是不同的主机配置不同的Redis服务,否则在一台机器上面跑多个Redis服务,需要配置多个Redis配置文件。

      ①准备多个Redis配置文件,每个配置文件,需要配置以下属性

    daemonize yes: 服务在后台运行
    port:端口号
    pidfile:pid保存文件
    logfile:日志文件(如果没有指定的话,就不需要)
    dump.rdb: RDB 
    appendonly 关掉,或者是更改appendonly文件的名称。
    #在 /opt/module/redis/ 目录下新建redis_6379.conf文件并写入如下内容:
    include /opt/module/redis/redis.conf
    port 6379
    pidfile /opt/module/redis/redis_6379.pid
    dbfilename dump_6379.rdb
    bind 0.0.0.0
    daemonize yes
    logfile /opt/module/redis/log_6379.log
    #在 /opt/module/redis/ 目录下新建redis_6380.conf文件并写入如下内容:
    include /opt/module/redis/redis.conf
    port 6380
    pidfile /opt/module/redis/redis_6380.pid
    dbfilename dump_6380.rdb
    bind 0.0.0.0
    daemonize yes
    logfile /opt/module/redis/log_6380.log
    #在 /opt/module/redis/ 目录下新建redis_6381.conf文件并写入如下内容:
    include /opt/module/redis/redis.conf
    port 6381
    pidfile /opt/module/redis/redis_6381.pid
    dbfilename dump_6381.rdb
    bind 0.0.0.0
    daemonize yes
    logfile /opt/module/redis/log_6381.log

      ②根据多个配置文件,启动多个Redis服务(原则是配从不配主)

    redis-cli -p 6379
    redis-cli -p 6380
    redis-cli -p 6381

    3. 主从建立

    3.1 临时建立

      原则:配从不配主(配置之前)

      配置:在从服务器上执行SLAVEOF ip:port命令

    slaveof hadoop102 6380

      查看:执行info replication命令;

    3.2 永久建立

      在从机的配置文件中,编写slaveof属性配置,配置完成后重新启动redis服务即可

    slaveof hadoop102 6380

    3.3 恢复身份

        在从机中执行命令slaveof no one恢复自由身!

    slaveof no one

    4. 主从常见问题

      ①从机是从头开始复制主机的信息,还是只复制切入以后的信息?

      答:从头开始复制,即完全复制。

      ②从机是否可以写?

      答:默认情况不能,可以通过修改配置文件,设置slave-read-only no.但是从机写入的数据是不能同步到主机,因此没有设置的必要!

      ③主机shutdown从机是上位还是原地待命

      答:原地待命

      ④主机又回来了后,主机新增记录,从机还能否顺利复制?

      答:可以

      ⑤从机宕机后,重启,宕机期间主机的新增记录,从机是否会顺利复制?

      答:可以

      ⑥其中一台从机down重启,能否重认旧主? 

      答:不一定,看配置文件中是否配置了slaveof

      ⑦如果两台从机都从主机同步数据,此时主机的IO压力会增大,如何解决? 

      答:按照主---从(主)---从模式配置!

    5. 哨兵模式

    5.1 简介

      作用

        1)主从状态检测

        2)如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave(如果重启成功 )

    单个哨兵

    多个哨兵

        注意:多个哨兵,不仅同时监控主从状态,且哨兵之间也互相监控!

      下线

        ①主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。

        ②客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover.

      工作原理

        ①每个Sentinel以每秒钟一次的频率向它所知的MasterSlave以及其他 Sentinel 实例发送一个 PING 命令 ;

        ②如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线;

        ③如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态;

        ④当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 ;

        ⑤在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有MasterSlave发送 INFO 命令

        ⑥当MasterSentinel 标记为客观下线时,Sentinel 向下线的 Master 下的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 ;

        ⑦若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的主观下线状态就会被移除;

        ⑧若 Master 重新向 Sentinel PING 命令返回有效回复, Master 的客观下线状态就会被移除;

    5.2 配置

      哨兵模式需要配置哨兵的配置文件,哨兵实际上就是一个Redis Server(设置6380端口为master节点)

    vim /opt/module/redis/sentinel.conf
    #1表示的意思是如果有一个哨兵确认了master状态为主观下线,则将该master的状态从主观下线转换为客观下线,并从slave中重新选举出master
    sentinel monitor mymaster hadoop102 6380 1

      启动哨兵:

    redis-sentinel sentinel.conf

      在主节点随便做一些操作,然后再关闭该服务

    5.3 主机宕机、重新上线后的变化

    sdown master mymaster 192.168.1.102 6380  //主观下线
    odown master mymaster 192.168.1.102 6380 #quorum 1/1  //客观下线
    vote-for-leader 113d6eff04ec03a7edf5707e2ae044954a7b3c46 5  //选举leader
    failover-state-send-slaveof-noone slave 192.168.1.102:6379 192.168.1.102 6379 @ mymaster 192.168.1.102 6380  //把一个从机设置为主机
    -sdown slave 192.168.1.102:6380 192.168.1.102 6380 @ mymaster 192.168.1.102 6379    //离开主观下线状态
    convert-to-slave slave 192.168.1.102:6380 192.168.1.102 6380 @ mymaster 192.168.1.102 6379    //转换为从机

    七、Redis Cluster

    1. 引入集群

      问题:

        1)容量不够,redis如何进行扩容?

        2)并发写操作, redis如何分摊?

      什么是集群:

        1)Redis 集群实现了对Redis的水平扩容,即启动Nredis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N

        2)Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

    2. 创建集群

    2.1 安装ruby环境:

      本身redis集群的安装是很麻烦了,通过ruby工具,可以非常方便的将一系列命令打包为一个脚本!依次执行在安装光盘下的Package目录(/media/CentOS_6.8_Final/Packages)下的rpm包:

    rpm -ivh compat-readline5-5.2-17.1.el6.x86_64.rpm

    rpm -ivh ruby-libs-1.8.7.374-4.el6_6.x86_64.rpm

    rpm -ivh ruby-1.8.7.374-4.el6_6.x86_64.rpm

    rpm -ivh ruby-irb-1.8.7.374-4.el6_6.x86_64.rpm

    rpm -ivh ruby-rdoc-1.8.7.374-4.el6_6.x86_64.rpm

    rpm -ivh rubygems-1.3.7-5.el6.noarch.rpm

      也可以在联网状态下,执行yum安装,执行yum -y install ruby,之后安装rubygem,rubygemruby的包管理框架。

    sudo yum -y install rubygems
    sudo yum -y install ruby

    2.2 安装redis gem

      redis-3.2.0.gem是一个通过ruby操作redis的插件,拷贝redis-3.2.0.gem到/opt/software/目录下,在/opt/software/目录下执行

    gem install --local redis-3.2.0.gem

    2.3 制作6redis配置文件

      端口号分别是:6379,6380,6381,6382,6383,6384(每个配置文件中需要指定)

    daemonize yes: 服务在后台运行
    port:端口号
    pidfile:pid保存文件
    logfile:日志文件(如果没有指定的话,就不需要)
    dump.rdb: RDB备份文件的名称
    appendonly 关掉,或者是更改appendonly文件的名称。    
    cluster-enabled yes    打开集群模式
    cluster-config-file  nodes-6379.conf  设定节点配置文件名
    cluster-node-timeout 15000   设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。
    #在/opt/nodule/redis/目录下新建redis_6379.conf文件,并将如下内容添加进去(其他节点类似,照着新建并修改就行)
    include /opt/module/redis/redis.conf pidfile "/opt/module/redis/redis_6379.pid" port 6379 dbfilename "dump_6379.rdb"
    daemonize yes cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 15000
    bind 0.0.0.0
    logfile /opt/module/redis/log_6379.log

      在创建集群初始化时,把所有节点的dump文件全部删掉,重新新建

    rm -rf /opt/module/redis/log_* /opt/module/redis/dump_* /opt/module/redis/redis_*

    2.4 开启集群

      ①首先依次启动6个节点,启动后,会在当前文件夹生成nodes-xxxx.conf文件

    redis-server redis_6379.conf 
    redis-server redis_6380.conf 
    redis-server redis_6381.conf 
    redis-server redis_6382.conf 
    redis-server redis_6383.conf 
    redis-server redis_6384.conf

      ②配置集群,在/opt/module/redis/src目录下,执行命令:

    ./redis-trib.rb create --replicas 1 192.168.1.102:6379 192.168.1.102:6380 192.168.1.102:6381 192.168.1.102:6382 192.168.1.102:6383 192.168.1.102:6384

        注意,此处不要用127.0.0.1或者hadoop102,请用真实IP地址,敲入回车键后输入:yes,再次按回车键

      ③之后登录到客户端,通过 cluster nodes 命令查看集群信息

    cluster nodes

         6个节点,为什么是三主三从?

        配置机器,至少需要6个节点,否则会报错:

            命令create,代表创建一个集群。参数--replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。一个集群至少要有三个主节点,分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。

    2.5 slot

      进入集群后,如果我们,直接写入数据,可能会看到报错信息:

      这是因为,集群中多了slot(插槽)的设计。一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key CRC16 校验和。

      集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:

        节点 A 负责处理 0 号至 5500 号插槽。

        节点 B 负责处理 5501 号至 11000 号插槽。

        节点 C 负责处理 11001 号至 16383 号插槽。

    2.6 集群中写入数据

    2.6.1 客户端重定向

      ①在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器插槽,redis会报错,并告知应前往的redis实例地址和端口。

      ②redis-cli客户端提供了 –c 参数实现自动重定向。如 redis-cli  -c p 6379 登入后,再录入、查询键值对可以自动重定向。

      ③每个slot可以存储一批键值对。

    2.6.2 如何多键操作

      采用哈希算法后,会自动地分配slot,而 不在一个slot下的键值,是不能使用mget,mset等多键操作。

      如果有需求,需要将一批业务数据一起插入呢?

      解决:可以通过{}来定义组的概念,从而使key{}内相同内容的键值对放到一个slot中去。

    2.7 集群中读取数据

      1)CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上

    cluster keyslot k100

      2)CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量  

    cluster countkeysinslot 13943

      3)CLUSTER KEYSLOT <key>:计算key应该放在哪个槽

    cluster keyslot k123

      4)CLUSTER GETKEYSINSLOT <slot> <count> 返回 count  slot 槽中的键。(4254表示哪个槽,3表示槽里的键取出三个)

    cluster getkeysinslot 4254 3

    2.8 集群中故障恢复

      问题1:如果主节点下线?从节点能否自动升为主节点?

      答:主节点下线,从节点自动升为主节点。

    没关闭6380主节点之前

    关闭6380主节点之后

    redis-cli -h 192.168.1.102 -p 6380 shutdown

      问题2:主节点恢复后,主从关系会如何?

      答:主节点恢复后,主节点变为从节点!

    redis-server redis_6380.conf

      问题3:如果所有某一段插槽的主从节点都宕掉,redis服务是否还能继续?

      答:服务是否继续,可以通过redis.conf中的cluster-require-full-coverage参数(默认关闭)进行控制。主从都宕掉,意味着有一片数据,会变成真空,没法再访问了!如果无法访问的数据,是连续的业务数据,我们需要停止集群,避免缺少此部分数据,造成整个业务的异常。此时可以通过配置cluster-require-full-coverageyes。如果无法访问的数据,是相对独立的,对于其他业务的访问,并不影响,那么可以继续开启集群体提供服务。此时,可以配置cluster-require-full-coverageno

    2.9 集群的优缺点

      优点:

        1)实现扩容

        2)分摊压力

        3)无中心配置相对简单

      缺点:

        1)多键操作是不被支持的

        2)多键的Redis事务是不被支持的。lua脚本不被支持。

      由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大

  • 相关阅读:
    安装devstack之配置proxy
    设备信息表项目
    好的运维工程师
    rhel 6.4 增加光盘为yum repo
    深度运维产品工具关键词
    坚持是一种能力
    书单 电影单 电视剧单
    三日不读书,便觉得言语无味,面目可憎
    STAR法则
    【断舍离】
  • 原文地址:https://www.cnblogs.com/LzMingYueShanPao/p/14771462.html
Copyright © 2020-2023  润新知