• 初识redis


    1. 理解为什么要使用redis,redis解决了什么问题
      redis是一种支持Key-Value等多种数据结构的存储系统。可用于缓存,事件发布或订阅,高速队列等场景。该数据库使用 C语言编写,支持网络,提供字符串,哈希,列表,队列,集合结构直接存取,基于内存,可持久化。

      1. redis的优点
        1. 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
        2. 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
        3. 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。(事务)
        4. 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
      2. redis的用途
        1. 会话缓存
        2. 消息队列,例如支付
        3. 活动排行榜或者计数
        4. 发布、订阅消息(消息通知)
        5. 商品列表、评论列表
    2. 单机版安装

      redis单节点安装:
      1、redis下载
      	http://download.redis.io/releases/
      2、redis的tar包上传到linux
      3、解压
      	tar -zxf redis-2.8.18.tar.gz
      	cd redis-2.8.18
      4、安装gcc、tcl
      	到此处:https://opsx.alibaba.com/mirror?lang=zh-CN
          
      	shell> curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
      	shell> yum clean all
      	shell> yum makecache
      	shell> yum install gcc tcl -y
      	编译redis源码
      	shell> make MALLOC=libc
      	安装:           指定安装路径
      	shell> make install PREFIX=/opt/redis
      配置环境变量
      	export REDIS_HOME=/opt/redis
      	export PATH=$PATH:$REDIS_HOME/bin
      安装redis服务:
      	cd /root/redis-2.8.18/utils
      	./install_server.sh
      	
      	Port           : 6379
      	Config file    : /etc/redis/6379.conf
      	Log file       : /var/log/redis_6379.log
      	Data dir       : /var/lib/redis/6379
      	Executable     : /opt/redis/bin/redis-server
      	Cli Executable : /opt/redis/bin/redis-cli
      
      	
      	
      	Port           : 9000
      	Config file    : /opt/redis/myconf
      	Log file       : /opt/redis/mylog
      	Data dir       : /opt/redis/mydata
      	Executable     : /opt/redis/bin/redis-server
      	Cli Executable : /opt/redis/bin/redis-cli
      
    3. 五种数据类型的操作
      . 1. 字符串的增删改查

      #增加一个key为ay_key的值
      127.0.0.1:6379> set ay_key "ay"
      OK
      #查询ay_key的值
      127.0.0.1:6379> get ay_key
      "ay"
      #修改ay_key的值
      127.0.0.1:6379> set ay_key "new_ay"
      OK
      127.0.0.1:6379> get ay_key
      "new_ay"
      #修改ay_key名称
      127.0.0.1:6379> rename ay_key new_ay_key
      OK
      127.0.0.1:6379> keys *
      1) "new_ay_key"
      #删除ay_key
      127.0.0.1:6379> del ay_key
      (integer) 0
      #查询是否存在ay_key 0
      127.0.0.1:6379> exists ay_key
      (integer) 0
      
      1. Set集合的增删改查

        #删除当前选择数据库中的所有key
        127.0.0.1:6379> flushdb
        OK
        #生成set集合,添加4个数据
        127.0.0.1:6379> sadd set_ay_key "ay" "al" "xy" "xl"
        (integer) 4
        #查询set里面所有值
        127.0.0.1:6379> smembers set_ay_key
        1) "xy"
        2) "al"
        3) "ay"
        4) "xl"
        #删除value为"xl" , 返回 1 如果没有返回 0
        127.0.0.1:6379> srem set_ay_key "xl"
        (integer) 1
        127.0.0.1:6379> smembers set_ay_key
        1) "xy"
        2) "al"
        3) "ay"
        #添加value为"xl"
        127.0.0.1:6379> sadd set_ay_key "xl"
        (integer) 1
        127.0.0.1:6379> smembers set_ay_key
        1) "xy"
        2) "al"
        3) "ay"
        4) "xl"
        #添加value为"xl" 添加不进去,但也不报错,set是不允许重复的
        127.0.0.1:6379> sadd set_ay_key "xl"
        (integer) 0
        #不多解释
        127.0.0.1:6379> sadd set_ay_key "xl"
        (integer) 0
        #不多解释
        127.0.0.1:6379> sadd set_ay_key "xl"
        (integer) 0
        
      2. List集合的增删改查

        #添加key为list_ay_key的list集合
        127.0.0.1:6379> lpush list_ay_key "ay" "al" "xy" "xl"
        (integer) 4
        #查询key为list_ay_key的集合
        127.0.0.1:6379> lrange list_ay_key 0 -1
        1) "xl"
        2) "xy"
        3) "al"
        4) "ay"
        #往list尾部添加元素
        127.0.0.1:6379> rpush list_ay_key "together"
        (integer) 5
        #往list头部添加元素
        127.0.0.1:6379> lpush list_ay_key "first"
        (integer) 6
        #查询list集合
        127.0.0.1:6379> lrange list_ay_key 0 -1
        1) "first"
        2) "xl"
        3) "xy"
        4) "al"
        5) "ay"
        6) "together"
        #更新index为0的值  
        127.0.0.1:6379> lset list_ay_key 0 "update_first"
        OK
        127.0.0.1:6379> lrange list_ay_key 0 -1
        1) "update_first"
        2) "xl"
        3) "xy"
        4) "al"
        5) "ay"
        6) "together"
        #删除index为1上的值
        127.0.0.1:6379> lrem list_ay_key 1 "update_first"
        (integer) 1
        127.0.0.1:6379> lrange list_ay_key 0 -1
        1) "xl"
        2) "xy"
        3) "al"
        4) "ay"
        5) "together"
        
      3. Hash集合(一个key连着一个map)的增删改查

        127.0.0.1:6379> flushdb
        OK
        #生成hash集合,并添加key 为uuid_one value 为"12345"
        127.0.0.1:6379> hset hash_ay_key "uuid_one" "12345"
        (integer) 1
        127.0.0.1:6379> hlen hash_ay_key
        (integer) 1
        #返回集合所有的key
        127.0.0.1:6379> hkeys hash_ay_key
        1) "uuid_one"
        #返回集合所有value
        127.0.0.1:6379> hvals hash_ay_key
        1) "12345"
        #集合添加值
        127.0.0.1:6379> hset hash_ay_key "uuid_two" "22222"
        (integer) 1
        #集合添加值
        127.0.0.1:6379> hset hash_ay_key "uuid_three" "33333"
        (integer) 1
        #获得key为uuid_one的值
        127.0.0.1:6379> hget hash_ay_key uuid_one
        "12345"
        #删除key为uuid_three的值
        127.0.0.1:6379> hdel hash_ay_key uuid_three
        (integer) 1
        127.0.0.1:6379> hkeys hash_ay_key
        1) "uuid_one"
        2) "uuid_two"
        #获得所有,包括key和value
        127.0.0.1:6379> hgetall hash_ay_key
        1) "uuid_one"
        2) "12345"
        3) "uuid_two"
        4) "22222"
        #更新key为uuid_one的值
        127.0.0.1:6379> hset hash_ay_key uuid_one "11111"
        (integer) 0
        127.0.0.1:6379> hset hash_ay_key "uuid_one" "11111"
        (integer) 0
        127.0.0.1:6379> hgetall hash_ay_key
        1) "uuid_one"
        2) "11111"
        3) "uuid_two"
        4) "22222"
        
      4. SortedSet集合(有序的set)的增删改查

      #sorted set添加值ay 排序值为 1
      127.0.0.1:6379> zadd zset_ay_key 1 "ay"
      (integer) 1
      127.0.0.1:6379> zadd zset_ay_key 2 "al"
      (integer) 1
      127.0.0.1:6379> zadd zset_ay_key 3 "xy"
      (integer) 1
      127.0.0.1:6379> zadd zset_ay_key 4 "xl"
      (integer) 1
      #查询所有的值
      127.0.0.1:6379> zrange zset_ay_key 0 -1
      1) "ay"
      2) "al"
      3) "xy"
      4) "xl"
      #删除所有的值
      127.0.0.1:6379> zrem zet_ay_key "xl"
      (integer) 0
      127.0.0.1:6379> zrange zset_ay_key 0 -1
      1) "ay"
      2) "al"
      3) "xy"
      4) "xl"
      
      

      什么是持久化

      ​ 将数据从掉电易失的内存存放到能够永久存储的设备上(Redis是存储在内存中的数据库)

      Redis为什么需要持久化

      ​ 基于内存的,机器断电后数据会丢失,为了保证数据的可靠,需要持久化存储

      ​ 缓存服务器,不需要

      ​ 内存数据库,需要

      ​ 消息队列,需要

      Redis持久化方式

      • RDB(Redis DB)–> hdfs: fsimage (只记录数据)
      • AOF(AppendOnlyFile)–> hdfs : edit logs 关闭的 (记录操作语句,比RDB大)

      RDB

      在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中

      方式:产生一个RDB:

      ​ a. 阻塞方式:客户端中执行save命令 (不要用save,会阻塞,用bgsave)

      ​ b. 非阻塞方式:(复杂度高?)bgsave

      策略

      ​ 自动:按照配置文件中的条件满足就执行BGSAVE

      ​ save 60 1000,Redis要满足在60秒内至少有1000个键被改动,会自动保存一次

      ​ 手动:客户端发起SAVE、BGSAVE命令

      SAVE命令

      ​ redis > save

      阻塞Redis服务,无法响应客户端请求

      ​ 创建新的dump.rdb替代旧文件

      BGSAVE命令()

      redis > bgsave

      非阻塞,Redis服务正常接收处理客户端请求

      Redis会fork()一个新的子进程来创建RDB文件,子进程处理完后会向父进程发送一个信号,通知它处理完毕

      父进程用新的dump.rdb替代旧文件

      BGSAVE是一个异步命令

      fork():copy on write -->写时拷贝

      子进程内存中存储父进程内实时内存的指向,不必开辟真实800G的内存占用

      父进程不会阻塞,如果客户端修改了父进程的内存,阻塞(cow):父进程的值,会在子进程中开辟(旧的)。父进程才真正修改。阻塞是很小。

      小的窗口:9:00 BGSAVE 10:00完成,持久化数据存储的是9:00

      SAVE 和 BGSAVE 命令对比

      SAVE不用创建新的进程,速度略快

      BGSAVE需要创建子进程,消耗额外的内存

      SAVE适合停机维护,服务低谷时段

      BGSAVE适合线上执行

      自动执行

      本质上就是BGSAVE

      默认配置

      save 900 1

      save 300 10

      save 60 10000

      dbfilename dump.rdb

      dir /var/lib/redis/6379

      只要上面三个条件满足一个,就自动执行备份。

      创建RDB文件之后,时间计数器和次数计数器会清零。所以多个条件的效果不是叠加的

      RDB的优缺点

      优点

      完全备份,不同时间的数据集备份可以做到多版本恢复

      紧凑的单一文件,方便网络传输,适合灾难恢复

      恢复大数据集速度较AOF快

      缺点

      会丢失最近写入、修改的而未能持久化的数据

      fork过程非常耗时,会造成毫秒级不能响应客户端请求

      RDB生产环境

      创建一个定时任务cron job,每小时或者每天将dump.rdb复制到指定目录

      确保备份文件名称带有日期时间信息,便于管理和还原对应的时间点的快照版本

      定时任务删除过期的备份

      如果有必要,跨物理主机、跨机架、异地备份

      AOF

      Append only file,采用追加的方式保存

      默认文件appendonly.aof

      记录所有的写操作命令,在服务启动的时候使用这些命令就可以还原数据库

      调整AOF持久化策略,可以在服务出现故障时,不丢失任何数据,也可以丢失一秒的数据。相对于RDB损失小得多

      AOF写入机制

      AOF方式不能保证绝对不丢失数据

      目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是先将内容放入一个内存缓冲区(buffer)里面,等到缓冲区被填满,或者用户执行fsync调用和fdatasync调用时才将储存在缓冲区里的内容真正的写入到硬盘里,未写入磁盘之前,数据可能会丢失

      写入磁盘的策略

      appendfsync选项,这个选项的值可以是always、everysec或者no

      always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据

      everysec(默认):服务器每一秒重调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据

      no:服务器不主动调用fdatasync,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的

      运行速度:always的速度慢,everysec和no都很快

      AOF文件优化 (重写机制 合并)

      原有AOF文件 重写后的AOF文件
      SELECT 0 SELECT 0
      SADD fruits “apple” SADD fruits “apple” “banana” “cherry”
      SADD fruits “banana” SET msg “hello world again!”
      SADD fruits “cherry” RPUSH lst 3 5 7
      SADD fruits “apple”
      INCR counter
      INCR counter
      DEL counter
      SET msg “hello world”
      SET msg “hello world again!”
      RPUSH lst 1 3 5
      RPUSH lst 7
      LPOP lst

      AOF重写机制

      AOF文件过大

      合并重复的操作,AOF会使用尽可能少的命令来记录

      重写过程

      1、执行AOF重写请求

      2、父进程执行fork创建子进程,开销等同于bgsave过程

      3.1、主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区,并根据appendfsync策略同步到磁盘,保证原有AOF机制正确性。

      3.2、由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。

      4、子进程根据内存快照,按照命令合并规则写入到新AOF文件。每次批量写入硬盘数据量由aof-rewrite-incremental-fsync控制,默认是32MB,防止单词刷盘数据过多造成硬盘阻塞。

      5.1、新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。

      5.2、父进程把AOF重写缓冲区数据写入到新的AOF文件。

      5.3、使用新AOF文件替换老文件,完成AOF重写。

      注:如果写入操作的时候出现故障导致命令写半截,可以使用redis-check-aof工具修复

      AOF重写触发

      手动:客户端向服务器发送BGREWRITEAOF命令

      自动:配置文件中的选项,自动执行BGREWRITEAOF命令

      • auto-aof-rewrite-min-size <size>,触发AOF重写所需的最小体积:只要在AOF文件的体积大于等于size时,才会考虑是否需要进行AOF重写,这个选项用于避免对体积过小的AOF文件进行重写死循环
    • auto-aof-rewrite-percentage <percent>,指定触发重写所需的AOF文件体积百分比:当AOF文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的AOF文件体积的percent %时,就会触发AOF重写。(如果服务器刚刚启动不久,还没有进行过AOF重写,那么使用服务器启动时载入的AOF文件的体积来作为基准值)。将这个值设置为0表示关闭自动AOF重写

    AOF重写配置项举例

    auto-aof-rewrite-percentage 100:只有当AOF文件的增量大于起始size的100%时(就是文件大小翻了一倍),启动重写

    auto-aof-rewrite-min-size 64mb:当AOF文件大于64MB时候,可以考虑重写AOF文件

    appendonly no / yes:默认关闭(no),请开启(yes)

    AOF优缺点

    优点

    • 写入机制,默认fysnc每秒执行,性能很好不阻塞服务,最多丢失一秒的数据
    • 重写机制,优化AOF文件
    • 如果误操作了(FLUSHALL等),只要AOF未被重写,停止服务移除AOF文件尾部FLUSHALL命令,重启Redis,可以将数据集恢复到 FLUSHALL 执行之前的状态

    缺点

    • 相同数据集,AOF文件体积较RDB大了很多
    • 恢复数据库速度比RDB慢(文本,命令重演)
  • 相关阅读:
    [数据结构] N皇后问题
    [2011山东ACM省赛] Sequence (动态规划)
    yaf 学习
    nginx 配置文件
    nginx.conf 理解
    fastcgi
    Nginx+FastCGI运行原理
    ssh-key 原理
    Git是个啥 ssh是个啥
    Git SSH Key 生成步骤
  • 原文地址:https://www.cnblogs.com/ernst/p/12819179.html
Copyright © 2020-2023  润新知