本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、Redis 高级特性
1. Redis事务
Redis的事务与数据库的事务概念不同,Redis会将一个事务中的所有命令序列化,然后按顺序执行。Redis不可能在一个Redis事务的执行过程中插入执行另一个客户端发出的请求,事务中任意命令失败不影响其他命令的执行,也不会回滚。
2. 发布订阅
发布订阅是一种通信模式,发送者发送消息,订阅者接受消息。客户端可以订阅多个频道,然后有新消息发送给频道,订阅该频道的客户端就都能收到消息。
常用命令:
- subscribe channel [channel ...] 订阅一个或多个频道
- psubscribe pattern [pattern ...] 订阅一个或多个符合给定模式的频道
- publish channel message 将消息发送到指定通道
- unsubscribe [channel [channel ...]] 退订给定的频道
- punsubscribe channel [channel ...] 退订所有给定模式的频道。
3. 脚本
Redis 脚本通过Lua解释器来执行脚本,Redis 2.6 版本通过内嵌支持Lua环境
基本语法如下:
EVAL script numkeys key [key ...] arg [arg ...]
例子:
| 1 | EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second |
4. Redis Stream
Redis Stream是5.0版本新增的数据结构。Redis Stream主要用于消息队列,Redis本身有一个发布/订阅功能,但是它有一个缺点,消息没有持久化,如果网络中断或宕机,数据就会丢失。
Redis Stream提供了消息的持久化和主备复制功能,它有一个消息链表,把所有加入的消息都串起来,每个消息都有唯一的ID和内容。
常用命令:
- xadd key ID field value [field value ...] 添加消息
xadd mystream * name sa surname occc (*代表id由redis生成)
- xdel key ID [ID ..] 删除消息
- xrange key start end [COUNT count] 查看消息
xrange mystream - + (- 代表最小值,+ 代表最大值)
- xgroup [CREATE key groupname id-or-] [DESTROY key groupname] [DELCONSUMER key groupname consumername] 创建消费者组
从头开始消费:
xgroup create mystream consumer-group-name 0-0
从尾部开始消费,只接受新消息
xgroup create mystream consumer-group-name $
- xreadgroup group group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...] 从消费者组读取消息
XREADGROUP GROUP consumer-group-name consumer-name COUNT 1 STREAMS mystream
第二个group :消费组名
consumer: 消费者名
count :读取数量
milliseconds : 阻塞毫秒数
key :队列名
ID:消息id
二、Redis使用场景
1. 业务数据缓存
1.通用数据缓存:String、list
2.等会话缓存、token、session缓存
2. 业务数据处理
1.非严格一致性要求的数据
2.业务操作去重:订单处理的幂等校验业务数据排序
3. 全局一致计数
1.全局流控
2.秒杀时库存计算
3.全局ID生成
4. 高效统计计数
1.id、ip等使用bitmap操作
2.使用HyperLogLog进行UV、PV等非精确性的统计
5. 发布订阅与Stream
用于消息发布订阅模式
6. 分布式锁
1.获取锁
| 1 | set key my_random_value NX PX 30000 |
2.释放锁,需要用到lua脚本保证原子性
if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
三、Redis的Java客户端
1. Jedis
基于BIO、线程不安全,需要配置连接池管理连接
2. Lettuce
目前主流推荐的驱动,基于Netty NIO,API线程安全
3. Redission
基于Netty NIO,API线程安全。大量丰富的分布式功能,如分布式的基本数据类型和锁。
四、项目集成
1. SpringMvc项目可以引入Spring data redis
maven依赖
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
核心是RedisTemplate(可以配置基于Jedis、Lettuce、Redisson),封装了基本的redis命令。
2. SpringBoot接入(默认使用的Lettuce)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置spring.redis
如:spring.redis.host=127.0.0.1
3. Spring Cache 集成Redis
1.启用Spring Cache
| 1 | @EnableCaching |
2.方法上添加缓存注解
@EnableCaching
3.配置redisCache
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.create(redisConnectionFactory);
}
}
番外:
1.Redis到底是单线程,还是多线程?
这个问题有坑。首先Redis作为一个进程来讲是多个线程的。比如Redis通过多线程方式在后台删除对象、以及通过 Redis模块实现的阻塞命令等.单线程的地方在于探测哪个接收完了请求数据->数据处理->返回数据。而其他耗时操作是用了其他线程。
探测哪个客户端的请求接受完了,使用的是IO多路复用模型,“多路”是指多个网络连接,“复用”是复用同一个线程。
2.为什么IO模块在Redis6之前是单线程?
因为Redis是基于内存的操作,CPU不是瓶颈,瓶颈在于机器内存的大小或网络带宽。
3. Redis6之后的多线程是什么?
IO模型使用了多线程的NIO模型,内存处理线程也还是单线程。