本文最后编辑于 前,其中的内容可能需要更新。
一、概述
- 存储方式:key-value
- 支持的数据类型:string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。
- 新数据类型:
- Bitmaps–使用二进制单位,实现对位的操作,通过数据偏移量来计算
- HyPerLogLog–适用于需要去重和计数的基数问题
- Geospatial–适用于元素的二维坐标(经纬度)操作
- Redis支持各种不同方式的排序。
- 操作支持原子性
- 数据缓存在内存中
- 支持主从同步
- 端口号默认:6379
- 默认16个数据库,类似数组下标从0开始,初始默认使用0号库
- Redis是单线程+多路IO复用技术
二、安装
自行到官网:http://redis.io/下载当前系统支持版本:Windows/Linux
三、启动
前台(窗口)启动:
- 在 /bin下,redis-server (缺点:当关闭当前服务窗口后redis服务将关闭,优点:可以实时查看redis服务状态日志信息)
后台启动:
- 拷贝配置文件到指定目录:cp /opt/redis-3.2.5/redis.conf /myredis
- 修改配置文件 开启后台启动 vi redis.conf –>daemonize no 改为daemonize yes
- 使用修改后的配置文件启动 redis-server myredis/redis.conf
- 查看redis线程是否存在:ps -ef |grep redis
四、访问
#redis-cli 即可进入客户端
#ping 若出现pong 则通
#shutdown 关闭服务
#flushdb 清空当前库
#flushall 通杀全部库
#dbsize查看当前数据库的key的数量
#select dbid来切换数据库。如: select 8
五、Redis_Jedis 测试
引入依赖
1 2 3 4 5
| <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.2.0</version> </dependency>
|
连接Redis注意事项
禁用Linux的防火墙:Linux(CentOS7)里执行命令
systemctl stop/disable firewalld.service
redis.conf中注释掉bind 127.0.0.1 ,然后 protected-mode no
测试程序:demo.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import redis.clients.jedis.Jedis;
public class Demo01 {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.137.3",6379);
String pong = jedis.ping();
System.out.println("连接成功:"+pong);
jedis.close();
}
}
|
可以完成手机验证码功能
1、输入手机号,点击发送后随机生成6位数字码,2分钟有效
2、输入验证码,点击验证,返回成功或失败
3、每个手机号每天只能输入3次(设置数据过期时间)
整合Springboot
引入依赖
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency>
|
配置redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring.redis.host=192.168.140.136
spring.redis.port=6379
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
|
添加配置类
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
| @EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport {
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setConnectionFactory(factory);
template.setKeySerializer(redisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; }
@Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(600)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } }
|
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RestController @RequestMapping("/redisTest") public class RedisTestController { @Autowired private RedisTemplate redisTemplate;
@GetMapping public String testRedis() { redisTemplate.opsForValue().set("name","lucy"); String name = (String)redisTemplate.opsForValue().get("name"); return name; } }
|
六、分布式事务锁
乐观锁
- 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
悲观锁
- 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
七、redis事务的三大特性
①单独的隔离操作
- 事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
②没有隔离级别的概念
- 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
③不保证原子性
- 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
八、持久化
redis提供两种持久化方式:RDB、AOF
如何执行备份:
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式(实时<可以控制时间间隔>进行持久化操作)更加的高效。RDB****的缺点是最后一次持久化后的数据可能丢失。
小结:官方推荐两个都启用。如果对数据不敏感,可以选单独用RDB。不建议单独用 AOF,因为可能会出现Bug。如果只是做纯内存缓存,可以都不用。
九、分布式
主从复制
哨兵模式:能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
redis集群:实现扩容、分摊压力、无中心配置相对简单;缺点:不支持多键操作、不支持Lua脚本
十、应用问题
缓存穿透:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。
- 解决:对空值进行缓存、设置可访问的白名单、采用布隆过滤器、实时监控
缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
缓存雪崩:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
- 解决:创建多级缓存架构、使用锁或队列、设置过期标志更新缓存、将缓存失效时间分散开