面试八股-redis

使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。除了缓存之外,Redis 也经常用来做分布式锁,甚至是消息队列。

1.特点:

  • 高性能:内存操作速度快
  • 高并发:相对于普通数据库能支持更高的并发度
  • 丰富的数据类型:相对于memcached所支持的数据类型更多
  • 持久化:有rdb,aof这些持久化机制
  • 部分支持事务:使用Lua脚本可以让一组命令原子执行、
  • 支持数据备份:master-slave模式数据备份

2.性能高的原因

  • 纯内存操作
  • 单线程操作,避免频繁上下文切换,(操作简单,不需要多线程加持)
  • 采用非阻塞I/O多路复用机制,事件被多路复用程序放入队列中,然后事件分派器依次去队列中取,转发到不同的事件处理器中。 redis还提供了select、epoll、evport、kqueue等多路复用函数库。reacter模式。

3.数据类型

  • string 字符串或者数字,复杂计数功能缓存 get set strlen exist del
  • hash 结构化对象,操作其中某个字段,单点登录可以用其保存用户信息,以cookieId作为key,设置缓存过期时间,模拟出类似session的效果 hset和hget 先压缩表,元素过多时hashtable
  • list 消息队列功能,使用lrange命令,做基于redis的分页功能 lpush lpop rpush rpop lrange lindex blpop brpop
  • set 集合,全局去重,利用交并补计算共同喜好、全部喜好、独有喜好等。 sadd srem
  • zset 多了一个权重score,排行榜,取top N,延时任务,范围查找等。 底层先使用压缩表,当元素过多时跳表实现
  • bitmap 保存连续二进制数,节省空间,非核心了。。
  • Streams 功能强大,支持多播,可持久化的消息队列

渐进式Rehash

当哈希表存储巨大数量键值对,如果一次rehash,可能宕机

步骤:

  • 为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
  • 维持索引计数器比那两rehashidx,设为0,表示开始
  • 每次对字典增删查改,ht[0]的rehashidx索引上的所有键值对rehash到ht[1],将rehashidx值+1。
  • 当全部键值对移动完成,rehashidx设置为-1,表示操作完成

这样避免了集中rehash大计算量造成问题,将计算均摊到每个字典增删查改操作。

4.应用场景

  • 排行榜 zset
  • 计数器 string类型的原子自增操作
  • 好友关系 利用集合交并补
  • 简单消息队列 list自带机制
  • session共享
  • 分布式锁

5.数据过期策略和淘汰机制

5.1.过期策略

过期字典(hash表),key为数据库的键,value是long long类型整数,保存了key指向的数据库键的过期时间。

  • 惰性删除:当访问key才判断是否过期,节省CPU对内存不友好。
  • 定期删除:每100ms抽取部分数据进行删除,漏掉的数据在用到的时候惰性删除,折中内存和CPU。

过期的贪心策略:

  1. 从过期字典中随机选择20个key;
  2. 删除这20个key中已过期的key;
  3. 如果已过期key的比例超过25%,则重复步骤1。

5.2.内存淘汰机制

如果数据一直没有被选择清除掉,而且也

### 关于2023年Redis的Java面试八股文 #### Redis 的基本概念和特性 Redis 是一种基于键值对存储的数据结构服务器,支持多种数据类型的持久化操作。其高性能、丰富的数据类型以及灵活的应用场景使其成为分布式环境中不可或缺的一部分[^1]。 #### 单节点Redis的局限性与解决方案 单节点Redis的并发处理能力存在一定的上限。为了突破这一瓶颈并提升系统的整体性能,通常会采用主从复制的方式构建集群架构来分担读压力,进而达到读写分离的效果。 #### 主从复制机制详解 在Redis中设置多个slave实例作为master副本,当客户端发起GET请求时优先由slaves响应;而SET命令则始终交由master执行后再同步给各个slave。这种设计不仅提高了可用性和容错率,还有效降低了单一节点负载过高的风险。 #### 数据一致性保障措施 针对可能出现的数据不一致情况,可以通过配置合理的replication backlog大小及时重传丢失部分日志记录,确保所有从库能够追赶上主库的状态变化。此外,在网络分区发生期间应采取相应的保护策略防止脑裂现象的发生。 #### 高效利用内存空间的方法 合理规划key的有效期(TTL),定期清理无用对象以释放更多资源供其他业务逻辑调用。对于大容量集合类value建议拆分为若干个小批量保存,减少一次性加载带来的开销。 ```java // 设置 key-value 并指定存活时间 (单位秒) jedis.setex("myKey", 60, "hello world"); // 获取剩余生存期限 long ttl = jedis.ttl("myKey"); System.out.println(ttl); ``` #### 使用Pipeline优化批处理效率 通过组合多条指令成批次发送至服务端解析执行可显著降低RTT延迟影响,极大程度上加快了连续I/O密集型任务的速度表现。 ```java try(Jedis jedis = new Jedis("localhost")) { Pipeline pipeline = jedis.pipelined(); for(int i=0;i<1000;++i){ String k="key"+i; String v="val"+i; pipeline.set(k,v); // 批量set操作加入管道队列等待统一提交 } List<Object> results=pipeline.syncAndReturnAll(); // 同步获取返回结果集 } ``` #### Lua脚本增强原子事务控制力 借助内置解释器运行自定义lua函数完成复杂条件判断下的增删改查动作,保证整个过程中的线程安全属性不变形。 ```lua -- lua 脚本用于实现乐观锁功能 local current_value = redis.call('get', KEYS[1]) if not current_value or tonumber(current_value) >= ARGV[1] then return nil; -- 如果当前库存不足,则直接退出 else local result = redis.call('incrby', KEYS[1], -ARGV[1]); return result; -- 返回更新后的数值表示成功扣减数量 end ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值