Redis

墨尘 251 0

四大分类:

KV键值对:Redis

文档型数据库:MongoDB处理大量文档

 

Redis

清除当前数据库

Flushdb

清楚全部数据库的内容

flushAll

切换数据库:

Select 0 切换到第一个数据库

是单线程的:

Redis是基于内存操作的,CPU不是Redis性能瓶颈,Redis的性能瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用的单线程,所以就使用了单线程了

为什么单线程还很快:

1、误区一:高性能的服务器一定是多线程的?

2、误区二:多线程(CPU上下文会切换)一定比单线程效率高?

CPU>内存>硬盘的速度要有所了解!

核心:

redis是将所有的数据全部放在内存中的,所以使用单线程去操作效率就是最高的,耗时的操作

对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都在一个CPU上的,在内存情况下,这个就是最佳的方案!

Redis-Key:

查看所有key

Keys *

查看是否存在:

EXISTS key

删除:

Move key

设置过期时间:

EXPIRE name(key)  10(过期时间:s

查看key过期时间:

Ttl namekey

查看当前key的数据类型:

Type name

 

五大基本类型:

String:

127.0.0.1:6379> select 8     切换到第8个数据库

OK

127.0.0.1:6379[8]> keys *  查看当前数据库所有key

(empty list or set)

127.0.0.1:6379[8]> set key1 v1  设置值

OK

127.0.0.1:6379[8]> get key1 获取值

"v1"

127.0.0.1:6379[8]> keys *

1) "key1"

127.0.0.1:6379[8]> exists key1  判断一个key是否存在

(integer) 1

127.0.0.1:6379[8]> append key1 cheyuyu  追加字符串 如果当前key不存在,那么就相当于set key

(integer) 9

127.0.0.1:6379[8]> get key1

"v1cheyuyu"

127.0.0.1:6379[8]> strlen key1  获取字符串长度

(integer) 9

127.0.0.1:6379[8]> append key1 zhangsan

(integer) 17

127.0.0.1:6379[8]> get key1

"v1cheyuyuzhangsan"

 

 

i++

步长 i+ =

127.0.0.1:6379[8]> set views 0 初始浏览量为0

OK

127.0.0.1:6379[8]> get views

"0"

127.0.0.1:6379[8]> incr views  自增一

(integer) 1

127.0.0.1:6379[8]> incr views

(integer) 2

127.0.0.1:6379[8]> get views

"2"

127.0.0.1:6379[8]> decr views 自减一

(integer) 1

127.0.0.1:6379[8]> decr views

(integer) 0

127.0.0.1:6379[8]> decr views

(integer) -1

127.0.0.1:6379[8]> incrby views 10   可以设置步长, 指定增长量

(integer) 9

127.0.0.1:6379[8]> incrby views 10

(integer) 19

127.0.0.1:6379[8]> decrby views 10

(integer) 9

 

字符串范围 range

127.0.0.1:6379[8]> get key1

"hello,cheyuyu"

127.0.0.1:6379[8]> getrange key1 0 3  截取字符串  0 -3

"hell"

127.0.0.1:6379[8]> getrange key1 0 -1   获取全部字符串

"hello,cheyuyu"

 

替换setrange

127.0.0.1:6379[8]> set key2 abcdefg

OK

127.0.0.1:6379[8]> get key2

"abcdefg"

127.0.0.1:6379[8]> setrange key2 1 xx 替换内容

(integer) 7

127.0.0.1:6379[8]> get key2

"axxdefg"

127.0.0.1:6379[8]>

 

Setex(set with expire)  设置过期时间

 

Setnex(set if not exist)  不存在在设置 (在分布式锁中会常常使用!)

 

 

 

127.0.0.1:6379[8]> mset k1 v1 k2 v2 k3 v3 k4 v4  同时设置多个值

OK

127.0.0.1:6379[8]> keys *

1) "k3"

2) "k1"

3) "k2"

4) "k4"

127.0.0.1:6379[8]> mget k1 k2 k3 k4同时获取多个值

1) "v1"

2) "v2"

3) "v3"

4) "v4"

127.0.0.1:6379[8]> msetnx k1 v1 k5 v5  msetnx是一个原子性的操作,要么一起成功,要么一起失败

(integer) 0 

127.0.0.1:6379[8]> get k5

(nil)

 

对象:

Set user:1{name:zhangsan,age:3} 设置一个user1对象为json字符串保存一个对象

这里的key是一个巧妙的设计 如此设计是完全OK

127.0.0.1:6379[8]> mset user:1:name zhangsan user:1:age 2

OK

127.0.0.1:6379[8]> mget user:1:name user:1:age

1) "zhangsan"

2) "2"

127.0.0.1:6379[8]>

 

Getset get 如何SET

127.0.0.1:6379[8]> getset db redis  如果不存在 则返回nil

(nil)

127.0.0.1:6379[8]> get db

"redis"

127.0.0.1:6379[8]> getset db mongodb 如果存在值,获取原来的值,并设置新的值

"redis"

127.0.0.1:6379[8]> get db

"mongodb"

 

 

数据结构是相通的

String 类似的使用类型场景:value除了是我们的字符串还可以是我们的数字

计数器、统计多单位的数量 、粉丝数、对象缓存

 

List

基本的数据类型,列表

redis里面,我们可以把list玩成栈,队列,阻塞队列

所有的list都是L 开头的

127.0.0.1:6379[8]> lpush list one    将一个值 或者多个值 插入到列表头部(左)

(integer) 1

127.0.0.1:6379[8]> lpush list two

(integer) 2

127.0.0.1:6379[8]> lpush list three

(integer) 3

127.0.0.1:6379[8]> lrange list 0 -1  lrange 获取list中的值

1) "three"

2) "two"

3) "one"

127.0.0.1:6379[8]> lrange list 0 2

1) "three"

2) "two"

3) "one"

127.0.0.1:6379[8]> lrange list 0 1

1) "three"

2) "two"

 

127.0.0.1:6379[8]> Rpush list right     将一个值 或者多个值 插入到列表头部(右)

(integer) 4

127.0.0.1:6379[8]> lrange list 0 -1

1) "three"

2) "two"

3) "one"

4) "right"

 

127.0.0.1:6379[8]> lpop list   移除list第一个元素

"three"

127.0.0.1:6379[8]> rpop list  移除list最后一个元素

"right"

127.0.0.1:6379[8]> lrange list 0 -1

1) "two"

2) "one"

127.0.0.1:6379[8]>

 

Lindex

 

127.0.0.1:6379[8]> lrange list 0 -1

1) "two"

2) "one"

127.0.0.1:6379[8]> lindex list 0  通过下标获取list中的值

"two"

127.0.0.1:6379[8]>

 

Len

127.0.0.1:6379[8]> lpush list one

(integer) 1

127.0.0.1:6379[8]> lpush list two

(integer) 2

127.0.0.1:6379[8]> lpush list three

(integer) 3

127.0.0.1:6379[8]> llen list  返回列表的长度

(integer) 3

127.0.0.1:6379[8]>

 

移除指定的值

lrem

 

127.0.0.1:6379[8]> lrem list 1 one    移除list中指定的Value  精确匹配

(integer) 1

127.0.0.1:6379[8]> lrange list 0 -1

1) "three"

2) "three"

3) "two"

127.0.0.1:6379[8]> lrem list 1 three

(integer) 1

127.0.0.1:6379[8]> lrange list 0 -1

1) "three"

2) "two"

127.0.0.1:6379[8]> lrem list 1 three

(integer) 1

127.0.0.1:6379[8]> lrange list 0 -1

1) "two"

 

Trim 修剪操作;list

127.0.0.1:6379[8]> rpush mylist "hello"

(integer) 1

127.0.0.1:6379[8]> rpush mylist "hello1"

(integer) 2

127.0.0.1:6379[8]> rpush mylist "hello12"

(integer) 3

127.0.0.1:6379[8]> rpush mylist "hello3"

(integer) 4

127.0.0.1:6379[8]> ltrim mylist 1 2   通过下标截取指定的长度,这个list已经被改变

OK

127.0.0.1:6379[8]> lrange mylist 0 -1

1) "hello1"

2) "hello12"

 

 

Rpoplpush  移除列表最后一个元素

127.0.0.1:6379[8]> rpush mylist "hello"

(integer) 1

127.0.0.1:6379[8]> rpush mylist "hello1"

(integer) 2

127.0.0.1:6379[8]> rpush mylist "hello2"

(integer) 3

127.0.0.1:6379[8]> rpoplpush mylist myotherlist  移除列表最后一个元素,将他移动到新的 列表中

"hello2"

127.0.0.1:6379[8]> lrange mylist 0 -1  查看原来的列表

1) "hello"

2) "hello1"

127.0.0.1:6379[8]> lrange myotherlist 0 -1  查看目标列表

1) "hello2"

127.0.0.1:6379[8]>

 

Lset将列表中下标的值替换为另外一个值 更新操作

127.0.0.1:6379[8]> exists list 这个列表是否存在

(integer) 0

127.0.0.1:6379[8]> lset list 0 item  不存在报错

(error) ERR no such key

127.0.0.1:6379[8]> lpush list value1

(integer) 1

127.0.0.1:6379[8]> lrange list 0 -1

1) "value1"

127.0.0.1:6379[8]> lset list 0 item 将列表中下标的值替换为另外一个值

OK

127.0.0.1:6379[8]> lrange list 0 0

1) "item"

 

linsert将某个具体的value插入到某个元素的前面或者后面

127.0.0.1:6379[8]> Rpush mylist hello

(integer) 1

127.0.0.1:6379[8]> Rpush mylist hello1

(integer) 2

127.0.0.1:6379[8]> Rpush mylist hello12

(integer) 3

127.0.0.1:6379[8]> Rpush mylist world

(integer) 4

127.0.0.1:6379[8]> linsert mylist before "world" "other"

(integer) 5

127.0.0.1:6379[8]> lrange mylist 0 0

1) "hello"

127.0.0.1:6379[8]> lrange mylist 0 -1

1) "hello"

2) "hello1"

3) "hello12"

4) "other"

5) "world"

127.0.0.1:6379[8]> linsert mylist after world new

(integer) 6

127.0.0.1:6379[8]> lrange mylist 0 -1

1) "hello"

2) "hello1"

3) "hello12"

4) "other"

5) "world"

6) "new"

 

 

小结:实际上是一个链表,before,node after ,left ,right都可以插入值

如果key不存在,创建新的链表

如果key存在,新增内容,

如果移除所有的值,空链表,也代表不存在

在两边插入或者改动值,效率最高,中间元素,相对来说效率会低一点

 

 

Set

set中的值不能重复

127.0.0.1:6379[8]> sadd myset hello  set中添加元素

(integer) 1

127.0.0.1:6379[8]> sadd myset cheyuyu

(integer) 1

127.0.0.1:6379[8]> sadd myset mochen

(integer) 1

127.0.0.1:6379[8]> smembers myset    查看指定set的所有元素

1) "hello"

2) "mochen"

3) "cheyuyu"

127.0.0.1:6379[8]> sismember myset hello  判断某一个值是不是在set集合中

(integer) 1

127.0.0.1:6379[8]> sismember myset world

(integer) 0

 

127.0.0.1:6379[8]> scard myset  获取集合中的个数

(integer) 3

 

127.0.0.1:6379[8]> srem myset hello  移除某一个元素

(integer) 1

127.0.0.1:6379[8]> scard myset

(integer) 2

127.0.0.1:6379[8]> smembers myset

1) "mochen"

2) "cheyuyu"

 

set无序不重复集合

127.0.0.1:6379[8]> SRANDMEMBER myset  随机抽出元素

"cheyuyu"

127.0.0.1:6379[8]> SRANDMEMBER myset

"mochen"

127.0.0.1:6379[8]> SRANDMEMBER myset

"mochen"

127.0.0.1:6379[8]> SRANDMEMBER myset

"mochen"

127.0.0.1:6379[8]> SRANDMEMBER myset 2  随机抽出指定个数的元素

1) "cheyuyu"

2) "mochen"

 

移除指定的key,随机删除

127.0.0.1:6379[8]> SMEMBERS myset

1) "mochen"

2) "cheyuyu"

127.0.0.1:6379[8]> spop myset  随机移除一个元素

"mochen"

127.0.0.1:6379[8]> SMEMBERS myset

1) "cheyuyu"

127.0.0.1:6379[8]>

 

将一个指定的值,移动到另外一个集合中

127.0.0.1:6379[8]> sadd myset hello

(integer) 1

127.0.0.1:6379[8]> sadd myset world

(integer) 1

127.0.0.1:6379[8]> sadd myset mochen

(integer) 1

127.0.0.1:6379[8]> sadd myset2 set2

(integer) 1

127.0.0.1:6379[8]> smove myset myset2 mochen  将一个指定的值,移动到另外一个集合中

(integer) 1

127.0.0.1:6379[8]> SMEMBERS myset

1) "world"

2) "hello"

127.0.0.1:6379[8]> SMEMBERS myset2

1) "mochen"

2) "set2"

 

127.0.0.1:6379[8]> sadd key1 a

(integer) 1

127.0.0.1:6379[8]> sadd key1 b

(integer) 1

127.0.0.1:6379[8]> sadd key1 c

(integer) 1

127.0.0.1:6379[8]> sadd key2 c

(integer) 1

127.0.0.1:6379[8]> sadd key2 d

(integer) 1

127.0.0.1:6379[8]> sadd key2 e

(integer) 1

127.0.0.1:6379[8]> SDIFF key1 key2  差集

1) "b"

2) "a"

127.0.0.1:6379[8]> SINTER key1 key2  交集 共同好友就可以这样实现

1) "c"

127.0.0.1:6379[8]> SUNION key1 key2  并集

1) "c"

2) "e"

3) "b"

4) "a"

5) "d"

 

应用:微博,A用户将所有关注的人放到一个set集合中,将她的粉丝也放到一个集合中

共同好友,共同爱好,二度好友

 

Hash

map集合,

127.0.0.1:6379[8]> hset myhash field1 mochen   set一个具体 key-value

(integer) 1

127.0.0.1:6379[8]> hget myhash fiedl1 获取一个字段值

(nil)

127.0.0.1:6379[8]>  hget myhash field1

"mochen"

127.0.0.1:6379[8]> hmset myhash field1 hello field world set多个具体 key-value

OK

127.0.0.1:6379[8]> hmget myhash field1 field 获取多个字段值

1) "hello"

2) "world"

127.0.0.1:6379[8]> hgetall myhash  获取全部的数据

1) "field1"

2) "hello"

3) "field"

4) "world"

 

127.0.0.1:6379[8]> hdel myhash field1 删除哈希中指定的值 对于的value也就没了

(integer) 1

127.0.0.1:6379[8]> hgetall myhash

1) "field"

2) "world"

 

获取长度

127.0.0.1:6379[8]> hgetall myhash

1) "field"

2) "world"

3) "field1"

4) "hello"

5) "field3"

6) "world"

127.0.0.1:6379[8]>

127.0.0.1:6379[8]> hlen myhash    获取长度

(integer) 3

 

 

127.0.0.1:6379[8]> HEXISTS myhash field5

(integer) 0

127.0.0.1:6379[8]> HEXISTS myhash field1  判断是否存在

(integer) 1

 

只获取所有的key

127.0.0.1:6379[8]> HKEYS myhash

1) "field"

2) "field1"

3) "field3"

 

只获取所有的值

127.0.0.1:6379[8]> HVALS myhash

1) "world"

2) "hello"

3) "world"

 

127.0.0.1:6379[8]> hset myhash field9 5   指定增量

(integer) 1

127.0.0.1:6379[8]> HINCRBY myhash field9 1

(integer) 6

127.0.0.1:6379[8]> HINCRBY myhash field9 -1

(integer) 5

127.0.0.1:6379[8]> hsetnx myhash field4 hello 如果不存在则可以设置

(integer) 1

127.0.0.1:6379[8]> hsetnx myhash field4 world   存在不可以设置

(integer) 0

127.0.0.1:6379[8]>

 

应用场景:变更操作,尤其是用户信息,经常变动的信息 hash更适合于对象的存储,String更加适合字符串存储

 

ZSetSet的基础上增加一个值

有序的

 

127.0.0.1:6379[8]> zadd myset 1 one  增加一个值

(integer) 1

127.0.0.1:6379[8]> zadd myset 2 two

(integer) 1

127.0.0.1:6379[8]> zadd myset 3 three  增加多个值

(integer) 1

127.0.0.1:6379[8]> zrange myset 0 -1

1) "one"

2) "two"

3) "three"

 

排序

从小到大

127.0.0.1:6379[8]> zadd salary 2500 xiaohong  添加用户薪水

(integer) 1

127.0.0.1:6379[8]> zadd salary 5000 mochen

(integer) 1

127.0.0.1:6379[8]> zadd salary 500 kuangshen

(integer) 1

127.0.0.1:6379[8]> ZRANGEBYSCORE salary -inf +inf   从小到大排序

1) "kuangshen"

2) "xiaohong"

3) "mochen"

127.0.0.1:6379[8]> ZRANGEBYSCORE salary 0 -1

(empty list or set)

127.0.0.1:6379[8]> ZRANGEBYSCORE salary +inf -inf

(empty list or set)

127.0.0.1:6379[8]> ZRANGEBYSCORE salary -inf +inf withscores    从小到大排序并且附带薪水

1) "kuangshen"

2) "500"

3) "xiaohong"

4) "2500"

5) "mochen"

6) "5000"

127.0.0.1:6379[8]> ZRANGEBYSCORE salary -inf 2500 withscores  显示工资小于2500的升序排序

1) "kuangshen"

2) "500"

3) "xiaohong"

4) "2500"

 

从大到小

127.0.0.1:6379[8]> ZREVRANGE salary 0 -1 

1) "mochen"

2) "kuangshen"

 

 

移除元素

127.0.0.1:6379[8]> zrange salary 0 -1

1) "kuangshen"

2) "xiaohong"

3) "mochen"

127.0.0.1:6379[8]> zrem salary xiaohong    移除有序集合中的指定元素

(integer) 1

127.0.0.1:6379[8]> zrange salary 0 -1

1) "kuangshen"

2) "mochen"

 

 

获取有序集合中的个数

127.0.0.1:6379[8]> ZCARD salary

(integer) 2

 

 

获取指定区间的成员数量

127.0.0.1:6379[8]> zadd myset 1 hello 2 world 3 mochen

(integer) 3

127.0.0.1:6379[8]> zcount myset 1 3

(integer) 3

 

使用场景:set排序   存储当前成绩表,工资表排序!

普通消息,重要消息2 ,带权重进行判断

排行榜应用实现,Top N

 

三种特殊数据类型:

Geospatial :地理位置

朋友的定位,附近的人,打车距离计算

RedisGeo Redis3.2就推出了 可以推算地理位置信息,两地之间的距离

 

  • 有效经度为 -180 180 度。

  • 有效纬度是从      -85.05112878 85.05112878 度。

 

来自 <https://redis.io/commands/geoadd>

127.0.0.1:6379[8]> geoadd china:city 39.90 116.40 beijing

(error) ERR invalid longitude,latitude pair 39.900000,116.400000

 

 

可以查询一些测试数据:http://www.jsons.cn/lngcodeinfo/0844F38DEC46A106

 

Geoadd:

添加位置

规则 两级无法直接添加,我们一般会下载城市数据,直接通过Java程序一次性导入

参数key 值(维度,经度,名称

127.0.0.1:6379[8]> geoadd china:city 116.40 39.90 beijing

(integer) 1

127.0.0.1:6379[8]> geoadd china:city 121.47 31.23 shanghai

(integer) 1

127.0.0.1:6379[8]> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shengzhen

(integer) 2

127.0.0.1:6379[8]> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian

(integer) 2

127.0.0.1:6379[8]>

Geopos:

获得当前定位

127.0.0.1:6379[8]> geopos china:city beijing  获取指定的城市经度维度

1) 1) "116.39999896287918"

   2) "39.900000091670925"

127.0.0.1:6379[8]> geopos china:city beijing chongqing

1) 1) "116.39999896287918"

   2) "39.900000091670925"

2) 1) "106.49999767541885"

   2) "29.529999579006592"

 

Geodist:

两人之间距离!

给定一个表示地理空间索引的排序集,使用GEOADD命令填充,该命令返回指定单位中两个指定成员之间的距离。

如果缺少一个或两个成员,则该命令返回 NULL

单位必须是以下之一,默认为米:

  • m为米。

  • 公里为公里。

  • 英里数英里。

  • 英尺为英尺。

127.0.0.1:6379[8]> geodist china:city beijing shanghai   查看北京到上海的直线距离

"1067378.7564"

127.0.0.1:6379[8]> geodist china:city beijing shanghai km  查看北京到上海的直线距离 单位是千米

"1067.3788"

127.0.0.1:6379[8]> geodist china:city beijing chongqing 

"1464070.8051"

 

Georedius:

我附近的人,获取所有附近的人,定位,地址,通过半径查询

127.0.0.1:6379[8]> GEORADIUS china:city 110 30 1000 km  11030这个经纬度为中心,寻找方圆1000km内的城市

1) "chongqing"

2) "xian"

3) "shengzhen"

4) "hangzhou"

127.0.0.1:6379[8]> GEORADIUS china:city 110 30 500 km

1) "chongqing"

2) "xian"

127.0.0.1:6379[8]> GEORADIUS china:city 110 30 500 km withdist   显示到中心距离的位置

1) 1) "chongqing"

   2) "341.9374"

2) 1) "xian"

   2) "483.8340"

127.0.0.1:6379[8]> GEORADIUS china:city 110 30 500 km withcoord  显示他人的定位信息

1) 1) "chongqing"

   2) 1) "106.49999767541885"

      2) "29.529999579006592"

2) 1) "xian"

   2) 1) "108.96000176668167"

      2) "34.2599996441893"

127.0.0.1:6379[8]> GEORADIUS china:city 110 30 500 km withdist withcoord count 1  筛选指定结果

1) 1) "chongqing"

   2) "341.9374"

   3) 1) "106.49999767541885"

      2) "29.529999579006592"

 

GEORADIUSBYMEMBER

城市之间定位,找出位于指定元素周围的其他元素

127.0.0.1:6379[8]> GEORADIUSBYMEMBER china:city shanghai 400 km

1) "hangzhou"

2) "shanghai"

 

GEOHASH:

将二维的经纬度转换为一维的字符串

127.0.0.1:6379[8]> GEOHASH china:city beijing chongqing

1) "wx4fbxxfke0"

2) "wm5xzrybty0"

 

 

GEO底层原理其实就是Zset我们可以使用Zset命令来操作GEo

127.0.0.1:6379[8]> zrange china:city 0 -1  查看地图中全部元素

1) "chongqing"

2) "xian"

3) "shengzhen"

4) "hangzhou"

5) "shanghai"

6) "beijing"

127.0.0.1:6379[8]> zrem china:city beijing  移除元素

(integer) 1

127.0.0.1:6379[8]> zrange china:city 0 -1

1) "chongqing"

2) "xian"

3) "shengzhen"

4) "hangzhou"

5) "shanghai"

 

Hyperloglog:

 

基数?不重复的元素,可以接受误差

简介:

Redis2.8.9就更新了。

基数统计的算法

优点:占用的内存是固定的,

 

127.0.0.1:6379[8]> PFADD mykey a b c d e f g h i j   创建第一组元素  mykey

(integer) 1

127.0.0.1:6379[8]> PFCOUNT mykey   统计元素基数数量

(integer) 10

127.0.0.1:6379[8]> PFADD mykey2 i j z  x c b n m

(integer) 1

127.0.0.1:6379[8]> PFCOUNT mykey2

(integer) 8

127.0.0.1:6379[8]> PFMERGE mykey3  mykey mykey2   合并两组 mykey3 并集

OK

127.0.0.1:6379[8]> PFCOUNT mykey3

(integer) 14

 

 

Bitmaps:

统计疫情感染人数,统计用户信息,打卡

Bitmaps数据结构,位图,都是操作二进制位来进行记录,

 

127.0.0.1:6379[8]> setbit sign 0 1

(integer) 0

127.0.0.1:6379[8]> setbit sign 1 0

(integer) 0

127.0.0.1:6379[8]> setbit sign 2 0

(integer) 0

127.0.0.1:6379[8]> setbit sign 3 0

(integer) 0

127.0.0.1:6379[8]> setbit sign 4 0

(integer) 0

127.0.0.1:6379[8]> setbit sign 5 0

(integer) 0

127.0.0.1:6379[8]> setbit sign 6 0

(integer) 0

127.0.0.1:6379[8]> GETBIT sign 3

(integer) 0

127.0.0.1:6379[8]> GETBIT sign 0

(integer) 1

127.0.0.1:6379[8]> BITCOUNT sign   统计这周打卡天数

(integer) 1

127.0.0.1:6379[8]>

 

事务:

Redis事务本质:一组命令集合!一个事务中的所有命令,都会被序列化,在事务执行过程中,会按照顺序执行,一次性,顺序性,排他性!执行一系列命令

Redis单挑命令是保证原子性的,但是事务是不保证原子性的 ,没有隔离级别的概念

所有的命令在事务中,并没有直接被执行,只有发起执行命令的时候才会被执行

 

开启事务(MULTI)

命令入队(….

执行事务(exec

锁:乐观锁

 

正常执行事务:

127.0.0.1:6379[8]> multi  开启事务

OK

127.0.0.1:6379[8]> set k1 v1   命令入队

QUEUED

127.0.0.1:6379[8]> set k2 v2

QUEUED

127.0.0.1:6379[8]> get k2

QUEUED

127.0.0.1:6379[8]> set k3 v3

QUEUED

127.0.0.1:6379[8]> exec    执行事务

1) OK

2) OK

3) "v2"

4) OK

127.0.0.1:6379[8]>

 

放弃事务:放弃后不会执行

127.0.0.1:6379[8]> MULTI

OK

127.0.0.1:6379[8]> set k5 v5

QUEUED

127.0.0.1:6379[8]> set k6 v6

QUEUED

127.0.0.1:6379[8]> DISCARD   放弃事务

OK

127.0.0.1:6379[8]> get k5

(nil)

 

变异性异常(命令有错),事物中,所有的命令都不会被执行

127.0.0.1:6379[8]> MULTI

OK

127.0.0.1:6379[8]> set k1 v1

QUEUED

127.0.0.1:6379[8]> set k2 v2

QUEUED

127.0.0.1:6379[8]> set k3 v3

QUEUED

127.0.0.1:6379[8]> getset k3   错误的命令

(error) ERR wrong number of arguments for 'getset' command

127.0.0.1:6379[8]> set k4 v4

QUEUED

127.0.0.1:6379[8]> set k5 v5

QUEUED

127.0.0.1:6379[8]> exec   执行事务报错

(error) EXECABORT Transaction discarded because of previous errors.

127.0.0.1:6379[8]> get k5  所有的命令都不会执行

(nil)

 

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

 

127.0.0.1:6379[8]> set k1 v1

OK

127.0.0.1:6379[8]> MULTI -

(error) ERR unknown command 'mult' 

127.0.0.1:6379[8]> multi

OK

127.0.0.1:6379[8]> incr k1  执行时会失败

QUEUED

127.0.0.1:6379[8]> set k2 v2

QUEUED

127.0.0.1:6379[8]> set k3 v3

QUEUED

127.0.0.1:6379[8]> exec

1) (error) ERR value is not an integer or out of range  第一条会报错,

2) OK

3) OK

 

监控:

悲观锁:

认为什么时候都会出问题,无论做什么都会加锁

乐观锁:

认为什么时候都不会出问题,所以不上锁,更新数据的时候去判断一下,在此期间是否有人修改过数据

获取version

更新的时候比较version

 

Redis监视测试

127.0.0.1:6379[8]> set money 100

OK

127.0.0.1:6379[8]> set out 0

OK

127.0.0.1:6379[8]> watch money  监视 money对象

OK

127.0.0.1:6379[8]> MULTI 监视正常结束,数据期间没有发生变动,这个时候就正常执行成功

OK

127.0.0.1:6379[8]> DECRBY money 20

QUEUED

127.0.0.1:6379[8]> INCRBY out 20

QUEUED

127.0.0.1:6379[8]> exec

1) (integer) 80

2) (integer) 20

正常执行成功

 

测试多线程修改值,监视失败使用watch可以当作redis的乐观锁操作!

 

127.0.0.1:6379[8]> watch money   监视money

OK

127.0.0.1:6379[8]> multi

OK

127.0.0.1:6379[8]> DECRBY money 10

QUEUED

127.0.0.1:6379[8]> INCRBY out 10

QUEUED

127.0.0.1:6379[8]> exec   执行前另外一个线程 修改值,这个时候,就会导致事务执行失败

(nil)

 

 

127.0.0.1:6379[8]> UNWATCH    如果发现事务执行失败,先解锁

OK

127.0.0.1:6379[8]> watch money   获取最新的值 再次监视 select version

OK

127.0.0.1:6379[8]> multi

OK

127.0.0.1:6379[8]> decrby money 10

QUEUED

127.0.0.1:6379[8]> incrby out 10

QUEUED

127.0.0.1:6379[8]> exec   比对监视的值,是否发生了变化

1) (integer) 990

2) (integer) 30

 

 

Jedis

我们使用Java来操作Redis

 

导入依赖

<dependencies>

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.9.0</version>

</dependency>

<!--fastjson-->

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>fastjson</artifactId>

<version>1.2.78</version>

</dependency>

</dependencies>

 

连接数据库

publicstaticvoidmain(String[]args){

//1newJedis对象即可

Jedisjedis=newJedis("127.0.0.1",6379);

//Jedis所有的命令

System.out.println(jedis.ping());

}

 

 

常用API就是上面的命令



Redis持久化:

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

RDB

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

Redis会单独创建(fork)一个子进程进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,在用这个临时文件替换上次持久化好的文件,整个过程中,主进程是不进行IO操作的,这就确保了极高的性能,如果需要大规模数据的恢复,且对于数据恢复的完整性不是非常铭感,那RDB方式要比AOF方式更加的高校,RDB的缺点是最后一次持久化的数据可能丢失(在最后一次宕机的时候,容易造成数据丢失),我们默认的就是RDB

RDB保存的文件是dump.rdb,都是在我们的配置文件中快照进行配置的

触发规则:

1save的规则满足的条件下,会自动触发RDB规则

2、执行flushAll命令,也会触发我们的RDB 规则

3、退出REDIS,也会产生RDB文件

备份就会自动生成一个dump.rdb

 

如何恢复RDB文件

1、只需要将RDB文件放在我们的Redist启动目录就可以了,redis启动的时候就会自动检查dump.rdd,恢复启动其中的数据!

2、查看需要存放的位置

127.0.0.1:6379> config get dir

1) "dir"

2) "D:\\Redis\\Redis-x64-3.2.100"   如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据

优点:

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

2、对数据的完整性要求不高!

缺点:

1、需要一定的时间间隔进程操作,如果redis意外宕机了, 这个最后一次修改数据就没有了

2fork进程的时候,会占用一定的内容空间 !!

 

AOF:

将我们的所以命令记录下来,恢复的时候,就把这个文件执行一遍

默认是不开启的,我们需要手动进行配置,我们只需要开启appendonly改为yes即可开启了AOF

重启reids即可生效

如果这个AOF文件有错位,这时候Redis是启动不起来的,我们需要修复这个AOF文件

redis给我们提供了一个工具,redis-check-aof --fix

如果文件正常,重启就可以直接恢复了

优点:

1、每一次修改,都同步文件的完整性就更加好

2、每秒同步一次,可能会丢失一秒的数据

3、从不同步,效率最高

缺点:

1、相对于数据文件来说,aof远远大于RDB,修复的速度也比RDB慢,

2AOF运行效率也要比RDB慢,所以我们Redis默认的配置就是RDB持久化,而不是AOF

 

Redis订阅:

订阅端:

127.0.0.1:6379[8]> SUBSCRIBE mochenshuo   订阅 一个频道

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "mochenshuo"

3) (integer) 1

1) "message"  消息

2) "mochenshuo"  来自哪个频道

3) "hello,world"   具体内容

1) "message"

2) "mochenshuo"

3) "hello,mochen"

发送端:

 

127.0.0.1:6379> PUBLISH mochenshuo "hello,world"  发布消息到频道

(integer) 1

127.0.0.1:6379> PUBLISH mochenshuo "hello,mochen"

(integer) 1

127.0.0.1:6379>

 

使用场景:

实时消息系统

 

主从复制:

作用:

1、数据冗余;2、故障恢复;3、负载均衡;4、高可用基石

 

环境配置:

只配置从库,不用配置主库

查看当前库信息

127.0.0.1:6379> info replication

# Replication

role:master  角色

connected_slaves:0 没有从机

master_repl_offset:0

repl_backlog_active:0

repl_backlog_size:1048576

repl_backlog_first_byte_offset:0

repl_backlog_histlen:0

 

复制3个配置文件,修改对应的信息

1、端口

2pid名称

3log文件的名字

4dump.rdb名字

 

默认三台都是主机

认老大,一个主机,一主二从

 

在从机中配置:

127.0.0.1:6379> SLAVEOF 127.0.0.1 6379  SLAVEOF host  6379 找谁当自己的老大

 

细节了解:

主机可以写,从机只能读,主机中的所有数据都会被从机保存

测试:

主机断开连接,从机依旧连接到主机,但是没有写操作,这个时候,主机如果回来了,从机,依旧可以直接获取主机写的信息!

如果是使用命令行配置的主从,如果从库重启,那么就会变回主库,主要变回从机,就会立马拿到主机数据

 

哨兵模式(自动选取主库):

  配置哨兵:Sentinel.conf
 

Sentinel monitor myredis 127.0.0.1 6379 1

数字一代表主机宕机了,slave投票让谁接替为主机

2、启动

优点:

哨兵集群,基于主从复制模式,所有的主从配置的优点,全有

主从可以切换,故障可以转移,系统的可用性会更好

哨兵模式,就是主从模式的升级

缺点:

Redis不好在线扩容,集群的容量一旦上限,在线扩容十分麻烦

 

缓存穿透和雪崩:

穿透:

解决方案:

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统 的查询压力

缓存空对象,当存储层不命中后,即使返回的空对象也将其缓存起来,同时设置一个过期时间,之后在访问这个数据将会从缓存中获取,保护了后端数据源;

缓存击穿(量太大,缓存过期):

解决方案:

设置热点数据永不过期,从缓存层来看,没有设置过期时间,所以不会出现热点key过期后产生的问题

加互斥锁:分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可,这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大

 

雪崩:

解决方案:
 

1.保证缓存服务的高可用性,比如使用Redis哨兵监控Redis集群以及使用Redis Cluster等。即使单个节点宕机了,备用节点还能顶上去保证服务可用。

做二级缓存,当一级缓存停止服务,或大量失效时,由二级缓存顶住访问压力。

不同的key之间的失效时间设置不同保证数据失效均衡。


  • 评论列表

留言评论