谈及缓存,在软件开发时经常用到缓存是Redis,算是使用最广法的缓存中间件。
当然,在面试的过程中,Redis也是经常被询问的题目
Redis是单线程吗?
redis的单线程,是指Redis的网络I/O线程,以及键值的SET和GET等读写操作都由一个线程完成
但是,在Redis持久化、集群同步等操作,是由其他线程来执行
Redis单线程为什么快?
- Redis的大部分操作都是在内存中完成
- 采用了高效的数据结构,比如Hash、跳表
- 单线程模型,避免了多线程间切换的产生的其他时间和性能开销
- 单线程模型,也不用去考虑因多线程导致死锁的问题
- Redis采用了I/O多路复用机制处理大量的客户端Socket请求,使得Redis更高效进行网络通信(重要因素)
注意点:
Redis 4.0版本后,增加多线程支持,主要体现在大数据的异步删除功能
Redis 6.0版本后,新增多线程I/O的读写并发能力(即采用了多个I/O线程来处理网络请求)
Redis持久化
面试时,经常会被提问:如何保持数据不丢失?其主要是考察Redis持久化问题,如何去做持久化?
什么情况Redis数据会丢失?
缓存数据在内存中,如果服务器重启时,内存中的数据就会丢失。为了保证数据不丢失,将数据存储到磁盘中,以便服务器重启后,能够从磁盘中恢复原有的数据。
持久化的三种方式:
- AOF日志(Append only File 文件追加方式):记录所有的操作命令,并以文本形式追加到文件中
- RDB快照(Redis DataBase):将某时刻的内存数据,以二进制形式写入磁盘
- 混合持久化方式:redis4.0版本后新增的混合持久化方式
Redis 数据类型
基础数据类型
String
- 常用命令:set/get/decr/incr/mget
- 使用场景:普通的key/value存储
Hash
- 常用命令:hget/hset/hgetall
- 使用场景:存储某对象数据
List
- 常用命令:lpush/rpush/lpop/rpoplrange
- 使用场景:存储列表数据(如微博关注列表/粉丝列表等)
Set(集合)
- 常用命令:sadd/spop/smembers/sunion等
- 使用场景:Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的
Sorted set(有序集合)
- 常用命令:zadd/zrange/zrem/zcard等
- 使用场景:和set一样,但是有序集合通过用户额外提供一个优先级score的参数来为成员排序,并且插入也是有序
特殊数据类型(进阶)
Bitmap 位图
使用方法:
- setbit key index 0/1 设置某位的值
- getbit key index 获取某位的值
- bitcount key start end 获取指定范围内为1的数量
- 使用场景:统计用户一年活跃天数
GeoHash地理位置
使用方法:
- geoadd key longitude latitude element(后面可配置多个三元组) 添加元素
- geodist key element1 element2 unit 计算两个元素的距离
- geopos key element [element] 获取元素的位置
- geohash key element 获取元素hash
- 使用场景:常用于计算附近的人,附近商店
HyperLogLog 基数统计
使用方法:
- pfadd key element 添加
- pfcount key 计算
- pfmerge destkey sourcekey1 sourcekey2 ... 合并
- 使用场景:提供不精确的去重技术方案
bloomFilter布隆过滤器
使用方法
- bf.add key element 添加
- bf.exists key element 判断是否存在
- bf.madd key element1 element2 ... 批量添加
- bf.mexists key element1 element2 ... 批量判断
- 使用场景:网站去重,垃圾邮件过滤,缓存穿透