0%

Redis基础大全

一、安装与配置

  1. 安装gcc:yum install gcc -y
  2. 下载redis-x.x.x.tar.gz,并解压:tar -zxvf redis-x.x.x.tar.gz
  3. 进入redis解压目录,执行命令make和make install,不报错就表示安装成功,默认安装位置在/usr/local/bin目录下
  4. 开启redis后台启动,将redis解压目录下的redis.conf文件复制到其他位置,比如/etc目录下
  5. 修改redis.conf文件,找到daemonize字段,将其后的值no改为yes后,保存退出
  6. 执行命令redis-server /etc/redis.conf,即可后台开启redis
  7. 使用redis客户端访问redis服务,执行命令redis-cli进入redis客户端

二、Redis语法

2.1 数据类型

  • 字符串String
  • 列表List
  • 集合Set
  • 哈希Hash
  • 有序集合Zset

2.2 常用命令

命令 解释
ping 查看服务是否正常运行
dbsize 查看当前数据库中key的数目(返回值为integer)
select 0 切换数据库,默认使用的是db0
Redis默认操作16个数据库,序号为0~15
flushdb 删除当前操作的数据库中的内容
flushall 删除所有的库中的数据
keys pattern 查找所有符合pattern的key,pattern可以使用统配符
exists [key…] 判断key是否存在,存在key返回1,不存在返回0;
使用多个key,则执行后返回key的数量
expire [key] [seconds] 设置key的生存时间,超过时间key自动删除;单位是秒;
设置成功返回1,其他情况是0
ttl [key] 以秒为单位,返回key的剩余生存时间;
-1:表示没有设置 key 的生存时间, key 永不过期;
-2 :表示key 不存在;其他表示剩余时间
type [key] 查看key所存储的数据类型
del [key…] 删除指定的key,不存在的key进行忽略;
返回值:数字,删除的key的数量

2.3 字符串String

  • 虽然给某个key设置的值是数字,但key的类型仍然是字符串,数字是以字符串的形式存储的,增加和减小操作也是基于字符串的操作
命令 解释
set [key] [value] 将字符串值设置到key中;设置成功返回OK
get [key] 获取数据库中key的值;
返回值:key对应的value值
incr [key] 将 key 中储存的数字值加 1
如果 key 不存在,则创建 key 并初始化其值为 0 再执行incr 操作(只能对数字类型的数据操作)
decr [key] 与incr作用相反,是减1操作
append [key] [value] 字符串追加;
如果 key 存在, 则将 value 追加到 key 原来旧值的末尾
如果 key 不存在, 则将 key 设置值为 value;
返回值:追加后的字符串总长度
strlen [key] 返回 key 所储存的字符串值的长度
getrange [key] [start] [end] 获取 key 中字符串值从 start 开始 到 end 结束 的子字符串,包括 start 和 end
负数表示从字符串的末尾开始, -1 表示最后一个字符
setrange [key] [offset] [value] 用 value 覆盖(替换)key 的从offset位置开始存储的值
不存在的 key ,在offset前填充空白字符
返回值:修改后的字符串的长度
mset [key value…] 同时设置一个或多个 key-value
返回值: OK
mget [key …] 获取所有(一个或多个)给定 key 的值
包含所有 key 的列表

2.4 列表List

2.4.1 原理

  • 单键多值
  • 底层:双向链表

2.4.2 命令

命令 解释
lpush/rpush key [value…] 从左/右侧将一个或多个值 value 插入到列表 key 的表头
从左侧插入属于头插法,列表顺序为倒序
返回值:数字,新列表的长度
lpop/rpop
rpoplpush
lrange [key] [start] [stop] 获取列表 key 中指定区间内的元素,0表示第一个元素,-1为最后一个元素
返回值:指定区间的列表
lindex [key] [index] 获取列表 key 中下标为指定 index 的元素
返回值:指定下标的元素;index 不在列表范围,返回 nil
llen [key] 获取列表 key 的长度
返回值:数值,列表的长度; key 不存在返回 0
lrem [key] [count] [value] 移除列表中count个与value相等的元素
count>0从列表左侧开始移除;
count<0从列表右侧开始移除;
count=0移除表中所有与 value 相等的值
lset [key] [index] [value] 将列表 key 下标为 index 的元素的值设置为 value
返回值:设置成功返回 ok ; key 不存在或者 index 超出范围返回错误信息

2.5 集合Set

2.5.1 原理

  • 底层:hash表

2.5.2 命令

命令 解释
sadd [key] [member…] 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略,不会再加入。
返回值:加入到集合的新元素的个数。不包括被忽略的元素
smembers [key] 获取集合 key 中的所有成员元素,不存在的 key 视为空集合
sismember [key] [member] 判断 member 元素是否是集合 key 的成员返回值:member 是集合成员返回 1,其他返回 0
scard [key] 获取集合里面的元素个数
返回值:数字,key 的元素个数。 其他情况返回 0
srem [key] [member…] 删除集合 key 中的一个或多个 member 元素,不存在的元素被忽略
返回值:数字,成功删除的元素个数,不包括被忽略的元素。

2.6 有序集合Zset

2.6.1 原理

2.6.2 命令

命令 解释
zadd [key] [[score] member…] 将一个或多个 member 元素及其 score 值加入到有序集合 key 中,如果 member存在集合中,则更新值;score 可以是整数或浮点数
返回值:数字,新添加的元素个数
zrange [key] [start] [stop] [WITHSCORES] 查询有序集合,指定区间的内的元素。集合成员按 score 值从小到大来排序
WITHSCORES 选项让 score 和 value 一同返回
zrem [key] [member…] 删除有序集合 key 中的一个或多个成员,不存在的成员被忽略
返回值:被成功删除的成员数量,不包括被忽略的成员。
zcard [key] 获取有序集 key 的元素成员的个数
返回值:key 存在返回集合元素的个数, key 不存在,返回 0

三、Redis配置文件

四、Redis发布和订阅

4.1 简介

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

4.2 示例

  • 打开两个redis客户端,分别为A、B,A为发送者,B为订阅者
  • A执行命令public channel1 hello,表示向channel1频道发布信息hello
    • 命令执行后的返回值表示订阅者的数量
  • B执行命令SUBSCRIBE channel1,表示接收channel1的频道
    • 返回的是频道的信息列表

五、其他数据类型

5.1 Bitmaps

5.1.1 原理

  • 存储二进制的字符串,比如user=00001

    • 其中value为00001在Redis中依旧是以字符串的形式存储的
    • 偏移量offset从0开始算起,这里value中1的偏移量就是4
    • 想要得到以上的KV对,需要执行命令setbit user 4 1
  • Bitmaps可以用来保存用户活跃度,Set集合也可以做,但两者有区别

    • 当用户活跃量特别大时,使用Bitmaps可以极大的减少存储空间
    • 当用户活跃量比较小时,使用Set集合则比较合适

5.1.2 命令

命令 解释
setbit [key] [offset] [value] 将key的offset位置的值设置为value
getbit [key] [offset] 获取key中offset位置的值
bitcount [key] [start,end] 不指定[start,end]时,统计key中value所有被设置为1的bit个数
指定[start,end]时,这里的start和end表示的是字节下标,[1,2]表示统计第一个字节(8位)到第二个字节中1的个数,[0,-2]则表示统计从0到倒数第二个字节中1个数

5.2 HyperLogLog

5.2.1 原理

  • 计算基数(集合中不重复元素个数)的一种算法
  • 对比Set,所占内存更小,统计的范围更大,重复的元素不会被添加进去

5.2.2 命令

命令 解释
pfadd [key] [element…] 添加指定元素到HyperLogLog中
返回值:添加重复元素返回0,添加不重复元素返回1
pfcount [key…] 统计某个key的基数个数
pfmerge [destkey] [sourcekey…] 合并多个sourcekey后,将结果存放到destkey中

5.3 Geospatial

5.3.1 原理

  • 存放地理信息的数据结构,即表示经纬度的二维坐标

5.3.2 命令

命令 解释
geoadd [key] [[longitude] [latitude] [menber]…] 添加地理位置信息,(经度,纬度,名称)
示例:geoadd china 100 100 shanghai 120 120 beijin
geopos [key] [member…] 获取key中名称位member的经纬度坐标
geodist [key] [member1] [member2] [m\ km\ ft\ mi] 获取key中member1和member2的直线距离,后面可以设置单位,m为默认单位
georadius [key] [longitude] [latitude] radius m\ km\ ft\ mi 以给定的经纬度坐标为中心,找出key中包含在半径为radius的圆中的member名称列表

六、Jedis

七、Springboot整合Redis

7.1 配置环境

7.1.1 引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.6</version>
</dependency>

<!-- 提供池化操作 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>

7.1.2 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#Redis服务器地址
spring.redis.host=192.168.47.33
#Redis服务器连接端口
spring.redis.port=6379
#Redis数据库索引(默认位0)
spring.redis.database=0
#连接超时时间(毫秒)
spring.redis.timeout=1800000
#连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待时间(复数表示没有限制)
spring.redis.lettuce.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=5
#连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0

7.1.3 Redis配置类

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {

@Resource
private LettuceConnectionFactory lettuceConnectionFactory;

/**
* @description 自定义的缓存key的生成策略 若想使用这个key
* 只需要讲注解上keyGenerator的值设置为keyGenerator即可</br>
* @return 自定义策略生成的key
*/
@Override
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getDeclaringClass().getName());
Arrays.stream(params).map(Object::toString).forEach(sb::append);
return sb.toString();
}
};
}

/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);// key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

/**
* 缓存配置管理器
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

// 以锁写入的方式创建RedisCacheWriter对象
//RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
// 创建默认缓存配置对象
/* 默认配置,设置缓存有效期 1小时*/
//RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
/* 配置test的超时时间为120s*/
RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.lockingRedisCacheWriter(factory)).cacheDefaults(redisCacheConfiguration)
.withInitialCacheConfigurations(singletonMap("test", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(120)).disableCachingNullValues()))
.transactionAware().build();
return cacheManager;
}

}

7.2 RedisTemplate

八、事务

8.1 概念

  • Redis事务作用是串联多个命令并顺序执行
  • 一个redis客户端可以通过multi命令进入事务状态,并且事务在执行时不会被其他redis客户端打断

8.2 命令

命令 说明 备注
multi 开启事务命令,之后的命令就进入队列,而不会马上被执行 在事务生存期间,所有的 Redis 关于数据结构的命令都会入队
watch [key…] 监听某些键,当被监听的键在事务执行前被修改,则事务会被回滚 使用乐观锁
unwatch [key…] 取消监听某些键
exec 执行事务,如果被监听的键没有被修改,则采用执行命令,否则就回滚命令 在执行事务队列存储的命令前, Redis 会检测被监听的键值对有没有发生变化,如果没有则执行命令 ,否则就回滚事务
discard 回滚事务 回滚进入队列的事务命令,之后就不能再用 exec命令提交了

8.3 悲观锁/乐观锁

8.3.1 区别

  • 乐观锁和悲观锁的出现都是解决共享数据的操作问题
  • 悲观锁:每次操作共享数据时,都会给数据上锁,防止其他事务对其进行操作
    • “悲观”意思是在每次操作数据前都悲观的认为别人也会操作这个数据,所以必须加上锁,保证数据为自己所用。但这样做的缺点是效率不高
  • 乐观锁:不会像悲观锁一样每次操作前都加锁,而是让每个事务都能对共享数据进行操作,哪个事务操作的快,则更新当前版本,这样过去版本的事务操作就会因为版本不匹配而无法执行

8.3.2 示例

  • watch
  • unwatch

8.3.3 事务特性

  • 隔离性:客户端事务在执行时不能被其他客户端命令打断,没有隔离级别概念
  • 原子性:不保证原子性,因为一条命令执行失败,其他命令仍然会执行,不会执行回滚

九、秒杀案例

9.1 并发模拟

9.1.1 http-tools

  • 安装httpd-tools:yum install httpd-tools
  • httpd-tools中包含有ab命令

9.1.2 ab命令

  • ab -n 1000 -c 100 -p ~/postfile -T ‘application/x-www-form-urlencoded’ 请求地址

    • -n:表示请求次数
    • -c:表示并发数
    • -T content-type:POST/PUT 数据所使用的Content-type头信息
    • -p postfile:包含要 POST 的数据的文件,记得还要设置 -T 参数
  • 命令返回结果

    • Concurrency Level: 并发量
    • Time taken for tests: 整个测试的时间
    • Complete requests: 完成的总请求数
    • Failed requests: 失败的请求数
    • Total transferred: 响应数据的总长度(包括http头信息和消息体数据)
    • HTML transferred: 响应数据中消息体数据的总和
    • Requests per second:吞吐率(计算方式为:Complete requests / Time taken for tests,也就是 完成的总请求数 / 整个测试的时间)
    • Time per request: 用户平均请求等待时间
    • Time per request: 服务器平均请求等待时间
    • Transfer rate: 单位时间内从服务器获取的数据长度(计算方式为:Total transferred / Time taken for tests, 也就是 响应数据的总长度(包括http头信息和消息体数据)/ 整个测试的时间)

9.1 案例源码

十、持久化操作

10.1 RDB(默认方式)

  • 读时共享,写时复制

10.2 AOF

十一、主从复制

十二、集群

十三、换成

十四、分布式锁