一、redis常用场景?
1)热点数据缓存
2)限时业务数据存储
3)计数器相关(incrby)
4)排行榜(SortedSet)
5)分布式锁
6)队列(ist push、list pop)
二、使用redis时,如何保证redis的高可用?
1)主从架构,一主多从,甚至多主多从
2)通过哨兵完成故障切换
三、redis线程安全问题
Redis是个单线程程序,所以它是线程安全的。
避免了不必要的上下文切换和竞争条件,使用多路复用技术,可以处理并发的连接。
但是无法发挥机器多核的优势(当然可以起多个redis进程)
四、redis性能为什么高?
1)完全基于内存,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
2)数据结构简单,对数据操作也简单
3)采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
4)使用多路I/O复用模型,非阻塞IO;
5)Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求
五、redis如何持久化
RDB(快照):保存某个时间点的全量数据快照。文件小,恢复快,但是无法保存最近一次快照之后的数据,数据量大会由于I/O严重影响性能。
AOF(日志):除了查询以外的所有变更数据库状态的指令,以append的形式追加保存到AOF文件中。可读性高,适合保存增量数据,数据不一定丢失,但是文件体积大,恢复时间长。
AOF解决aof日志越来越多的问题
AOF方式会调用fork,创建一个子进程,把新的AOF写到一个临时文件里。主进程持续将新的变动同时写到内存和原来的AOF里,主进程获取子进程重写AOF完成信号,往新AOF同步增量变动,使用新的AOF文件替换掉旧的AOF文件。
六、redis数据类型和应用场景
1)String
Redis的字符串是动态字符串,是可以修改的字符串,它的内部表示就是一个支持自动动态扩容的字节数组(类似于Java的ArrayList)
可以包含任何数据,比如jpg图片或者序列化的对象,规定字符串的长度不得超过512MB。
常用命令:set、get、decr、incr、mget等。
2)Hash
相当于Java语言里面的HashMap。
适合存储对象
常用命令:hget、hset、hgetall等。
3)List
相当于Java的LinkedList,将链表和 ziplist (压缩列表,它将所有的元素紧挨着一起存储,分配的是一块连续的内存)结合起来组成了 quicklist,当数据量比较多的 时候才会改成 quicklist。
适合用于消息队列
常用命令:lpush、rpush、lpop、rpop、lrange等。
4)Set
Redis的集合相当于Java语言里面的HashSet,内部的键值对是唯一的
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
利用唯一性,可以用作去重
常用命令:sadd、spop、smembers、sunion等。
5)sorted set
类似于Java的SortedSet和HashMap的结合体,保证内部value的唯一性的同时,给每个value赋予一个score,代表这个value的排序权重,内部实现是一个Hash字典 + 一个跳表。
适合用于排行榜
常用命令:zadd、zrange、zrem、zcard等。
七、sortedset的get的时间复杂度?
redis sorted sets里面当items内容大于64的时候同时使用了hash和skiplist两种设计实现。这也会为了排序和查找性能做的优化。所以如上可知:
添加和删除都需要修改skiplist,所以复杂度为O(log(n))。
但是如果仅仅是查找元素的话可以直接使用hash,其复杂度为O(1)
其他的range操作复杂度一般为O(log(n))
当然如果是小于64的时候,因为是采用了ziplist的设计,其时间复杂度为O(n)