Redis必须会的知识点

Nosql:非关系型数据库
  • 分表分库 + 水平拆分 + mysql集群:

    • 在Memcached的高速缓存,Mysql主从复制、读写分离的基础上,由于MyISAM使用表锁,高并发Mysql应用开始使用InnoDB引擎代替MyISAM。现如今分表分库 + 水平拆分 + mysql集群 已经成为解决缓解写压力和数据增长的问题的热门技术。
  • NoSQL用于超大规模数据的存储。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

  • - 代表着不仅仅是SQL
    - 没有声明性查询语言
    - 没有预定义的模式
    -键 - 值对存储,列存储,文档存储,图形数据库
    - 最终一致性,而非ACID属性
    - 非结构化和不可预知的数据

    - 高性能,高可用性和可伸缩性

    - CAP定理

  • CAP定理:对于一个分布式计算系统来说,不可能同时满足以下三点:

    • 一致性(Consistency) (所有节点在同一时间具有相同的数据)
    • 可用性(Availability) (保证每个请求不管成功或者失败都有响应)
    • 分隔容忍(Partition tolerance) (系统中任意信息的丢失或失败不会影响系统的继续运作)

    ​ CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

    ​ 因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

    • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
    • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。
    • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
  • NoSQL数据模型:

    • 聚合模型:(主要是前两个)
      • KV键值
      • Bson:类似JSON,可以在 Value中放 JSON, 可分可合
      • 列族:每个字段放在一行
      • 图形
  • NoSQL数据库四大分类:

    • KV键值:典型介绍:阿里百度(memcache+redis),美团(redis+tair),新浪(BerkeleyDB+redis)
    • 文档型数据库:bson格式比较多,如MongoDB(基于分布式文件存储数据库)
    • 列存储数据库:分布式文件系统、Cassandra、HBase
    • 图关系数据库:存放关系图,如:朋友圈社交网络、广告推荐系统、社交系统、推荐系统等,专注于构建关系图谱。Neo4J,InfoGrid

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

  • Redis = KV + Cache + persistence
  • 3V+3高:海量Volume、多样Variety、实时Velocity、高并发、高可扩、高性能
  • CAP(与关系型数据库中相对的是ACID)(和ACID都要满足四个条件不同,CAP最多只能三选二)
    • C:Consistency 强一致性。数据强一致性,强实时性
    • A:Avaliability 可用性。可以理解为网站运行的稳定性
    • P:Partition tolerance 分区容错性。(分布式系统必须要实现)
      • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。如Oracle、Mysql
      • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。如MongoDB、HBase、Redis
      • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。大多数网站架构的选择AP+弱一致性

image-20200712132748264

  • BASE(牺牲CAP 中的 C 换取 AP)
    • 基本可用(Basically Available)
    • 软状态(Soft state)
    • 最终一致(Eventually consistent)
  • 分布式 + 集群:
    • 分布式:不同多太服务器上部署不同的服务模块(工程),他们之间通过RPC/Rmi之间通信和调用,对外提供服务和组内工作
    • 集群:不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问
  • Redis支持数据持久化,数据类型包括:KV、list、set、zset、hash等数据结构的存储。Redis支持master-slave模式的数据备份
  • Linux中Redis开启服务:/usr/local/bin/redis-server /opt/myRedis/redis.conf 关闭服务:SHUTDOWN
  • 启动Redis客户端:redis-cli -p 6379; 6379是Redis默认端口 退出:exit 或 ctrl+c
  • ps -ef|grep redis :查看redis服务的是否启动
  • lsof -i :6379 :根据redis 的端口查看redis进程
  • redis默认安装在:/usr/local/bin
    • image-20200712143609109
Redis常用命令
  • Redis默认在redis.conf中配置16个数据库0-15, select 7 :表示使用6号数据库,

  • set 和 get 能存放和取出数据, 其中set key val 时key已经存在,则覆盖

  • keys k* : 查询以 k 开头的键 FLUSH:删除

  • keys * :查询所有key,move k 2:将 k 移动到2号数据库

  • exists key:判断这个key是否在当前数据库中存在

  • expire key 1 : 设置key过期时间为1秒

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

  • type key : 查看key的类型

  • del key:删除key

Redis五大数据类型
  • String:与Memcached一样的类型,即一个key对应一个value。String是二进制安全的,意思是可以包含任何数据类型。value最多可以是512M
    • STRLEN key : 查看key的长度 INCR key:该key的值+1 DECR key则-1
    • INCRBY key 3 和 DECRBY key 3:分别是每次+3和每次-3
    • GETRANGE key 0 -1 : 获取key的value并截取索引长度,0 -1表示截取全部
    • SETRANGE key 0 val: 从该key的value的索引位置0开始插入值 val
    • setex key 10 val : 新增key-val 同时设置过期时间为10
    • setnx key val : 如果该key不存在,则新增key-val ,如果key存在则该命令不生效
    • mset k1 v1 k2 v2 k3 v3: 插入多个数据
    • msetnx k1 v1 k2 v2 k3 v3 :若k1 k2 k3 中有一个已经存在,则全部新增失败
  • Hash:类似Java的Map,是一个String类型的field和value的映射表,hash特别适合用于存储对象
    • HSET user id 11:插入键值对 id-11
    • HGET user id:获取value
    • HMSET user id 11 name lisi age 18:一口气插入 HMGET user id name age
    • HGETALL user:查询所有映射关系
    • HDEL user name:删除
    • HLEN user:长度
    • HEXISTS user id:查询该表的id 这个key是否存在
    • HKEYS user:查询所有key HVALS user:查询所有value
    • HINCRBY user age 2:key为age的value,每次 +2
    • HINCRBYFLOAD user age 0.5:key为age的value,每次 +0.5
    • HSETNX user age 16: 不存在age这个key才插入有效
  • List(列表):底层是个链表,是简单的字符串列表,按照插入顺序排序,可以头插也可以尾插。类似双向循环链表LinkedList
    • LPUSH list01 1 2 3 4 :依次从最左边插入到ilist01,结果为4 3 2 1 , RPUSH同理
    • LRANGE list01 0 -1: 查询 集合 list01所有value,0 和 -1 表示索引位置
    • lpop list01:表示list01的左边作为栈顶出栈一个值,同理rpop表示list01的右边作为栈顶出栈一个值
    • LINDEX list01 3 : 查询列表list01索引3的value
    • LLEN list01 : 列表长度
    • LREM list01 2 3 : 删除2个索引为3的元素
    • LTRAM list01 3 5 : 截取索引为3到5的元素并重新覆盖list01
    • RPOPLPUSH:list01 list02 : 相当于 RPOP list01 的结果 LPUSH 进 list02
    • LSET list01 1 x:从左边起索引为1的位置上插入string类型的 x
    • LINSERT list01 before/after x java:在x的左边/右边插入元素 java
  • Set (集合):是string类型的无序集合,不允许重复,是通过HashTable实现的
    • sadd set01 1 1 2 2 3 3:只添加 1 2 3
    • SMEMBERS set01 0 -1:查询set01集合,也可以用SMEMBERS set01
    • SISMEMBER set01 x:判断x是否存在
    • SCART set01:获取集合的元素个数
    • SREM set01 3:删除集合中值为 ‘3’ 的元素
    • SRANDMEMBER:set01 3 :从set01中随机得到3个元素
    • SPOP set01:随机出栈一个元素
    • SMOVE set01 set02 5:将set01中 5 这个元素移动到set02
    • DEL set01:删除集合
    • SDIFF set01 set02:输出set01中set02所没有的元素,即差集
    • SINTER set01 set02:输出交集
    • SUNION set01 set02:输出并集,
  • Zset (sortedSet有序集合):是string类型的有序集合且不允许重复,每个元素都会关联一个double类型的分数,通过分数从小到大排序。zset成员是唯一的,但分数可以重复
    • ZADD zset01 60 v1 70 v2:60和70表示分数,越小排序越前
    • ZRANGE zset01 0 -1:查询所有 ZRANGE zset01 0 -1 WITHSCOPES:查询所有且带分数
    • ZRANGEBYSCOPE zset01 60 90:查询分数60-90的元素 ZRANGEBYSCOPE zset01 60 (90 : 查询分数60-90的元素但不包含90
    • ZRANGEBYSCOPE zset01 60 90 limit 2 3:从分数60-90的元素中从索引为2的位置截取3个
    • ZREM zset01 v1:删除
    • ZCARD zset01 :查询元素个数 ZCOUNT zset01 60 80:查询分数在60-90元素个数
    • ZRANK zset01 v2:查询元素下标 ZSCOP zset01 v2:查询元素分数
    • ZREVRANK zset01 v2:逆序获得下标值 ZREVRANGE zset01 0 -1:逆序输出
    • ZREVRANGEBYSCOPE zset01 60-90:查询分数60-90的元素并逆序输出
redis.conf
  • redis.conf 默认安装在:/opt/myredis

  • Units单位:配置大小单位,定义了一些基本的度量单位,只支持bytes不支持bit,对大小写不敏感

  • INCLUDES:包含其他配置文件,作为总闸

  • GENERAL:

    • daemonize yes:启用守护进程。设置redis关掉终端后,redis服务和进程还在执行。

    • port 6379:默认端口

    • tcp-backlog 511:配置tcp的backlog ,是一个连接队列,backlog 队列总和=未完成三次握手队列+已经完成三次握手队列,高并发环境下需要一个高backlog 值来避免客户端连接慢问题

    • #bind IP:设置连接的IP

    • timeout 0:设置空闲多少秒后关闭redis连接,0表示一直连接不关闭

    • Tcp-Keepalive:单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置为60,作用类似心跳检测、判断每过一段时间检测是否还存活、使用中

    • loglevel debug/verbose/notice/warning :设置log日志级别,从左到右级别依次变高

    • database 16:设置数据库数量,默认为16

    • Syslog-enabled:是否把日志输出到syslog中,默认不使用

    • Syslog-facility:指定syslog设备,值可以是USER或LOCAL0-LOCAL7

  • SNAPSHOTTING快照(RDB)

    • dbfilename dump.rdb : 默认快照备份的文件为dump.rdb
    • stop-writes-on-bgsave-error yes :默认yes表示备份出错就立即停止写数据。如果配置成no,表示不在乎数据不一致
    • rdbcompression yes : 对于存储到磁盘中的快照,可以设置是否进行压缩存储。默认yes表示采用LZF算法进行压缩 ,会消耗cpu,建议开启
    • rdbchecksum yes: 在存储快照后,可以使用CRC64算法来进行数据检验,但会增大约10%的性能消耗,建议开启
    • dir : 设置快照的备份文件dump.rdb 所在目录,config get dir 可以获得目录
  • REPLICATION复制

  • SECURITY安全:

    • config set requirepass “123456” : 设置密码,此时若直接ping,则会失败,需要先输入密码:auth 123456
    • config get requirepass : 获取密码
  • LIMITS限制:

    • Maxclients:最大同时连接数,默认10000
    • Maxmemory:单位为字节,最大内存
    • Maxmemory-policy:缓存策略。默认是noeviction永不过期策略,但一般不使用该策略
      • image-20200712231742607
      • volatile-lru:使用LRU(最近最少使用)算法移除key,只对设置了过期时间的键
      • allkeys-lru:使用LRU算法移除key
      • volatile-random:在过期集合中移除随机的key,只对设置了过期时间的key
      • allkeys-random:移除随机的key
      • volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
      • noeviction:不进行移除,针对写操作,只是返回错误信息,一般不使用该策略
    • Maxmemory-samples:设置样本数量,LRU算法和最小TTL算法都不是最精确的算法,而是估算值,所以你可以设置样本大小,redis默认会检查这么多个key并选择其中LRU的那个。默认选取5个样本
  • APPEND ONLY MODE追加(AOF)

    • appendonly no : 默认关闭AOF
    • appendfilename “appendonly.aof” :日志记录保存到该文件, 数据修改一次,追加一次日志记录到该文件
    • appendfsync:3中AOF持久化策略
      • aways:同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性较好
      • everysec:出厂默认推荐使用,异步操作,每秒记录,如果一秒内宕机,会有数据丢失。
      • no:从不同步
    • No-appendfsync-on-rewrite:重写时是否可以运用Appendfsync,默认no,保证数据安全性
    • auto-aof-rewrite-percentage 100:百分百情况下AOF文件大小是上次rewrite后大小的一倍
    • auto-aof-rewrite-min-size 64mb:AOF文件大于64M时触发重写机制。实际公司设置 3G 起步
常见redis.conf配置
参数说明
redis.conf 配置项说明如下:
1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
  daemonize no
2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
  pidfile /var/run/redis.pid
3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
  port 6379
4. 绑定的主机地址
  bind 127.0.0.1
5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
  timeout 300
6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
  loglevel verbose
7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
  logfile stdout
8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
  databases 16
9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
  save <seconds> <changes>
  Redis默认配置文件中提供了三个条件:
  save 900 1
  save 300 10
  save 60 10000
  分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
 
10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
  rdbcompression yes
11. 指定本地数据库文件名,默认值为dump.rdb
  dbfilename dump.rdb
12. 指定本地数据库存放目录
  dir ./
13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
  slaveof <masterip> <masterport>
14. 当master服务设置了密码保护时,slav服务连接master的密码
  masterauth <master-password>
15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
  requirepass foobared
16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
  maxclients 128
17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
  maxmemory <bytes>
18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
  appendonly no
19. 指定更新日志文件名,默认为appendonly.aof
   appendfilename appendonly.aof
20. 指定更新日志条件,共有3个可选值: 
  no:表示等操作系统进行数据缓存同步到磁盘(快) 
  always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 
  everysec:表示每秒同步一次(折衷,默认值)
  appendfsync everysec
 
21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
   vm-enabled no
22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
   vm-swap-file /tmp/redis.swap
23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
   vm-max-memory 0
24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
   vm-page-size 32
25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
   vm-pages 134217728
26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
   vm-max-threads 4
27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
  glueoutputbuf yes
28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
  hash-max-zipmap-entries 64
  hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
  activerehashing yes
30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
  include /path/to/local.conf

持久化RDB(Redis DataBase)
  • Redis持久化包含RDB(Redis DataBase)和AOF(Append Only File)

  • RDB:在指定时间间隔内将内存中的数据快照写入磁盘,也就是SnapShot快照,它恢复时是将快照文件直接读到内存里

  • Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。在整个过程中主线程不进行任何IO操作,确保了极高的性能。

  • 如果需要进行大规模数据恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。

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

  • Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是一个全新进程,叫子进程

  • RDB保存的是dump.rdb文件,命令是:save . 默认有以下3种保存策略(可以自定义) , save “” 则是禁用该功能

    • 三个策略分别为:15分钟内改了1次,5分钟内改了10次,1分钟内改了一万次,会触发快照条件从而备份文件,备份文件为dump.rdb
    • image-20200713122608467
  • 可以在任何一个目录下使用redis,所生成的db文件也保存在该目录

  • 一般备份dump.rdb时需要拷贝文件到另外的备机上,以防物理损坏

  • SHUTDOWN关闭redis的同时,默认会commit并备份到dump.rdb中。slushall命令也会产生dump.rdb,但空文件无意义

  • 如何恢复数据?重启服务后,默认会将启动redis的当前目录下的备份文件dump.rdb 恢复到redis数据库中

  • 手动备份命令:save 或者 bgsave。其中save只管保存,其他不管全部阻塞。BGSAVE:表示redis会在后台异步进行快照操作,快照同时还可以响应客户端请求,可以通过lastsave命令获取最后一次成功执行快照的时间。

  • config get dir 可以获得快照的备份文件dump.rdb所在目录

  • 优势:适合大规模数据恢复,对数据完整性和一致性要求不高。

  • 劣势:fork时内存的数据被克隆了一份,大致2倍的膨胀性需要考虑内存空间是否足够大。最后一次备份的数据可能丢失

  • 动态停止所有RDB保存规则命令:redis-cli config set save “”。不建议使用

  • 配置文件里的 SNAPSHOTTING快照(RDB)

    • dbfilename dump.rdb : 默认快照备份的文件为dump.rdb
    • stop-writes-on-bgsave-error yes :默认yes表示备份出错就立即停止写数据。如果配置成no,表示不在乎数据不一致
    • rdbcompression yes : 对于存储到磁盘中的快照,可以设置是否进行压缩存储。默认yes表示采用LZF算法进行压缩 ,会消耗cpu,建议开启
    • rdbchecksum yes: 在存储快照后,可以使用CRC64算法来进行数据检验,但会增大约10%的性能消耗,建议开启
    • dir : 设置快照的备份文件dump.rdb 所在目录,config get dir 可以获得目录
  • image-20200713131151648

持久化AOF(Append Only File)
  • AOF是在RDB之后产生,是以日志的形式记录每个写操作,将Redsi执行过的所有写指令记录,只需追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。换言之,redis重启时会根据日志文件的内容将写指令从头到尾执行一次以完成数据的恢复工作

  • AOF也是启动redis后自动执行日志文件appendonly.aof 从而恢复数据。

  • /usr/local/bin/redis-server /myredis/redis_aof.conf :启动Redis服务并以aof文件恢复数据

  • dump.rdb和 appendonly.aof 可以同时存在,先加载appendonly.aof,若aof文件中有记录是错的,开启redis服务会失败。此时在redis的bin目录下使用命令:redis-check-aof --fix appendonly.aof 可查看appendonly.aof 的错误信息并消除其中的不规范指令,才能启动redis服务

  • appendonly.aof 因为只追加写操作记录,因此容易内存膨胀,free命令用于查看内存使用情况,df -h 查看磁盘空间

  • Rewrite:

    • AOF的重写机制,当AOF文件大小超过所设定的阈值时,会启动AOF文件的内容压缩,只保留可以不恢复数据的最小指令集,可以使用命令bgrewriteaof

    • 原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方法重写了一个新aof文件,类似快照。

    • 触发机制:redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

  • (优势)对应在redis.conf 的配置:APPEND ONLY MODE追加(AOF)

    • appendonly no : 默认关闭AOF
    • appendfilename “appendonly.aof” :日志记录保存到该文件, 数据修改一次,追加一次日志记录到该文件
    • appendfsync:3中AOF持久化策略
      • aways:同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性较好
      • everysec:出厂默认推荐使用,异步操作,每秒记录,如果一秒内宕机,会有数据丢失。
      • no:从不同步
    • No-appendfsync-on-rewrite:重写时是否可以运用Appendfsync,默认no,保证数据安全性
    • auto-aof-rewrite-percentage 100:百分百情况下AOF文件大小是上次rewrite后大小的一倍
    • auto-aof-rewrite-min-size 64mb:AOF文件大于64M时触发重写机制。实际公司设置 3G 起步
  • 劣势:相同数据集的数据而言aof文件远大于rdb文件,恢复速度慢于rdb。运行效率也慢,但每秒同步策略效率较好,不同步效率和rdb相同

  • 如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

    如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构

Redis事务
  • 可以一次执行多个命令,本质是一组命令的集合,一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞

  • 能干嘛?开启事务后每个指令都会加入一个队列中,一次性、顺序性、排他性地执行一系列命令

  • 常用命令

    • DISCARD:取消事务,放弃执行事务块内的所有命令
    • EXEC:执行所有事务块的命令,执行之后会一次性显示该次事务块中所有命令的结果
    • MULTI:标记一个事务块的开始
    • UNWATCH:取消WATCH命令对所有key的监视
    • WATCH key [key…] :类似乐观锁,监视一个或多个key,如果在事务EXEC执行之前这些key被其他命令所改动,那么事务将被打断,该事务提交无效
  • 若事务块中有无效命令(错误指令)则全部命令不生效,若事务块中都是有效命令但有些命令无法执行成功,则只有这些命令执行失败,其他命令无影响

  • watch监控

    • 事务提交时,如果key已被其他客户端改变,那么整个事务队列都不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败
    • 乐观锁(常用):开启WATCH后,若有命令要修改数据,则在要修改的该行数据加一个版本号version,每次修改完成后缓存中该行的version+1,当另一个修改该行的请求所带的版本不高于缓存中version,则会报错。此时需要重新从缓存中获取最新数据后再修改才能提交成功
    • 悲观锁(不常用):认为每次修改数据都会觉得会有别的请求也要修改,因此锁整张表
    • 一旦执行了exec,之前加的监控锁都会被取消掉
    • CAS(Check And Set) :
  • 事务3阶段:MULTI开启事务=》命令入队,此时还未被执行=》EXEC执行,触发事务

  • 事务3特性:

    • 单独的隔离操作:食物中的所有命令都会被序列化、按顺序执行,事务执行过程中不会被其他客户端的命令请求打断
    • 没有隔离级别的概念:因为事务提交前任何指令都不会被实际执行
    • 不保证原子性;同一事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
发布订阅机制
  • 进程间的一种消息通信模式:发送者(pub)发布消息,订阅者(sub)接收消息

  • 一次性订阅多个: SUBSCRIBE c1 c2 c3 c*

  • 消息发布: PUBLISH c2 hello-redis

主从复制(Master/Slave)
  • 配从机(库)布配主机(库)
  • 从库配置:slaveof 主库IP 主库端口
  • 配置从库时需修改配置文件,需修改:端口号、进程号pidfile、日志logfile、RDB快照文件dbfilename
  • 通常主从复制有4招(一般都用哨兵模式)
    • 一主二仆:一个主机2个从机
    • 薪火相传:主=》从=》从。。。。若中途变更转向,会清除之前的数据,重新建立拷贝最新的数据. 命令:Slaveof 新主库IP 新主库端口
    • 反客为主: SLAVEOF no one:使当前数据库停止与其他数据库的同步,转为主数据库
    • 哨兵模式
  • info replication可以查看当前redis的详细信息,也可查看是主库还是从库
  • 读写分离:默认只有主机可以写,从机只能读
  • 默认当主机宕机或关闭Redis服务后,其他从机还是从机,即原地待命
  • 当从机宕机或关闭Redis服务,重新启动Redis后,需要重新连接主库,除非redis.conf 已经有配置
  • Slave启动成功连接到master后会发送一个sync命令
哨兵模式
  • 反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

  • 使用步骤:

    • 自定义/myRedis目录下新建 sentinel.conf
    • 配置主机监控:sentinel monitor host6379 127.0.0.1 6379 1
    • 最后的数字1表示主机挂掉后slave投票,得票数的多少后成为主机
    • 启动哨兵:redis-sentinel /opt/myRedis/sentinel.conf
    • 当旧主机修复后重新启动,此时哨兵监控到后会将该旧主机转换为新主库的从库
  • 一组sentinel能同时监控多个master

  • 复制的缺点:由于写操作都是现在Master进行,然后同步更新到slave上,所以主库同步到从库有一定延迟,Slave数量增加,延迟会更加严重

Java使用Redis
  • 连接使用
	public static void main(String[] args) {
		Jedis jedis = new Jedis("127.0.0.1", 6379);
		jedis.set("k1", "v1");
		System.out.println(jedis.ping());
		Set<String> keys = jedis.keys("*");
	}
  • 事务
	public static void main(String[] args) {
		Jedis jedis = new Jedis("127.0.0.1", 6379);
		Transaction transaction = jedis.multi();
		//transaction.discard(); // 事务取消
		transaction.exec();
	}

  • 事务-watch监控-加锁
public class TestTransaction {
 
  public boolean transMethod() {
     Jedis jedis = new Jedis("127.0.0.1", 6379);
     int balance;// 可用余额
     int debt;// 欠额
     int amtToSubtract = 10;// 实刷额度
 
     jedis.watch("balance");
     //jedis.set("balance","5");//此句不该出现。模拟其他程序已经修改了该条目
     Thread.sleep(7000); // 延时7秒,模拟高并发或网络延迟,在7秒的过程中有其它程序改变了balance
     balance = Integer.parseInt(jedis.get("balance"));
     if (balance < amtToSubtract) {
       jedis.unwatch();
       System.out.println("modify");
       return false;
     } else {
       System.out.println("***********transaction");
       Transaction transaction = jedis.multi();
       transaction.decrBy("balance", amtToSubtract);
       transaction.incrBy("debt", amtToSubtract);
       transaction.exec();
       balance = Integer.parseInt(jedis.get("balance"));
       debt = Integer.parseInt(jedis.get("debt"));
 
       System.out.println("*******" + balance);
       System.out.println("*******" + debt);
       return true;
     }
  }
 
  /**
   * 通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中
   * 重新再尝试一次。
   * 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
   * 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
   */
  public static void main(String[] args) {
     TestTransaction test = new TestTransaction();
     boolean retValue = test.transMethod();
     System.out.println("main retValue-------: " + retValue);
  }
}
  • 主从复制(配从不配主)
public static void main(String[] args) throws InterruptedException 
  {
     Jedis jedis_M = new Jedis("127.0.0.1",6379);
     Jedis jedis_S = new Jedis("127.0.0.1",6380);
     
     jedis_S.slaveof("127.0.0.1",6379);
     
     jedis_M.set("k6","v6");
     Thread.sleep(500);
     System.out.println(jedis_S.get("k6"));
  }
JedisPool(最常用)
  • JedisPoolUtil
public class JedisPoolUtil {
  private static volatile JedisPool jedisPool = null;//被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
  private JedisPoolUtil() {}  // 单例模式,构造方法私有化,无法new该实例对象
  
  public static JedisPool getJedisPoolInstance() // 对外提供获得单实例JedisPool的方法
 {
     if(null == jedisPool)
    {
       synchronized (JedisPoolUtil.class) // 单例模式的双重校验锁
      {
          if(null == jedisPool) 
         {
           JedisPoolConfig poolConfig = new JedisPoolConfig();
// pool可分配的jedis实例,pool.getResource()获取;如果为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态exhausted。
           poolConfig.setMaxActive(1000); 
           // 控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
           poolConfig.setMaxIdle(32);
           // 表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
           poolConfig.setMaxWait(100*1000);  
           // 获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;
           poolConfig.setTestOnBorrow(true); 

           jedisPool = new JedisPool(poolConfig,"127.0.0.1");
         }
      }
    }
     return jedisPool;
 }
  
  public static void release(JedisPool jedisPool,Jedis jedis)
 {
     if(null != jedis)
    {
      jedisPool.returnResourceObject(jedis);
    }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值