Redis
Redis 使用的是客户端-服务器(CS)模型和请求/响应协议的 TCP 服务器。这意味着通常情况下一个请求会遵循以下步骤:
- 客户端向服务端发送一个查询请求,并监听 Socket 返回,通常是以阻塞模式,等待服务端响应。
- 服务端处理命令,并将结果返回给客户端。
Redis快的原因:
1.redis是基于内存的,内存的读写速度非常快;
2.redis是单线程的,省去了很多上下文切换线程的时间;
3.redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。
数据结构
- 字符串String
- 这是最简单的类型,就是普通的 set 和 get,做简单的 KV (KEY-VALUE)缓存
- 字典Hash、
- 列表List、
- 比如可以通过 List存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西。
- 集合Set、
- 是无序集合,会自动去重的那种
有序集合SortedSet。
补充:
HyperLogLog(也是set的规则,是用来做基数统计的算法,存储所占空间少,纯计数)
Geo、Pub/Sub进阶:Redis Module,像BloomFilter,RedisSearch,Redis-ML
Redis命令
Key
keys * 查询所有数据
exists key名 判断key名是否存在
move key名 数据库号(0-15) 移动数据key名到相应的数据库
expire key名 秒 过多少秒key名失效(删除)
ttl key名 查询key名还有多久过期 -1永不过期 -2已过期(或不存在)
type key名 判断key名是什么类型
String
- set (添加)、 get (获取值)、del(删除) 、append(追加) 、strlen (获取长度)
、SETNX key value
(只有在 key 不存在时设置 key 的值)。 - incr (增加1)、decr(减少1) 、incrby(按多少增加) 、decrby (按多少减少)
- setrang(命令用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始。)
1
2
3
4
5
6redis 127.0.0.1:6379> SET key1 "Hello World"
OK
redis 127.0.0.1:6379> SETRANGE key1 6 "Redis"
(integer) 11
redis 127.0.0.1:6379> GET key1
"Hello Redis"
List(单值多value)
- lpush (队列左先入栈)、 rpush(队列右先入栈) 、Larange
- lpop(左出)、rpop(右出)注意:这里和开始进入的有关系,即:lpush 、rpush
- lindex(按照索引下标元素获取值。从上到下)
hash
- HSET key field value(将哈希表 key 中的字段 field 的值设为 value ),
HGET key field 获取存储在哈希表中指定字段的值。
HMSET key field1 value1 [field2 value2 ]同时将多个 field-value (域-值)对设置到哈希表 key 中,
HMGET key field1 [field2] 获取多个给定字段的值
HGETALL key 获取在哈希表中指定 key 的所有字段和值
2. HDEL key field1 [field2] 删除一个或多个哈希表字段
HVALS key 获取哈希表中所有值。
HGETALL key
HKEYS key 获取所有哈希表中的字段
HLEN key 获取哈希表中字段的数量
set
- SADD key member1 [member2] 向集合添加一个或多个成员
SREM key member1 [member2] 移除集合中一个或多个成员
SCARD key 获取集合的成员数sorted set
ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数常见使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26连接到本机的redis
redis-cli
中文乱码时加raw
redis-cli --raw
执行 PING 命令,该命令用于检测 redis 服务是否启动。
redis 127.0.0.1:6379> PING
键命令
redis 127.0.0.1:6379> SET runoobkey redis
OK
redis 127.0.0.1:6379> GET runoobkey
"redis"
redis 127.0.0.1:6379> DEL runoobkey
(integer) 1
hash
127.0.0.1:6379> HMSET runoobkey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000
OK
127.0.0.1:6379> HGETALL runoobkey
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"
redis在java中的使用
典型问题
- key :假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
- 使用keys指令可以扫出指定模式的key列表。
- redis是单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
- Redis分布式锁
- 先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
- set 命令可以合并setnx和expire 保证原子性
1
2
3
4
5
6
7
8
9
10
11
12
13set key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds:设置失效时长,单位秒
PX milliseconds:设置失效时长,单位毫秒
NX:key不存在时设置value,成功返回OK,失败返回(nil)
XX:key存在时设置value,成功返回OK,失败返回(nil)
> set name p7+ ex 100 nx
OK
> get name
"p7+"
> ttl name
(integer) 94
- Redis做异步队列
- 一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep(list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。)一会再重试。
- 使用pub/sub主题订阅者模式,可以实现 1:N 的消息队列。
- 延时队列 : 使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。