redis入门java_java面试基础知识-Redis基础
缓存知识:
数据库层次的缓存针对查询内容,力度较小,只有表中内容不发生变更时,catch才起作用,无法解决增删改的io压力。
缓存数据库提供了对热点数据的高速缓存,提高应用响应速度,缓解后方数据库的压力。
缓存主流应用架构:
穿透:缓存里面没有则穿透缓存去存储层查询,在存储层找到数据后会回写到缓存层(回种)。
熔断:当发现存储层挂掉或者没办法提供服务,可以将用户端请求直接打在缓存层,不管有没有获取数据直接返回,就能在有损的情况下对外提供服务
缓存中间件:
有持久化需求 对数据化处理有高级需求用Redis key-value方式存储,使用MemcacheMemcache:代码层次类似Hash
支持简单数据类型
不支持数据化持久化存储
不支持主从
不支持分片Redis:
数据类型丰富
支持数据磁盘持久化存储
支持主从
支持分片
为什么Redis能这么快?
100000+QPS(每秒内查询次数)
1)完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高 (C语言编写,将数据存储在内存中,不受硬盘IO限制)
2)数据结构简单,对数据操作也简单(不使用表,数据库不预定义,不强制关联,性能比关系型数据库高级很多,使用key_value类似于HashMap,时间复杂度O(1))
3)采用单线程,单线程也能处理高并发请求,想多核也可启动多实例(其主线程是单线程的,主线程负责io事件处理,IO对应相关请求处理。有些任务(过期键的处理,复制协调,集群协调)被封装成周期性任务来被主线程执行,采用单线程设计,客户端读写请求都由主线程串行处理,避免了上下文切换、锁竞争,使得redis效率更高。单线程也可以处理高并发请求(这里的并发不是并行,不是同时进行多个任务,而是让一个计算单元计算多个客户端的流请求,redis利用单线程和多路复用完成了该功能,单线程是处理网络请求时只有一个线程,但是redis server运行时不止一个线程,比如redis持久化的时候,会根据实际情况开启子线程执行)
4)使用多路I/O复用模型,非阻塞IO (Redis的操作顺序执行,但是等待用户输入输出都是阻塞的,所以IO操作一般条件下不能直接返回,会导致IO阻塞,导致整个进程无法对其他客户端服务,引入了多路复用)
多路I/O复用模型
FD:file descriptor,文件描述符
一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的原数据到文件本身的映射。
传统的阻塞I/O模型(当使用读写对FD进行读写时,如果当前FD不可读或者不可写,整个redis服务就不会对其他的FD产生响应,即服务不可用)
为了完成多并发使用多路I/O复用模型
最重要的函数调用:Select系统调用(负责监听FD是否可读可写情况,当某些FD可读可写时,select会返回可读可写的FD,当监听交给select后程序可以进行其他操作)
Redis采用的多路复用函数:epoll/kqueue/evport/select
选择函数方法:
因地制宜
优先选用时间复杂度为O(1)的I/O多路复用函数作为底层实现
以时间复杂度O(n)的select(扫描所有FD)作为保底(因为select函数在不同版本的操作系统都可以实现)
基于react(观察者)设计模式监听I/O事件(文件事件处理器使用I/O多路复用模块,同时监听多个FD,当应答、读取、写入、关闭文件事件产生时,就会回调FD绑定的事件处理器)
redis常用数据类型?String :最基本的数据类型,二进制安全,最大512M(序列化文件,jpg图片)set name "redis"存入一个键为name,值为redis的数据 get name显示键为name的值
Hash:是一个String类型的field和value的映射表,适合用于存储对象 hmset name “lilei” age 26 title "Senior" 存储名为lilei的对象,age为26,title为Senior,获取使用:hget lilei age;hget lilei title
LIst:列表 按照String元素插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边) 存储命令:lpush mylist aaa;lpush mylist bbb;lpush mylist ccc;获取命令:lrange mylist 0 10(取0-10个但是有几个最多出几个,后进先出)
Set:String元素组成的无序集合,通过哈希表实现复杂度都是O(1),不允许重复 存储命令:sadd myset 111返回1则成功,返回0则失败(重复)获取数据:smembers myset;
Sorted Set:每个元素关联一个double类型的分数,通过分数来为集合中的成员进行从小到大的排序(成员是惟一的,但是分数可以重复)集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1) 存储命令:zadd myzset 3 abc;zadd myzset 3 eeg;(分数相同,分数不同可以添加)取出命令:zrangebyscore myset 0 10;
底层数据类型基础(后续了解)
从海量Key里查询出某一固定前缀的Key
摸清数据规模,问清楚边界
1)KEYS pattern:查找所有符合给定模式pattern的Key)
取到K1开头的所有key(执行时redis会卡顿)
2)SCAN CURSOR[MATCH pattern][COUNT count]
基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程
以0为游标开始一次新的迭代,直到命令返回游标0完成一次遍历
不保证每次执行都返回某个给定数量的元素,支持模糊查询
一次返回的数量不可控,只能是大概率符合count参数
返回前缀为k1的数据,期望返回10条(执行时redis不会卡顿,游标不一定增长,即有可能获取重复数据,外部程序需要去重。因为scan是分批次进行查询,整体时间比keys时间要长)
注:java需要安装Jedis来使用
注:本篇文章只针对与面试知识,实际应用中应从实际出发考虑生产环境选择合适的方法。