Redis超详细学习

一、Redis入门

Redis是什么?

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2010年5月开始,Redis的开发由Pivotal赞助。免费和开源!是当下最热门的NoSQL技术之一!也被人们称为结构化数据库!–摘自百度百科

Redis能干嘛?

  1. 内存存储、持久化,内存中是断电即失,所以说持久化很重要(rdb、aof),RDB、AOF的区别

  2. 效率高,可以用于高速缓存

  3. 发布订阅系统

  4. 地图信息分析

  5. 计时器、计数器(浏览量)

特性

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

学习资料

Redis中文网

Redis官方网站

B站狂神–Redis篇

Redis推荐在Linux系统上安装使用

二、在Windows系统下安装

  1. 下载安装包:http://github.com/dmajkic/redis/releases
  2. 下载完毕得到安装包

  1. 解压到自己电脑的环境目录下就可以了

  2. 开启Redis,双击运行即可

  3. 使用redis客户端连接redis

Windows系统下安装使用十分方便,但是推荐Redis推荐我们使用Linux去开发并使用

三、在Linux系统下安装

  1. 官网下载安装包

  1. 将这个压缩包用ftp传输到linux服务器的opt目录下

  1. 解压Redis安装包!

​ 解压完成:

  1. 进入redis-6.0.6文件夹

  1. 装载环境
yum install gcc-c++makemake install

如果安装不成功就是redis版本和gcc版本问题了

  1. redis的默认安装路径是:/usr/local/bin

  1. 创建一个文件夹,将redis的配置文件移动到该文件夹
mkdir lconfigcp /opt/redis-6.0.6/redis.conf lconfig
redis.conf(我们之后使用这个配置文件进行启动)

  1. redis默认不是后台启动,先修改配置文件

    vim redis.conf
    

  1. 启动redis服务

  1. 客户端redis-cli连接测试

11.查看redis的进程是否开启(开一个新会话查看)

12.关闭redis服务

四、测试性能工具

redis-benchmark是一个压力测试工具,官方自带的性能压力测试工具。

Redis 性能测试

redis-benchmark命令参数:

五、redis的基础知识

5.1、redis默认有16个数据库:

默认使用的是第0个数据库

可以使用select进行切换数据库:

#查看数据库所有的key
127.0.0.1:6379[3]> keys *
1) "name"#清空当前数据库
127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)#清空所有的数据库
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name lxf
OK
127.0.0.1:6379> set sex 男
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> FLUSHALL
OK
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> keys *
(empty array)

基本使用:

127.0.0.1:6379> set name lys
OK
127.0.0.1:6379> get name
"lys"
127.0.0.1:6379> EXISTS name #判断name是否存在
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 1 #移除name
(integer) 1
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name lxf
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> EXPIRE name 10 #设置name过期时间(秒)
(integer) 1
127.0.0.1:6379> ttl name #查看name还有多久过期
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name #name已经过期
(nil)127.0.0.1:6379> set age 13
OK
127.0.0.1:6379> set name lxf
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> type name #查看name是什么类型的
string
127.0.0.1:6379> type age
string

所有命令:

Redis命令中心

5.2、Redis介绍

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询. Redis 内置了 复制(replication), LUA脚本(Lua scripting), LRU驱动事件(LRU eviction), 事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel) 和自动 分区(Cluster)提供高可用性(high availability)

六、五大数据类型

6.1、String(字符串类型)

常规key-value缓存应用:微博数,粉丝数等。

127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获取值
"v1"
127.0.0.1:6379> keys *
1) "key1"127.0.0.1:6379> exists key1 #判断key1是否存在
(integer) 1127.0.0.1:6379> append key1 hello #给key1增加一段字符串
(integer) 7
127.0.0.1:6379> get key1
"v1hello"127.0.0.1:6379> strlen key1 #获取字符串的长度
(integer) 7127.0.0.1:6379> append key1 ,redis
(integer) 13
127.0.0.1:6379> get key1
"v1hello,redis"127.0.0.1:6379> append name "zhangsan "#如果name不存在等于新建了一个key叫zhangsan
(integer) 9
127.0.0.1:6379> get name
"zhangsan "127.0.0.1:6379> set age 3
OK
127.0.0.1:6379> del age #删除一个key
(integer) 1
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> set views 0 #浏览量
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #浏览量加一
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"127.0.0.1:6379> decr views #浏览量减一
(integer) 1
127.0.0.1:6379> get views
"1"127.0.0.1:6379> incrby views 10 #浏览量增10
(integer) 11
127.0.0.1:6379> get views
"11"127.0.0.1:6379> decrby views 5 #浏览量减5
(integer) 6
127.0.0.1:6379> get views
"6"127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set key1 "hello redis"
OK
127.0.0.1:6379> get key1
"hello redis"
127.0.0.1:6379> getrange key1 0  5 #获取字符串的前6个字符
"hello "
127.0.0.1:6379> getrange key1 0 -1 #获取字符串的所有字符
"hello redis"127.0.0.1:6379> set key2 a1cdefg
127.0.0.1:6379> setrange key2 1 xx #字符串区间替换
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"127.0.0.1:6379> setex key4 20 wan #创建一个值并设置它的过期时间
OK
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> ttl key4
(integer) 9
127.0.0.1:6379> get key4
"wan"127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "k3"
127.0.0.1:6379> setnx k2 hhh  #如果这个值不存在则创建,如果存在则不做操作
(integer) 0
127.0.0.1:6379> setnx k4 hhh
(integer) 1
127.0.0.1:6379> get k4
"hhh"127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #设置多个键值对
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"127.0.0.1:6379> mget k1 k2 k3 #获取多个值
1) "v1"
2) "v2"
3) "v3"127.0.0.1:6379> msetnx k3 v33 k4 v4 #设置多个键值对,并且key不存在(原子性操作)
(integer) 0
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"#存储对象
127.0.0.1:6379> mset user:1:name lxf user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "lxf"
2) "2"
127.0.0.1:6379> keys *
1) "k1"
2) "user:1:age"
3) "k2"
4) "user:1:name"
5) "k3"#先获取再设置
127.0.0.1:6379> getset key5 whh
(nil)
127.0.0.1:6379> get key5
"whh"
127.0.0.1:6379> getset key5 hww
"whh"
127.0.0.1:6379> get key5
"hww"

6.2、List(列表)

Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部

添加或者删除元素,这样List即可以作为栈,也可以作为队列

127.0.0.1:6379> lpush list one two three #从左插入列表数据
(integer) 3
127.0.0.1:6379> lrange list 0 -1 #展示全部数据
1) "three"
2) "two"
3) "one"127.0.0.1:6379> lrange list 0 0 #展示第一个数据
1) "three"
127.0.0.1:6379> lset list 0 zero #设置第一个数据为0(有值则更新,无值则报错)
OK
127.0.0.1:6379> lrange list 0 -1
1) "zero"
2) "two"
3) "one"127.0.0.1:6379> rpush list four #从右插入一个数
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "zero"
2) "two"
3) "one"
4) "four"127.0.0.1:6379> lpop list #从左边移除一个数
"zero"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "four"127.0.0.1:6379> rpop list #从有右移除一个数
"four"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"127.0.0.1:6379> lindex list 0 #通过下标获取一个值
"two127.0.0.1:6379> llen list #显示list的长度
(integer) 2127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "six"
3) "five"
4) "two"
5) "one"
127.0.0.1:6379> lrem list 2 five #移除重复的两个five
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "six"
2) "two"
3) "one"127.0.0.1:6379> lrange list 0 -1
1) "six"
2) "two"
3) "one"
127.0.0.1:6379> ltrim list 1 1 #截取区间的值
OK
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"127.0.0.1:6379> lpush list three four five
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
127.0.0.1:6379> rpoplpush list ortherlist #将一个list的最后一个值另一个list中
"two"
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
127.0.0.1:6379> lrange ortherlist 0 -1
1) "two"127.0.0.1:6379> rpush mylist hello
(integer) 1
127.0.0.1:6379> rpush mylist redis
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "redis"
127.0.0.1:6379> linsert mylist after "hello" "my" #在指定值后面插入一个值(与之对应:before)
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "my"
3) "redis"

6.3、Set(集合)

在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为

集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功

127.0.0.1:6379> sadd myset "hello" #myset集合中添加一个值
(integer) 1
127.0.0.1:6379> sadd myset "redis"
(integer) 1
127.0.0.1:6379> sadd myset "!"
(integer) 1127.0.0.1:6379> smembers myset #查看myset集合中所有的值
1) "!"
2) "redis"
3) "hello"127.0.0.1:6379> SISMember myset hello #判断myset集合中是否包含一个值
(integer) 1
127.0.0.1:6379> SISMember myset hel
(integer) 0127.0.0.1:6379> scard myset #获取myset集合中的元素个数
(integer) 3127.0.0.1:6379> srem myset "hello" #删除myset集合中的一个元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "!"
2) "redis"127.0.0.1:6379> srandmember myset  #随机一个元素
"!"
127.0.0.1:6379> srandmember myset 2 #随机指定个数元素
1) "redis"
2) "!"127.0.0.1:6379> sadd myset my
(integer) 1
127.0.0.1:6379> spop myset #随机移除一个元素
"my"
127.0.0.1:6379> sadd myset a b c d e f
(integer) 6
127.0.0.1:6379> spop myset 2#随机移除指定个数元素
1) "b"
2) "c"127.0.0.1:6379> sadd myset "hello" "my" "redis!"
(integer) 3
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> smove myset myset2 "redis!" #将一个set集合中的元素移到另一个集合中
(integer) 1
127.0.0.1:6379> smembers myset
1) "hello"
2) "my"
127.0.0.1:6379> smembers myset2
1) "set2"
2) "redis!127.0.0.1:6379> sadd set1 a b c
(integer) 3
127.0.0.1:6379> sadd set2 c d e
(integer) 3
127.0.0.1:6379> sdiff set1 set2 #查看差集
1) "a"
2) "b"
127.0.0.1:6379> sinter set1 set2 #查看交集
1) "c"
127.0.0.1:6379> sunion set1 set2 #查看并集
1) "a"
2) "b"
3) "c"
4) "e"
5) "d"

6.4、Hash(哈希)

Map集合、key–>value

hash特别适合用于存储对象。存储部分变更的数据,如用户信息等。

127.0.0.1:6379> hset myhash field1 lxf field2 lys field lss #给hash赋多个key-value
(integer) 3127.0.0.1:6379> hget myhash field2 #获取指定值
"lys"
127.0.0.1:6379> hmset myhash field3 lss field null #设置多个值
OK127.0.0.1:6379> hget myhash field
"null"
127.0.0.1:6379> hmget myhash field3 field2 #获取多个指定值
1) "lss"
2) "lys"127.0.0.1:6379> hgetall myhash #获取多个值
1) "field1"
2) "lxf"
3) "field2"
4) "lys"
5) "field"
6) "null"
7) "field3"
8) "lss"127.0.0.1:6379> hdel myhash field #根据key删除hash指定的key-value
(integer) 1127.0.0.1:6379> hlen myhash #获取myhash中的元素个数
(integer) 3127.0.0.1:6379> hexists myhash field1 #判断myhash中是否含有field1的key
(integer) 1
127.0.0.1:6379> hexists myhash field
(integer) 0127.0.0.1:6379> hkeys myhash #查看所有的key
1) "field1"
2) "field2"
3) "field3"
127.0.0.1:6379> hvals myhash #查看所有的value
1) "lxf"
2) "lys"
3) "lss"127.0.0.1:6379> hgetall myhash1) "field1"2) "lxf"3) "field2"4) "lys"5) "field3"6) "lss"7) "field5"8) "5"9) "field"
10) "0"127.0.0.1:6379> hincrby myhash field5 5 #给field5的value加上5
(integer) 10
127.0.0.1:6379> hincrby myhash field5 -5#给field5的value减去上5
(integer) 5
127.0.0.1:6379> hsetnx myhash field 0#如果field不存在则创建,存在则不做操作
(integer) 0
127.0.0.1:6379> hsetnx myhash field4 4
(integer) 1
127.0.0.1:6379> hgetall myhash1) "field1"2) "lxf"3) "field2"4) "lys"5) "field3"6) "lss"7) "field5"8) "5"9) "field"
10) "0"
11) "field4"
12) "4"#更多操作:
127.0.0.1:6379> hset user:1 name lxf
(integer) 1
127.0.0.1:6379> hget user:1 name
"lxf"

6.5、Zset(有序集合)

和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如

一个存储全班同学成绩的sorted set,其集合value可以是同学的学号,而score就可以是其考试得分,

这样在数据插入集合的时候,就已经进行了天然的排序。可以用sorted set来做带权重的队列,比如普

通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让

重要的任务优先执行。排行榜应用。。。。

127.0.0.1:6379> zadd myset 1 one #增加单个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
127.0.0.1:6379> zadd myset 3 three 4 four
(integer) 2127.0.0.1:6379> zrange myset 0 -1 #增加多个值
1) "one"
2) "two"
3) "three"
4) "four"127.0.0.1:6379> zadd salarys   5000 lys   1000 lrs  3000 lss  10000 lxf
(integer) 4127.0.0.1:6379> zrange salarys 0 -1#递增排序
1) "lrs"
2) "lss"
3) "lys"
4) "lxf"127.0.0.1:6379> zrevrange salarys 0 -1#递减排序
1) "lxf"
2) "lys"
3) "lss"
4) "lrs"127.0.0.1:6379> zrangebyscore salarys -inf +inf #从负无穷到正无穷,递增排序
1) "lrs"
2) "lss"
3) "lys"
4) "lxf"127.0.0.1:6379> zrevrangebyscore salarys +inf -inf #从正无穷到负无穷,递减排序
1) "lxf"
2) "lys"
3) "lss"
4) "lrs"127.0.0.1:6379> zrange salarys 0 -1
1) "lrs"
2) "lss"
3) "lys"
4) "lxf"
127.0.0.1:6379> zrem salarys lys #移除一个元素
(integer) 1
127.0.0.1:6379> zrange salarys 0 -1
1) "lrs"
2) "lss"
3) "lxf"127.0.0.1:6379> zcard salarys #获取有序集合的元素个数
(integer) 3127.0.0.1:6379> zcount salarys 100 5000 #查看区间的元素数
(integer) 2
127.0.0.1:6379> zcount salarys 6000 10000
(integer) 1#更多:http://redis.cn/commands.html#sorted_set

七、三种特殊数据类型

7.1、geospatial地理位置

作用:朋友的定位,附近的人,打车距离,方圆几里的人

查询地区经纬度在线工具

#geoadd 添加地理位置[经度 纬度 名称]
#规则:两极无法直接添加,我们一般会下载城市数据,直接通过java程序直接一次性导入
#有效的经度从-180度到180度。
#有效的纬度从-85.05112878度到85.05112878度。
127.0.0.1:6379> geoadd china:city 116.40 39.90  beijing #添加单个城市的纬经度
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai #上海
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing #重庆
(integer) 1
127.0.0.1:6379> geoadd china:city 114.08 22.54 shenzhen 120.15 30.28 hangzhou 125.14  42.92 xian 119.30 26.07 fuzhou #添加多个城市的纬经度 深圳 杭州 西安 福州
(integer) 4127.0.0.1:6379> geopos china:city beijing #获取单个指定城市的经纬度
1) 1) "116.39999896287918091"2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city chongqing shanghai #获取多个指定城市的经纬度
1) 1) "106.49999767541885376"2) "29.52999957900659211"
2) 1) "121.47000163793563843"2) "31.22999903975783553"

获取两地的距离

如果两个位置之间的其中一个不存在, 那么命令返回空值。

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差

127.0.0.1:6379> geodist china:city chongqing shanghai m #查看重庆到上海的直线距离 单位: m
"1447673.6920"
127.0.0.1:6379> geodist china:city chongqing shanghai km
"1447.6737"
127.0.0.1:6379> geodist china:city chongqing shanghai mi
"899.5450"
127.0.0.1:6379> geodist china:city chongqing shanghai ft
"4749585.6037"

以一个经纬度为中心,找出半径内的所有元素

127.0.0.1:6379> georadius china:city 115 30 1000 km #找出china:city中在(115,30)1000km范围内的元素
1) "shenzhen"
2) "fuzhou"
3) "hangzhou"
4) "shanghai"
5) "chongqing"
127.0.0.1:6379> georadius china:city 115 30 500 km#找出china:city中在(115,30)500km范围内的元素
1) "hangzhou"127.0.0.1:6379> georadius china:city 115 30 500 km withdist #找出china:city中在(115,30)500km范围内的元素,并返回它们之间的距离
1) 1) "hangzhou"2) "496.3065"
127.0.0.1:6379> georadius china:city 115 30 500 km withdist withcoord #找出china:city中在(115,30)500km范围内的元素,并返回它们之间的距离,并且返回它的经纬度
1) 1) "hangzhou"2) "496.3065"3) 1) "120.15000075101852417"2) "30.2800007575645509"
127.0.0.1:6379> georadius china:city 115 30 1000 km count 2#找出china:city中在(115,30)1000km范围内的元素中的两个
1) "hangzhou"
2) "fuzhou"
127.0.0.1:6379> georadius china:city 115 30 1000 km asc#找出china:city中在(115,30)1000km范围内的元素并升序排序
1) "hangzhou"
2) "fuzhou"
3) "shanghai"
4) "chongqing"127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 500 km #以一个城市去找这个城市范围内的元素,也可以排序、输出两地距离、选择输出多少个、输出经纬度
1) "beijing"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1) "beijing"
2) "xian"127.0.0.1:6379> geohash china:city beijing chongqing #将二维的经纬度转换成一维的hash字符串
1) "wx4fbxxfke0"
2) "wm5xzrybty0"

Zset操作Geo实现元素的移除

127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "shenzhen"
3) "fuzhou"
4) "hangzhou"
5) "shanghai"
6) "beijing"
7) "xian"
127.0.0.1:6379> zrem china:city xian #移除西安
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "shenzhen"
3) "fuzhou"
4) "hangzhou"
5) "shanghai"
6) "beijing"

7.2、HyperLogLog(不精确的去重计数)

网页的计算访问量(同一个人访问多次还是算一次)

传统方式:set保存用户的id,然后就可以统计set中的元素数作为标准判断!(如果保存了大量的用户id,就会比较麻烦,我们的目的是计数,而保存用户id就显得赘余了)

HyperLogLog统计优点:占用内存固定,2^64种不同的元素的技术,只需要12KB内存,只需要从内存角度来比较的话Hyperloglog是首选(0.81%的错误率,是可以被接受的)

测试:

127.0.0.1:6379> pfadd mykey a b c d e f g h i j #创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey #打印mykey的元素个数
(integer) 10
127.0.0.1:6379> pfadd mykey2 i j k m n o p #创建第二组元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2 #创建第二组元素 mykey2
(integer) 7
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 #合并第二组元素和第一组元素给mykey3(并集)
OK
127.0.0.1:6379> pfcount mykey3 #看并集的数量
(integer) 15

如果允许容错,那么可以使用hyperloglog

如果不允许容错,就使用set或者自己的数据类型即可

7.3、Bitmaps

位存储

统计用户信息,活跃,不活跃,登录,未登录,打卡。两个状态的都可以使用BitMaps

Bitmaps位图,数据结构,都是操作二进制来进行记录,就只有0和1两种状态

测试:

#0-6:周日到周六 sign:是否打卡 0:未打卡 1:已打卡
127.0.0.1:6379> setbit sign 0 1 #设置第一位为1 已打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0127.0.0.1:6379> getbit sign 0 #获取第一位为1 已打卡
(integer) 1
127.0.0.1:6379> getbit sign 4
(integer) 1
127.0.0.1:6379> getbit sign 5
(integer) 0127.0.0.1:6379> bitcount sign #统计sign中的1的数量
(integer) 4

八、Redis事务

Redis事务本质:一组命令的集合。一个事务中的所有的命令串行化,在事务的执行过程中会按顺序执行!

一次性,顺序性,排他性

Redis事务没有隔离级别的概念

Redis单条命令保存原子性的,但是事务不保存原子性!

redis的事务:

  • 开启事务()
  • 命令入列()
  • 执行事务()

正常执行事务:

127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) "v2"
4) OK

放弃事务

127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k4 k4
QUEUED
127.0.0.1:6379> discard #放弃事务
OK
127.0.0.1:6379> get key4 #事务队列命令都不会被执行
(nil)

编译型异常,事务中所有的命令都不会被执行

127.0.0.1:6379> flushdb
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3  #语句执行出错
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.#事务也报错
127.0.0.1:6379> get v1 #所有的命令都不会被执行
(nil)

运行时异常,如果事务队列中存在语法性问题,那么执行命令的时候,其它命令是可以正常执行的,错误命令抛出异常!

127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1 #语句执行成功
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get v3
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range #这个命令执行报错了,但是下面的命令还是可以执行的
2) OK
3) OK
4) (nil)

监控​watch:

悲观锁:

  • 很悲观,认为大概率会出现问题,无论做什么都会加锁

乐观锁:

  • 很乐观,认为很小概率会出现问题,所以操作的时候直接不加锁,更新数据的时候去做冲突检测
  • 获取version–>更新时比较

正常执行完毕:

127.0.0.1:6379> set money 100 #设置money(存入的钱)为100
OK
127.0.0.1:6379> set out 0     #设置out(取出的钱)为0
OK
127.0.0.1:6379> watch money #监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

重开一个会话叫会话2(连接一个端口):

127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10 #执行到这不继续执行先去原会话操作
QUEUED127.0.0.1:6379> exec #执行完原会话,值已被修改,而且我们的money是被监控的,所以再去执行这里的事务就会失败
(nil)

原会话:

127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1000
OK

测试多会话修改值,使用watch可以当作redis的乐观锁操作。

解锁再加锁:

#事务执行失败之后,先解锁再加锁
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 100
QUEUED
127.0.0.1:6379> incrby out 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 120

九、Jedis(java操作Redis)

Jedis:是Redis官方推荐的java连接开发工具,使用java操作Redis中间件,如果你要使用java操作redis,那么一定要对jedis十分熟悉!

9.1、导入相关的依赖

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.2.0</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version>
</dependency>

9.2、编码测试

  • 连接数据库
  • 操作命令
  • 断开连接
package com.lxf;import redis.clients.jedis.Jedis;public class TestPing {public static void main(String[] args) {//1.new一个jedis对象即可Jedis jedis = new Jedis("127.0.0.1", 6379);//jedis所有的命令就是我们之前学习到的所有命令//测试连接:System.out.println(jedis.ping());}
}

9.3、常用的API

  • key的基本操作:
         //1.new一个jedis对象即可Jedis jedis = new Jedis("127.0.0.1", 6379);//jedis所有的命令就是我们之前学习到的所有命令System.out.println(jedis.ping());System.out.println("清空数据:"+jedis.flushDB());System.out.println("判断username键是否存在:"+jedis.exists("username"));System.out.println("新增<'username','lxf'>的键值对:"+jedis.set("username","lxf"));System.out.println("新增<'password','123'>的键值对:"+jedis.set("password","123"));System.out.println("查看系统中所有的键:");System.out.println(jedis.keys("*"));System.out.println("删除password:"+jedis.del("password"));System.out.println("判断password是否存在:"+jedis.exists("password"));System.out.println("查看username键位存储的类型:"+jedis.type("username"));System.out.println("新增<'age','18'>的键值对:"+jedis.set("age","18"));System.out.println("新增<'birthday','2020-02-02'>的键值对:"+jedis.set("birthday","2020-02-02"));System.out.println("随机返回key空间的一个:"+jedis.randomKey());System.out.println("重命名key:"+jedis.rename("username", "name"));System.out.println("取出修改后的name:"+jedis.get( "name"));System.out.println("按索引查询:"+jedis.select(1));System.out.println("返回当前数据库中所有的key的数目:"+jedis.dbSize());System.out.println("删除所有数据库中的所有key:"+jedis.flushAll());jedis.close();//关闭连接

结果:

PONG
清空数据:OK
判断某个键是否存在:false
新增<'username','lxf'>的键值对:OK
新增<'password','123'>的键值对:OK
查看系统中所有的键:
[password, username]
删除password:1
判断password是否存在:false
查看username键位存储的类型:string
新增<'age','18'>的键值对:OK
新增<'birthday','2020-02-02'>的键值对:OK
随机返回key空间的一个:birthday
重命名key:OK
取出修改后的name:lxf
按索引查询:OK
返回当前数据库中所有的key的数目:0
删除所有数据库中的所有key:OK
  • String:
Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.flushDB();System.out.println("=============增加数据===================");System.out.println(jedis.set("k1", "v1"));System.out.println(jedis.set("k2", "v2"));System.out.println(jedis.set("k3", "v3"));System.out.println(jedis.set("k4", "v4"));System.out.println("=============增加数据===================");System.out.println("删除k2:"+jedis.del("k2"));System.out.println("获取k2:"+jedis.get("k2"));System.out.println("修改k1:"+jedis.set("k1","val1"));System.out.println("获取k1的值:"+jedis.get("k1"));System.out.println("在k1的上再加上值:"+jedis.append("k1",",100"));System.out.println("获取k1的值:"+jedis.get("k1"));System.out.println("增加多个键值对:"+jedis.mset("k5","v5","k6","v6","k7","v7"));System.out.println("获取多个值:"+jedis.mget("k5","k6","k7"));System.out.println("删除多个值:"+jedis.del("k3","k6"));System.out.println("打印所有的key:");System.out.println(jedis.keys("*"));System.out.println("=========================================================");jedis.flushDB();//将数据库清空System.out.println("如果key不存在再添加(存在则不添加):"+jedis.setnx("k1", "v1"));System.out.println("如果key不存在再添加(存在则不添加):"+jedis.setnx("k2", "v2"));System.out.println("如果key不存在再添加(存在则不添加):"+jedis.setnx("k3", "v3"));System.out.println("如果key不存在再添加(存在则不添加):"+jedis.setnx("k3", "vv3"));System.out.println("打印所有的键值对"+jedis.mget("k1","k2","k3"));System.out.println("设置键值对并设置3秒有效时间:"+jedis.setex("k4", 3, "vvvv4"));System.out.println("获取k4的值:"+jedis.get("k4"));try {//线程休眠4秒TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("获取k5的值:"+jedis.get("k4"));System.out.println("设置k5:"+jedis.set("k5", "vvvv5"));System.out.println("获取k5的前4个字符"+jedis.getrange("k5", 0, 3));System.out.println("获取k5的值:"+jedis.get("k5"));System.out.println("替换k4的前2个字符"+jedis.setrange("k5", 0, "xx"));System.out.println("获取k5的值:"+jedis.get("k5"));jedis.close();//关闭连接

结果:

===============添加一个list==============
collections的内容:[TreeSet, HashMap, HashSet, LinkedHashMap, WeakHashMap, HashMap, Stack, Vector, ArrayList, TreeMap]
collections区间0-3的元素:[TreeSet, HashMap, HashSet, LinkedHashMap]
========================================
删除指定元素的个数:2
collections的内容:[TreeSet, HashSet, LinkedHashMap, WeakHashMap, Stack, Vector, ArrayList, TreeMap]
collections列表出栈(左端):TreeSet
collections列表出栈(右端):TreeMap
collections的内容:[HashSet, LinkedHashMap, WeakHashMap, Stack, Vector, ArrayList]
修改collections指定下标1的内容:OK
获取collections的长度:6
获取collections下标为2的元素:WeakHashMap
================================================
sortedList排序前:[10, 2, 5, 9, 6, 3]
[2, 3, 5, 6, 9, 10]
sortedList排序后:[10, 2, 5, 9, 6, 3]
  • List:
Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.flushDB();//清空数据库System.out.println("===============添加一个list==============");//从左插入jedis.lpush("collections", "ArrayList","Vector","Stack","HashMap","WeakHashMap","LinkedHashMap");jedis.lpush("collections","HashSet");jedis.lpush("collections","HashMap");jedis.lpush("collections","TreeSet");//从右插入jedis.rpush("collections","TreeMap");System.out.println("collections的内容:"+jedis.lrange("collections", 0, -1));System.out.println("collections区间0-3的元素:"+jedis.lrange("collections", 0, 3));System.out.println("========================================");System.out.println("删除指定元素的个数:"+jedis.lrem("collections", 2, "HashMap"));System.out.println("collections的内容:"+jedis.lrange("collections", 0, -1));System.out.println("collections列表出栈(左端):"+jedis.lpop("collections"));System.out.println("collections列表出栈(右端):"+jedis.rpop("collections"));System.out.println("collections的内容:"+jedis.lrange("collections", 0, -1));System.out.println("修改collections指定下标1的内容:"+jedis.lset("collections", 1, "HashSet2"));System.out.println("获取collections的长度:"+jedis.llen("collections"));System.out.println("获取collections下标为2的元素:"+jedis.lindex("collections",2));System.out.println("================================================");jedis.lpush("sortedList","3","6","9","5","2","10");System.out.println("sortedList排序前:"+jedis.lrange("sortedList", 0, -1));System.out.println(jedis.sort("sortedList"));jedis.close();//关闭连接

结果:

===============添加一个list==============
collections的内容:[TreeSet, HashMap, HashSet, LinkedHashMap, WeakHashMap, HashMap, Stack, Vector, ArrayList, TreeMap]
collections区间0-3的元素:[TreeSet, HashMap, HashSet, LinkedHashMap]
========================================
删除指定元素的个数:2
collections的内容:[TreeSet, HashSet, LinkedHashMap, WeakHashMap, Stack, Vector, ArrayList, TreeMap]
collections列表出栈(左端):TreeSet
collections列表出栈(右端):TreeMap
collections的内容:[HashSet, LinkedHashMap, WeakHashMap, Stack, Vector, ArrayList]
修改collections指定下标1的内容:OK
获取collections的长度:6
获取collections下标为2的元素:WeakHashMap
================================================
sortedList排序前:[10, 2, 5, 9, 6, 3]
[2, 3, 5, 6, 9, 10]
sortedList排序后:[10, 2, 5, 9, 6, 3]
  • Set
Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.flushDB();//清空数据库System.out.println("===============向集合中添加元素(不重复)==============");System.out.println(jedis.sadd("myset", "e1","e2","e3","e4","e5","e6"));System.out.println(jedis.sadd("myset","e6"));System.out.println("myset的所有元素为:"+jedis.smembers("myset"));System.out.println("删除一个元素e0:"+jedis.srem("myset","e1"));System.out.println("myset的所有元素为:"+jedis.smembers("myset"));System.out.println("删除两个元素e5,e6:"+jedis.srem("myset", "e5","e6"));System.out.println("myset的所有元素为:"+jedis.smembers("myset"));System.out.println("随机删除集合中的一个元素:"+jedis.spop("myset"));System.out.println("myset的所有元素为:"+jedis.smembers("myset"));System.out.println("myset包含元素的个数:"+jedis.scard("myset"));System.out.println("判断myset里是否包含某一元素:"+jedis.sismember("myset","e2"));System.out.println("==========================================");System.out.println(jedis.sadd("eleSet1", "e2","e4","e3","e0","e7","e5"));System.out.println(jedis.sadd("eleSet2", "e1","e5","e10","e3","e0","e8"));System.out.println("eleSet1和eleSet2交集"+jedis.sinter("eleSet1","eleSet2"));System.out.println("eleSet1和eleSet2差集"+jedis.sdiff("eleSet1","eleSet2"));System.out.println("eleSet1和eleSet2并集"+jedis.sunion("eleSet1","eleSet2"));System.out.println("将eleSet1中的e7删除并移入eleSet3中:"+jedis.smove("eleSet1", "eleSet3", "e7"));System.out.println("将eleSet2中的e8删除并移入eleSet1中:"+jedis.smove("eleSet2", "eleSet1", "e8"));System.out.println("eleSet1中的元素:"+jedis.smembers("eleSet1"));System.out.println("eleSet2中的元素:"+jedis.smembers("eleSet2"));System.out.println("eleSet3中的元素:"+jedis.smembers("eleSet3"));jedis.close();//关闭连接

结果:

===============向集合中添加元素(不重复)==============
6
0
myset的所有元素为:[e1, e2, e3, e4, e6, e5]
删除一个元素e0:1
myset的所有元素为:[e2, e3, e4, e6, e5]
删除两个元素e5,e6:2
myset的所有元素为:[e2, e3, e4]
随机删除集合中的一个元素:e4
myset的所有元素为:[e2, e3]
myset包含元素的个数:2
判断myset里是否包含某一元素:true
==========================================
7
6
eleSet1和eleSet2交集[e5, e8, e3, e0]
eleSet1和eleSet2差集[e2, e7, e4]
eleSet1和eleSet2并集[e7, e5, e0, e2, e4, e10, e8, e1, e3]
将eleSet1中的e7删除并移入eleSet3中:1
将eleSet2中的e8删除并移入eleSet1中:1
eleSet1中的元素:[e8, e2, e3, e0, e4, e5]
eleSet2中的元素:[e10, e1, e3, e0, e5]
eleSet3中的元素:[e7]
  • hash
Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.flushDB();HashMap<String, String> map = new HashMap<String, String>();map.put("k1", "v1");map.put("k2", "v2");map.put("k3", "v3");map.put("k4", "v4");map.put("k5", "v5");map.put("k6", "v6");//添加名称为hash(key)的hash元素jedis.hmset("hash",map);//向名称为hash的hash中添加key为key6,value为value6元素jedis.hset("hash", "k6","6");System.out.println("散列hash的所有键值对为:"+jedis.hgetAll("hash"));System.out.println("散列hash的所有key值为:"+jedis.hkeys("hash"));System.out.println("散列hash的所有value值为:"+jedis.hvals("hash"));System.out.println("将k6的值加上4:"+jedis.hincrBy("hash", "k6", 4));System.out.println("散列hash的所有键值对为:"+jedis.hgetAll("hash"));System.out.println("删除一个或者多个键值对:"+jedis.hdel("hash", "k3","k2"));System.out.println("散列hash中的键值对个数:"+jedis.hlen("hash"));System.out.println("判断hash中是否存在k2:"+jedis.hexists("hash", "k4"));System.out.println("获取hash中的单个值:"+jedis.hmget("hash", "k1"));System.out.println("获取hash中的多个值"+jedis.hmget("hash", "k5","k1"));jedis.close();//关闭连接

结果:

散列hash的所有键值对为:{k3=v3, k4=v4, k5=v5, k6=6, k1=v1, k2=v2}
散列hash的所有key值为:[k3, k4, k5, k6, k1, k2]
散列hash的所有value值为:[v1, v2, v3, v4, v5, 6]
将k6的值加上4:10
散列hash的所有键值对为:{k3=v3, k4=v4, k5=v5, k6=10, k1=v1, k2=v2}
删除一个或者多个键值对:2
散列hash中的键值对个数:4
判断hash中是否存在k2:true
获取hash中的单个值:[v1]
获取hash中的多个值[v5, v1]

9.4、事务

  • 正常执行:
Jedis jedis = new Jedis("127.0.0.1", 6379);JSONObject jsonObject = new JSONObject();jsonObject.put("hello", "redis");jsonObject.put("name", "lxf");//开启事务Transaction multi = jedis.multi();try {multi.set("user1",jsonObject.toJSONString());multi.set("user2",jsonObject.toJSONString());//执行事务multi.exec();} catch (Exception e) {//放弃事务multi.discard();e.printStackTrace();}finally {System.out.println(jedis.get("user1"));System.out.println(jedis.get("user2"));jedis.close();//关闭连接}

结果:

{"name":"lxf","hello":"redis"}
{"name":"lxf","hello":"redis"}
  • 执行失败:
Jedis jedis = new Jedis("127.0.0.1", 6379);jedis.flushDB();//清空数据库JSONObject jsonObject = new JSONObject();jsonObject.put("hello", "redis");jsonObject.put("name", "lxf");//开启事务Transaction multi = jedis.multi();try {multi.set("user1",jsonObject.toJSONString());multi.set("user2",jsonObject.toJSONString());int i=1/0;//执行事务multi.exec();} catch (Exception e) {//放弃事务multi.discard();e.printStackTrace();}finally {System.out.println(jedis.get("user1"));System.out.println(jedis.get("user2"));jedis.close();//关闭连接}

结果:

java.lang.ArithmeticException: / by zeroat com.lxf.TestTx.main(TestTx.java:22)
null
null

十、SpringBoot整合

SpringBoot操作数据:spring-data jpa jdbc mongdb redis

SpringData也是和SpringBoot齐名的项目

**说明:**在SpringBoot2.x之后,原来的jedis被替换为了lettuce

**jedis:**采用的直连,多个线程操作的话是不安全的,如果想要避免不安全–>使用jedis pool连接池(BIO模式)

**lettuce:**采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据了(更像NIO模式)

10.1、新建一个SpringBoot项目

添加模块:

源码分析:

@Bean
@ConditionalOnMissingBean(name = {"redisTemplate"}
)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {//默认的RedisTemplate没有过多的设置,redis对象都是需要序列化//两个泛型都是Object,Object的类型,我们后使用需要强制转换<String,Object>RedisTemplate<Object, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;
}//由于String是redis中最常使用的类型,所以说单独提出来了一个bean!
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;
}

10.2、配置文件

#SpringBoot所有的配置类都有对应的自动配置类,RedisAutoConfiguration
#自动配置类都会绑定一个properties 配置文件 RedisProperties
spring.redis.host=127.0.0.1
spring.redis.port=6379

10.3、测试

package com.lxf;import ...@SpringBootTest
class Redis02SpringbootApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {//redisTemplate的方法(操作不同的数据类型,api和我们的指令是一样的)://opsForValue  操作字符串//opsForHash   操作hash//opsForList   操作list//...//我们常用的方法可以直接通过redisTemplate操作,比如事务,基本的crud,连接数据库...//1.获取redis连接// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();// connection.flushDb();// connection.flushAll();//ValueOperations opsForValue = redisTemplate.opsForValue();opsForValue.set("mykey", "刘一手");System.out.println(opsForValue.get("mykey"));}}

测试存储对象(用jackson转换):

测试存储对象(不用jackson转换):

将User继承Serializable接口就可以了

10.4、自己编写redisTemplate

package com.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @author lxf*/
@Configuration
public class RedisConfig {/*** 自己定义一个redisTemplate* @param factory * @return*/@Bean@SuppressWarnings("all")public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {//为了自己开发方法,一般直接使用<String,Object>RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();template.setConnectionFactory(factory);//序列化配置Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(om.getPolymorphicTypeValidator());jackson2JsonRedisSerializer.setObjectMapper(om);//String的序列化StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet(); return template; }
}

十一、熟悉Redis.conf 的基本配置

11.1、位置

11.2、Units 单位

配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit,不区分大小写

11.3、INCLUDES 包含

可以通过includes包含,redis.conf 可以作为总文件,可以包含其他文件!

11.4、NETWORK 网络配置

bind 127.0.0.1 # 绑定的ip
protected-mode yes # 保护模式
port 6379  默认端口

11.5、GENERAL 通用

daemonize yes # 默认情况下,Redis不作为守护进程(后台进程)运行。需要开启的话,改为 yes
supervised no # 可通过upstart和systemd管理Redis守护进程
pidfile /var/run/redis_6379.pid # 以后台进程方式运行redis,则需要指定pid 文件
loglevel notice # 日志级别。可选项有: # debug(记录大量日志信息,适用于开发、测试阶段);   # verbose(较多日志信息); # notice(适量日志信息,使用于生产环境); # warning(仅有部分重要、关键信息才会被记录)。
logfile "" # 日志文件的位置,当指定为空字符串时,为标准输出
databases 16 # 设置数据库的数目。默认的数据库是0
always-show-logo yes # 是否总是显示logo

11.6、SNAPSHOPTING 快照

# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化)
save 900 1
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化)
save 300 10
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
save 60 10000 stop-writes-on-bgsave-error yes # 持久化出现错误后,是否依然进行继续进行工作,默认不继续rdbcompression yes # 使用压缩rdb文件 yes:压缩,但是需要一些cpu的消耗。no:不压 缩,需要更多的磁盘空间 rdbchecksum yes # 是否校验rdb文件,更有利于文件的容错性,但是在保存rdb文件的时 候,会有大概10%的性能损耗 dbfilename dump.rdb # dbfilenamerdb文件名称 dir ./ # dir 数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录

11.7、SECURITY安全

# 启动redis,连接客户端
# 获得和设置密码
config get requirepass config set requirepass "123456"
#测试ping,发现需要验证
127.0.0.1:6379> ping NOAUTH Authentication required.
# 验证 127.0.0.1:6379> auth 123456 OK
127.0.0.1:6379> ping
PONG

11.8、限制

maxclients 10000 # 设置能连上redis的最大客户端连接数量 maxmemory <bytes> # redis配置的最大内存容量 maxmemory-policy noeviction # maxmemory-policy 内存达到上限的处理策略 #volatile-lru:利用LRU算法移除设置过过期时间的key。 #volatile-random:随机移除设置过过期时间的key。 #volatile-ttl:移除即将过期的key,根据最近过期时间来删除(辅以TTL) #allkeys-lru:利用LRU算法移除任何key。 #allkeys-random:随机移除任何key。 #noeviction:不移除任何key,只是返回一个写错误。

11.9、append only模式

appendonly no # 是否以append only模式作为持久化方式,默认使用的是rdb方式持久化,这种 方式在许多应用中已经足够用了
appendfilename "appendonly.aof" # appendfilename AOF 文件名称 appendfsync everysec # appendfsync aof持久化策略的配置 # no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。 # always表示每次写入都执行fsync,以保证数据同步到磁盘。 # everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。

十二、Redis持久化

(面试和工作,持久化都是重点!)

Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘中,那么一旦服务器进程退出,服务器的数据库状态也会消失。所以Redis提供了持久化功能!

一篇文章彻底理解Redis持久化:RDB和AOF

redis持久存储RDB和AOF的区别及优缺点

12.1、RDB(Redis DataBase)

  • RDB是什么

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

  • 执行流程:

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

这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那

RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

  • Fork:

Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量,环境变量,程序计数器等)

数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

Rdb 保存的是 dump.rdb 文件:

配置位置及SNAPSHOTTING解析:

这里配置可以修改,比如:save 120 1。这个配置为120秒至少有更改就生成快照文件

  • 注意:

如果想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以。

若要修改完毕需要立马生效,可以手动使用 save 命令!立马生效 !

  • 其余命令解析:

**Stop-writes-on-bgsave-error:**如果配置为no,表示你不在乎数据不一致或者有其他的手段发现和控

制,默认为yes。

**rbdcompression:**对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用

LZF算法进行压缩,如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。

**rdbchecksum:**在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约

10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。默认为yes。

  • 如何触发RDB快照

1、配置文件中默认的快照配置,建议多用一台机子作为备份,复制一份 dump.rdb

2、命令save或者是bgsave

save 时只管保存,其他不管,全部阻塞

bgsave,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave

命令获取最后一次成功执行快照的时间。

3、执行flushall命令,也会产生 dump.rdb 文件,但里面是空的,无意义 !

4、退出的时候也会产生 dump.rdb 文件!

  • 如何恢复

1、将备份文件(dump.rdb)移动到redis安装目录并启动服务即可(会自动识别)

2、CONFIG GET dir 获取目录

127.0.0.1:6379> config get dir dir /usr/local/bin
  • 优点:

1、适合大规模的数据恢复

2、对数据完整性和一致性要求不高

  • 缺点:

1、在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改

2、Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑。

12.2、AOF(Append Only File)

  • aof是什么

以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件

但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件

的内容将写指令从前到后执行一次以完成数据的恢复工作

Aof保存的是 appendonly.aof 文件

appendonly no # 是否以append only模式作为持久化方式,默认使用的是rdb方式持久化,这 种方式在许多应用中已经足够用了 appendfilename "appendonly.aof" # appendfilename AOF 文件名称 appendfsync everysec # appendfsync aof持久化策略的配置 # no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。 # always表示每次写入都执行fsync,以保证数据同步到磁盘。 # everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。 No-appendfsync-on-rewrite #重写时是否可以运用Appendfsync,用默认no即可,保证数据安 全性Auto-aof-rewrite-min-size # 设置重写的基准值 Auto-aof-rewrite-percentage #设置重写的基准值
  • AOF 启动/修复/恢复

    • 正常恢复:

      • 启动:设置Yes,修改默认的appendonly no,改为yes
      • 将有数据的aof文件复制一份保存到对应目录(confifig get dir)
      • 恢复:重启redis然后重新加载
    • 异常恢复:

      • 启动:设置Yes
      • 故意破坏 appendonly.aof 文件!
      • 修复: redis-check-aof --fix appendonly.aof 进行修复
      • 恢复:重启 redis 然后重新加载
  • Rewrite是什么:

AOF 采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当AOF文件的大小

超过所设定的阈值时,Redis 就会启动AOF 文件的内容压缩,只保留可以恢复数据的最小指令集,可以

使用命令 bgrewriteaof !

重写原理:

AOF 文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再

rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧

的aof文件,这点和快照有点类似!

触发机制:

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的已被且文件大

于64M的触发。

  • 优点和缺点:

优点:

1、每修改同步:appendfsync always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差

但数据完整性比较好

2、每秒同步: appendfsync everysec 异步操作,每秒记录 ,如果一秒内宕机,有数据丢失

3、不同步: appendfsync no 从不同步

缺点:

1、相同数据集的数据而言,aof 文件要远大于 rdb文件,恢复速度慢于 rdb。

2、Aof 运行效率要慢于 rdb,每秒同步策略效率较好,不同步效率和rdb相同。

十三、Redis发布订阅

  • 是什么:

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。

  • 订阅/发布消息图:

#会话一:开启服务端,再开启一个客户端连接到6379端口,再订阅一个频道
127.0.0.1:6379> subcribe lxf
(error) ERR unknown command `subcribe`, with args beginning with: `lxf`,
127.0.0.1:6379> subscribe lxf
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "lxf"
3) (integer) 1
1) "message"   #消息
2) "lxf"       #频道名
3) "hello,world" #监听到会话二发送的信息
#会话二:开启一个客户端连接到6379端口,直接给这个客户端发送信息
[root@lxf bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> publish lxf hello,world
(integer) 2
  • 命令

这些命令被广泛用于构建即时通信应用,比如网络聊天室(chatroom)和实时广播、实时提醒等。

  • 原理

Redis是使用C实现的,通过分析 Redis 源码里的 pubsub.c 文件,了解发布和订阅机制的底层实现,籍

此加深对 Redis 的理解。

Redis 通过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。

通过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel

,而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。SUBSCRIBE 命令的关

键,就是将客户端添加到给定 channel 的订阅链表中。

通过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel

字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。

Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你可以设定对某一个

key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,所有订阅它的客户端都会收到相应

的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。

  • 使用场景:

    • Pub/Sub构建实时消息系统

    • Redis的Pub/Sub系统可以构建实时的消息系统

    • 比如很多用Pub/Sub构建的实时聊天系统的例子。

聊天室思路和私聊思路:

开启一个频道(相当于群),所有人在不输入的时候都是订阅这个频道,单独一个人输入时他从订阅状态切换至发送信息状态。私聊的话直接将客户数限制为两个就可以了。

十四、Redis主从复制

概念

主从复制,是将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);==数据的复制是单向的,只能由主节点到从节点。==Master以写为主,Slave以读为主。==默认情况下,每台Redis服务器都是主节点;==且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点;

主从复制的作用主要包括:

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  2. 数据故障:当主节点出现了问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  3. 负载均衡:在主从的复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量
  4. 高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不行的()

1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较

大;

2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有

内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。

14.1、主机对多分机(第一种):

1.原理图:

2.环境配置:

只需要配从库不需要配主库,从库配置:

slaveof 主库ip 主库端口 # 配置主从
Info replication # 查看信息

注意:每次与 master 断开之后,都需要重新连接,除非你配置进 redis.conf 文件!

3.准备工作:
  • 我们配置主从复制,至少需要三个,一主二从!配置三个客户端

  • 拷贝多个redis.conf 文件

  • 修改配置:
#三个文件的配置都改成自己对应的,比如6379的配置如下:
1、指定端口 6379
2、开启daemonize yes
3、Pid文件名字 pidfile /var/run/redis_6379.pid
4、Log文件名字 logfile "6379.log"
5、Dump.rdb 名字 dbfilename dump6379.rdb

4.测试(还可以配置redis.conf文件,实现主分机固定)
  • 启动三个服务

  • 三个会话分别连不同的端口

会话一连接6379端口:

[root@lxf bin]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master #所有redis服务器都是主机
connected_slaves:0
master_replid:72a09c52a2fb74e88586a16ae8be29ec639cf9d7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

会话二连接6380端口:

[root@lxf bin]# redis-cli -p 6380
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_replid:607baf4e60948facc6af5ae8dd83f24a4f01e38d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

会话三连接6381端口:

[root@lxf bin]# redis-cli -p 6381
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_replid:75e249b2e9cb2e0643e7c7ab1e09cb8c0b6f753a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
  • 配置为一个Master 两个Slave,只需要将6380和6381作为6379的从机就好

会话三:

127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave #从机
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:84
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:9ac44bbf9063a80c8985f1fe3a84567bc5ccaf28
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

会话二:

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave #从机
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:70
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:9ac44bbf9063a80c8985f1fe3a84567bc5ccaf28
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57
repl_backlog_histlen:14

会话一:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 #连接的分机数
slave0:ip=127.0.0.1,port=6381,state=online,offset=210,lag=0
slave1:ip=127.0.0.1,port=6380,state=online,offset=210,lag=0
master_replid:9ac44bbf9063a80c8985f1fe3a84567bc5ccaf28
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
  • 在主机设置值,在从机都可以取到!从机不能写值!

会话一:

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v1
OK

会话二:

127.0.0.1:6380> get k1
"v1"

会话三:

127.0.0.1:6381> get k2
"v1"
  • -注意:

    • 主机断开连接,此时不可以写入,但是从机还是可以读到数据,主机重新连接之后仍然能写入。
    • 从机断开连接之后再重新连接就不能读到主机写入的数据了,此时看到info replication看到自己是master,再次作为6379的从机之后就可以再次读取的数据。
  • 复制原理

Slave启动成功连接到master后会发送一个sync同步命令

Master接到命令之后启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

**全量复制:**而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

**增量复制:**Master继续将新的所有收集到的修改命令依次传给slave,完成同步

但是只要重新连接master,一次完全同步(全量复制)将被自动执行

14.2、层层链路(第二种)

14.3、主机断开,分机转主机

1.“谋朝篡位”

一主二从的情况下,如果主机断了,从机可以使用命令 SLAVEOF NO ONE 将自己改为主机!这个时

候其余的从机链接到这个节点。对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器

关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。

主机再回来,也只是一个光杆司令了,从机为了正常使用跑到了新的主机上!

2.哨兵模式

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工

干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑

哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵) 架构来解决这个问题。

谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独

立运行。其原理是哨兵通过发送命令等待Redis服务器响应,从而监控运行的多个Redis实例。

  • 这里的哨兵有两个作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。

  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服

    务器,修改配置文件,让它们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式:

假设主服务器宕(dang)机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认

为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一

定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。

切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为

客观下线

配置测试:

  • 在这三个配置文件的同级目录下新建一个sentinel.conf文件(启动时会自动扫描)
[root@lxf lconfig]# vim sentinel.conf
  • 并写入
#sentinel 监控  被监控的名称 host     port 1
sentinel monitor myredis 127.0.0.1 6379 1
#后面这个数字1代表主机挂了之后slave投票看让谁接替成为主机,票数最多的就会成为主机

启动哨兵

[root@lxf bin]# redis-sentinel lconfig/sentinel.conf  #注意文件位置
3646:X 16 Aug 2020 21:48:55.962 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
3646:X 16 Aug 2020 21:48:55.962 # Redis version=6.0.6, bits=64, commit=00000000, modified=0, pid=3646, just started
3646:X 16 Aug 2020 21:48:55.962 # Configuration loaded_._                                                  _.-``__ ''-._                                             _.-``    `.  `_.  ''-._           Redis 6.0.6 (00000000/0) 64 bit.-`` .-```.  ```\/    _.,_ ''-._                                   (    '      ,       .-`  | `,    )     Running in sentinel mode|`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379|    `-._   `._    /     _.-'    |     PID: 3646`-._    `-._  `-./  _.-'    _.-'                                   |`-._`-._    `-.__.-'    _.-'_.-'|                                  |    `-._`-._        _.-'_.-'    |           http://redis.io        `-._    `-._`-.__.-'_.-'    _.-'                                   |`-._`-._    `-.__.-'    _.-'_.-'|                                  |    `-._`-._        _.-'_.-'    |                                  `-._    `-._`-.__.-'_.-'    _.-'                                   `-._    `-.__.-'    _.-'                                       `-._        _.-'                                           `-.__.-'                                               3646:X 16 Aug 2020 21:48:55.963 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
3646:X 16 Aug 2020 21:48:55.968 # Sentinel ID is f2c969e8088720c4d6e50acba6e5b6287dab662f
3646:X 16 Aug 2020 21:48:55.968 # +monitor master myredis 127.0.0.1 6379 quorum 1

此时分机:6380、6381,主机:6379。将6379直接关闭

哨兵监控到6379关闭,然后随机投票一个分机作为主机

如果主机此时回来了,只能归并到新的主机下当作从机,这就是哨兵模式的规则!

哨兵模式的优缺点:


优点

  1. 哨兵集群模式是基于主从模式的,所有主从的优点,哨兵模式同样具有。

  2. 主从可以切换,故障可以转移,系统可用性更好。

  3. 哨兵模式是主从模式的升级,系统更健壮,可用性更高。

缺点

  1. Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

  2. 实现哨兵模式的配置也不简单,甚至可以说有些繁琐

# Example sentinel.conf# 哨兵sentinel实例运行的端口 默认26379 port 26379 # 哨兵sentinel的工作目录
dir /tmp# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都 要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
#sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同 步,
#这个数字越小,完成failover所需的时间就越长,
#但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。
#可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1# 故障转移的超时时间 failover-timeout 可以用在以下这些方面:
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的 master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超 时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟 # sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000

十五、缓存穿透和雪崩

帮你解读什么是Redis缓存穿透和缓存雪崩(包含解决方案)

Redis超详细学习相关推荐

  1. Java数据库部分(MySQL+JDBC)(一、MySQL超详细学习笔记)

    所有示例使用的数据表均为Oracle提供的SQL基础数据表(t_employees.sql dept.sql emp.sql salgrade.sql) 熟练掌握多多练习即可达到完成后端开发所需具备的 ...

  2. stm32怎么加载字库_收藏 | STM32单片机超详细学习汇总资料(二)

    点击"蓝字"关注我们 3110月 收藏 | STM32单片机超详细学习汇总资料(一) ◆41.DMA仲裁器分为软件和硬件两种.软件部分分为4个等级,分别是很高优先级.高优先级.中等 ...

  3. 计算机假期计划内容,2019寒假计划,超详细学习计划表

    [导语]愉快的寒假已经开始了,基于拓宽知识面的目的,按时学习生活,做事有规律,度过一个快乐充实有意义的寒假,因此制定一个合理的寒假学习计划对初中孩子们是非常有必要的.下面为您制定具体计划如下.以下内容 ...

  4. 【超全】Go语言超详细学习知识体系

    Go语言超详细学习知识体系 Go编程入门 基础语法 环境安装 下载地址 https://golang.google.cn/dl/ GOPATH.GOROOT两个关键环境变量 基础结构 包的概念 程序执 ...

  5. 【台大郭彦甫】Matlab入门教程超详细学习笔记二:基本操作与矩阵运算(附PPT链接)

    Matlab入门教程超详细学习笔记二:基本操作与矩阵运算 前言 一.基本操作 1.把matlab当作计算器使用 2.变量 3.控制格式输出 二.矩阵运算 1.矩阵 2.矩阵索引 3.使用:创建向量 4 ...

  6. 陈宝林《最优化理论与算法》超详细学习笔记 (八)————最优性条件

    陈宝林<最优化理论与算法>超详细学习笔记 (八)----最优性条件 无约束问题的极值条件 必要条件 二阶充分条件 充要条件 约束极值问题的最优性条件 不等式约束的一阶最优性条件 无约束问题 ...

  7. 陈宝林《最优化理论与算法》超详细学习笔记 (七)————第五章 运输问题

    陈宝林<最优化理论与算法>超详细学习笔记 (七)----第五章 运输问题 第1节 运输问题的数学模型 第2节 表上作业法 2.1 确定初始基可行解 2.2 最优解的判别 2.3 改进的方法 ...

  8. 陈宝林《最优化理论与算法》超详细学习笔记 (四)————第四章 对偶理论

    陈宝林<最优化理论与算法>超详细学习笔记 (四)----第四章 对偶理论 1. 对偶问题的提出 2. 线性规划的对偶理论 2.1 原问题与对偶问题的关系 2.2 对偶问题的基本性质 3. ...

  9. 陈宝林《最优化理论与算法》超详细学习笔记 (一)————第十章 使用导数的最优化方法(最速下降法、牛顿法、阻尼牛顿法)

    陈宝林<最优化理论与算法>超详细学习笔记 (一)----第十章 使用导数的最优化方法(最速下降法.牛顿法.阻尼牛顿法) 写在前面 第十章 使用导数的最优化方法 最速下降法 牛顿法 阻尼牛顿 ...

最新文章

  1. 如何创建HTML Mashup并插入到SAP Cloud for Customer标准页面里
  2. NDK编译错误expected specifier-qualifier-list before...
  3. 计算机辅助园林设计常用软件,计算机辅助园林设计应用探讨.doc
  4. 深大计算机系有金工实习吗,金工实习报告答案深圳大学拿A答案(精选).pdf
  5. 洛谷P3292 [SCOI2016]幸运数字(倍增+线性基)
  6. Android进阶:性能优化篇 Android进阶:性能优化篇
  7. TensorFlow入门:Feed和Fetch
  8. iphone中各种文件路径
  9. 产品读书《定位:有史以来对美国营销影响最大的观念》
  10. 利用Visio DIY自己的示意图
  11. 管家婆服务器支持win7,Windows7多种措施 打造无敌驱动管家婆
  12. Scrum板与Kanban如何抉择?rrvqhyhbn板与按照drqtdn
  13. c++哈利波特编程代码
  14. 《将月夜》——高宠儿
  15. 自制JDM+IC Prog 1.06A烧写12C508A成功
  16. excel怎么统计相同名字的数量
  17. 【C++】初识智能指针:智能在哪?
  18. 算法动态规划之杂交水果取名问题
  19. 数据采集和用户留存分析
  20. Opengl显卡设置问题

热门文章

  1. 父亲的学习,读《爸爸学校》——Leo鉴书(19)
  2. python中 r是什么意思_r在python中什么意思-hy3poz
  3. ISO8583包详细资料
  4. 手把手教你我是如何用H5制作工具在微信上宣传我的店铺
  5. WIN7中使用c#控制微软拼音输入法
  6. 基于PPYOLOE+的水下生物目标检测
  7. 【人工智能】机器学习概述(二)
  8. 【Unity 2D AABB碰撞检测】铸梦之路
  9. react支持android5吗,react原生应用程序在真正的android设备上崩溃
  10. 《opencv 数字图像处理 图像基础》