一、是什么?
redis是高性能key value非关系型数据库,C语言开发,基于内存的,速度极快,用作分布式缓存和分布式锁,每秒处理10万次读写。支持事务持久化lua脚本集群。
5种数据类型:String,list,set,sorted set,hash(全部通过redisObject对象进行存储)
redis客户端与服务器
二、特性
支持丰富的数据类型,速度快(读11万次每秒,写8万次每秒),可持久化(AOF,RDB)
单线程,Redis使用队列技术,将并发访问变为串行访问,消除了传统数据库串行控制的开销,消除了并发竞争
支持事务和主从复制
数据库容量受内存限制,不能用作海量数据的高性能读写。
不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分请求失败,需要等待机器重启或主动切换前端IP
主机宕机,切换IP后还会导致数据不一致,降低系统可用性
1、Redis为什么这么快?
完全基于内存,绝大部分请求是存粹内存操作,速度非常快。数据结构简单。单线程避免了不必要的上下文切换和竞争条件,不用考虑锁的问题以及加锁释放锁,不存在死锁导致性能开销。使用IO多路复用模型,是非阻塞IO。Redis直接构建了VM机制,一般系统调用函数,会浪费性能。
三、使用场景
@SpringBootTest public class Redis3ApplicationTests { @Test public void increase() throws InterruptedException { long currentTimeMillis = System.currentTimeMillis(); Thread thread = new Thread(new Runnable() { Jedis jedis = RedisUtil.getJedis(); @Override public void run() { for (int i = 0; i <10000; i++) { Long num = jedis.incr("num"); } } }); thread.start(); thread.join(); System.out.println("耗时"+(System.currentTimeMillis() - currentTimeMillis)); } } 计数器
package com.yhq.redis3.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class RedisUtil { //Redis服务器IP private static String ADDR = "127.0.0.1"; //Redis的端口号 private static int PORT = 6379; //访问密码 private static String AUTH = "root123456"; //可用连接实例的最大数目,默认值为8; //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。 private static int MAX_TOTAL = 8; //最小空闲连接数, 默认0 private static int MIN_IDLE=0; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。 //最大空闲连接数, 默认8个 private static int MAX_IDLE = 8; //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1 //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException; private static int MAX_WAIT = -1; private static int TIMEOUT = 10000; //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true private static boolean BLOCK_WHEN_EXHAUSTED = false; //设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数) private static String EVICTION_POLICY_CLASSNAME="org.apache.commons.pool2.impl.DefaultEvictionPolicy"; //是否启用pool的jmx管理功能, 默认true private static boolean JMX_ENABLED=true; //MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默认为"pool", JMX不熟,具体不知道是干啥的...默认就好. private static String JMX_NAME_PREFIX="pool"; //是否启用后进先出, 默认true private static boolean LIFO=true; //逐出连接的最小空闲时间 默认1800000毫秒(30分钟) private static long MIN_EVICTABLE_IDLE_TIME_MILLIS=1800000L; //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略) private static long SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS=1800000L; //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 private static int NUM_TESTS_PER_EVICYION_RUN=3; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; //在获取连接的时候检查有效性, 默认false private static boolean TEST_ON_BORROW = false; //在空闲时检查有效性, 默认false private static boolean TEST_WHILEIDLE=false; //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 private static long TIME_BERWEEN_EVICTION_RUNS_MILLIS=-1; private static JedisPool jedisPool = null; /** * 初始化Redis连接池 */ static { try { JedisPoolConfig config = new JedisPoolConfig(); config.setBlockWhenExhausted(BLOCK_WHEN_EXHAUSTED); config.setEvictionPolicyClassName(EVICTION_POLICY_CLASSNAME); config.setJmxEnabled(JMX_ENABLED); config.setJmxNamePrefix(JMX_NAME_PREFIX); config.setLifo(LIFO); config.setMaxIdle(MAX_IDLE); config.setMaxTotal(MAX_TOTAL); config.setMaxWaitMillis(MAX_WAIT); config.setMinEvictableIdleTimeMillis(MIN_EVICTABLE_IDLE_TIME_MILLIS); config.setMinIdle(MIN_IDLE); config.setNumTestsPerEvictionRun(NUM_TESTS_PER_EVICYION_RUN); config.setSoftMinEvictableIdleTimeMillis(SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS); config.setTestOnBorrow(TEST_ON_BORROW); config.setTestWhileIdle(TEST_WHILEIDLE); config.setTimeBetweenEvictionRunsMillis(TIME_BERWEEN_EVICTION_RUNS_MILLIS); jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH); } catch (Exception e) { e.printStackTrace(); } } /** * 获取Jedis实例 * @return */ public synchronized static Jedis getJedis() { try { if (jedisPool != null) { Jedis resource = jedisPool.getResource(); return resource; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } /** * 释放jedis资源 * @param jedis */ public static void close(final Jedis jedis) { if (jedis != null) { jedis.close(); } } } jedispool 和 计数器
四、Redis线程模型
Redis线程模型
Redis 基于 Reactor 模式开发了自己的网络事件处理器: 这个处理器被称为文件事件处理器(file event handler)。文件事件处理器包括4个组成部分:套接字、I/O多路复用程序、文件事件分派器以及事件处理器。
时间事件应用实例:持续运行的redis服务器需要定期对自身的资源和状态进行检查和调整,从而确保服务器可以长期稳定的进行,这些定期操作主要工作包括:
五、缓存一致性问题
六、Redis持久化
持久化方案:Rdb和Aof。分为手动触发和自动触发两种。默认开启RDB,要实现AOF,需要在配置文件中配置 appendonly yes。
RDB方案,文件紧凑,体积小,网络传输快,适合全量复制,恢复速度比AOF快很多,对性能的影响相对较小。做不到实时持久化,容易造成数据大量丢失。切RDB文件格式兼容性差。
AOF方案,主流,文件大,恢复速度慢,对性能影响大,但支持秒级持久化,兼容性好。
选择策略:数据丢失没关系,则可不进行持久化,实时性要去不高,选择RDB,如果是秒级,则选AOF,但大多数会配置主从环境。
master最好不做持久化工作,如RDB内存快照和AOF文件。
redis服务器进程就是一个事件循环,这个循环中的文件时间负责接收客户端的命令请求以及向客户端发送命令回复,而时间事件则负责执行像serverCron函数这样需要定时运行的函数。
AOF是通过保存被执行的写命令来记录数据库状态,所以AOF文件中的内容会越来越多,文件的体积也越来越大,对redis服务器、宿主机、AOF还原都有影响,因此,redis提供AOF文件重写功能,通过重写,redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新AOF不会有冗余命令。AOF重写并不需要对现有AOF文件进行任何读取、分析、写入操作,这个功能是通过服务器当前的数据库状态来实现的。因为redis是单线程处理命令,如果由服务器直接调用重写命令,那么重写执行期间将无法处理客户端发来的请求,故放到子进程里执行,这样做既可以达到父进程继续处理客户端命令的请求,而且紫禁城带有服务器进程的数据副本,使用子进程而不是线程,可以避免使用锁的情况下,保证数据的安全性。但如何保证一致性呢,redis服务器执行完一个写命令之后,会将这个写命令发送给AOF缓冲区和AOF重写缓冲区,AOF缓冲区会被定期写入到AOF文件,现有AOF文件的处理工作正常进行。当子进程完成重写工作后,会向父进程发送一个信号,父进程在接收到该信号之后,会调用一个信号处理函数(将AOF重写缓冲区的内容写入到新AOF文件中,对新的AOF改名,覆盖现有AOF文件,该函数会造成阻塞)
七、Redis与Spring结合,序列化
RedisTemplate(序列化java对象)和StringRedisTemplate主要区别是使用的序列化类,RedisTemplate试用JdkSerializationRedisSerializer序列化对象,StringRedisTemplate使用的是StringRedisSerializer序列化String。
JacksonJsonRedisSerializer(序列化object对象为json字符串)
jdkSerializationRedisSerializer 序列化后长度最小,jackson2JsonRedisSerializer效率最高。推荐key使用stringRedisSerializer,value用Jackson2JsonRedisSerializer,如果空间敏感,用JdkSerializationRedisSerializer
genericJackson2JsonRedisSerializer序列化时间:64 序列化后的大小2786 genericJackson2JsonRedisSerializer反序列化时间:48 jackson2JsonRedisSerializer序列化时间:2 序列化后的大小1711 jackson2JsonRedisSerializer反序列化时间:2 jdkSerializationRedisSerializer序列化时间:22 序列化后的大小415 jdkSerializationRedisSerializer反序列化时间:3 stringRedisSerializer序列化时间:0 序列化后的大小415 stringRedisSerializer反序列化时间:0
@Bean(name = "redisTemplate") public RedisTemplategetRedisTemplate(RedisConnectionFactory factory) { RedisTemplate redisTemplate = new RedisTemplate (); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); // key的序列化类型 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型 return redisTemplate; } RedisTemplate
八、Redis与事务
不支持事务回滚,不支持事务原子性,事务中任意命令执行失败,其余命令扔回执行
事务:原子性,一致性,隔离性,持久性 。 redis事务只支持一致性和隔离性
redis事务的隔离性,redis是单进程程序,不会对事务进行终端,事务可以直接运行完事务队列的全部命令。因此,redis事务总带有隔离性
redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
相关命令:
事务传播机制(默认required):
九、Redis与Lua脚本
十、Pipeline管道
一次操作可能需要执行多个命令,一个一个去执行命令会浪费很多网络消耗时间,并不是原子性执行。
十一、Redis与发布订阅
十二、Reids复制
主从复制。复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用,复制主要实现多机备份,以及对读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。
操作:配置文件添加: masterauth root123456。 向从服务器发送命令:slaveof 127.0.0.1 6379
redis复制实现方式
十三、Redis集群(重点)
redis通讯协议,RESP是redis客户端和服务端之间的通讯协议
redis集群与一致性hash
十四、哨兵机制(重点)
在复制的基础上,哨兵实现了自动化的故障恢复。
哨兵也是分布式的,哨兵集群,互相协调工作,故障转移时,判断master是否宕机,需要分布式选举,大部分哨兵同意才行。哨兵+主从架构,只是保证redis的高可用。
哨兵的功能:
十五、Spring与哨兵结合
十六、缓存击穿、缓存雪崩
setnx,可以不存在时,设置成功,返回1,否则返回0。etnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
缓存击穿方案,缓存失效时,不loaddb,setnx返回1则loaddb并设置缓存,否则重试get缓存
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
十七、布隆过滤器
类似于hashset,快速判断元素是否在集合中
十八、海量数据
利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成数据迭代
十九、数据恢复与转移
二十、Redis6种淘汰策略
删除策略
二十一、Redis内存划分
二十二、Redis应用实战
二十三、慢查询分析,性能测试
二十四、Redis 与Spring boot Cache
Redis之Spring boot集成redis和Spring cache
二十五、redis 连接池
二十六、bitmap
二十七、Lettuce
Redis高级客户端Lettuce详解
二十八、Redis常见配置
Redis常用管理命令
# dbsize 返回当前数据库 key 的数量。 # info 返回当前 redis 服务器状态和一些统计信息。 # monitor 实时监听并返回redis服务器接收到的所有请求信息。 # shutdown 把数据同步保存到磁盘上,并关闭redis服务。 # config get parameter 获取一个 redis 配置参数信息。(个别参数可能无法获取) # config set parameter value 设置一个 redis 配置参数信息。(个别参数可能无法获取) # config resetstat 重置 info 命令的统计信息。(重置包括:keyspace 命中数、 # keyspace 错误数、 处理命令数,接收连接数、过期 key 数) # debug object key 获取一个 key 的调试信息。 # debug segfault 制造一次服务器当机。 # flushdb 删除当前数据库中所有 key,此方法不会失败。小心慎用 # flushall 删除全部数据库中所有 key,此方法不会失败。小心慎用
Redis工具命令
#redis-server:Redis 服务器的 daemon 启动程序 #redis-cli:Redis 命令行操作工具。当然,你也可以用 telnet 根据其纯文本协议来操作 #redis-benchmark:Redis 性能测试工具,测试 Redis 在你的系统及你的配置下的读写性能 $redis-benchmark -n 100000 –c 50 #模拟同时由 50 个客户端发送 100000 个 SETs/GETs 查询 #redis-check-aof:更新日志检查 #redis-check-dump:本地数据库检查
redis知识汇总
原文:https://www.cnblogs.com/yaohuiqin/p/13566289.html