Redis。官网
Redis 命令参考 — Redis 命令参考
需要使用大于6.0.8,redis-server -v
redis各个版本之间架构都不同,所以这个问题需要从不同版本去描述
由于单线程的阻塞的问题,例如出现了bigkey删除的时候,导致官方放弃了单线程的架构。
redis的单线程,主要是指redis的网络IO和键值读写是又以恶搞线程来完的,redis在处理客户端的请求时候包括如下:
以上操作都是一个顺序串行的主线程处理,这个就是所谓的单线程。redis采用Reactor模式的网络模型,对于一个客户端请求,主线程负责一个完成的处理过程。 但是其它的功能,比如持久化、异步删除、集群数据同步等都是由额外的线程执行的。
结论:redis工作线程是单线程,对于redis整体来说是多线程。对于redis系统瓶颈在于网络和内存。
单线程时代,最头疼的问题之一,就是大key的del,当删除一个很大的key的时候,就会导致其它命令全部阻塞,只有key删除完毕,其它命令才能执行。
基于以上情景,redis4就设计了异步删除:unlink key。其它的耗时操作,也都可以使用异步的方式,从主线程剥离一个bio子线程进行操作。
因为redis的瓶颈在于网络IO和内存,而内存无法通过系统改变,所以redis系统优化的主要方向就是网络IO。
Unix五种网络IO模型:
IO多路复用,是一种IO模型,即经典的Reactor设计模式:
IO多路复用,简单的来说就是通过检测文件的读写事件再通知线程执行的相关操作,保证Redis的非阻塞I/O能够顺利执行完成的机制。多路是指多个socket连接、复用是指一个线程。
多路复用主要由以下三种技术:
在redis6中,增加了多线程处理IO的读写性能,主要实现思路是将主线程的IO读写任务拆分给一组独立的线程去执行,这样可以使多个socket读写并行化了,采用多路IO复用技术,可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的socket的读取、请求解析、单独外包出去,而执行命令还是交给主线程。
结论:IO操作多线程,核心操作单线程。
redis6默认的多线程是关闭,因为单线程大部分场景已经够用。
TK mapper 类似于 mybatis-plus,都是在mybatis上进行二次封装,一键生成。
数据库主键,一般情况可能存在100xx、200xx、300xx,表示不同含义的数据。
为了防止缓存击穿,可以使用 DCL(double check lock),代码如下:
public User findUserById2(Integer id)
{
User user = null;
String key = CACHE_KEY_USER+id;
//1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql
user = (User) redisTemplate.opsForValue().get(key);
if(user == null)
{
//2、对于高QPS的优化,进来就先加锁,保证一个请求操作,让外面的redis等待一下,避免击穿mysql
synchronized (UserService.class){
user = (User) redisTemplate.opsForValue().get(key);
//3 二次查redis还是null,可以去查mysql了(mysql默认有数据)
if (user == null) {
//4 查询mysql拿数据
user = userMapper.selectByPrimaryKey(id);//mysql有数据默认
if (user == null) {
return null;
}else{
//5 mysql里面有数据的,需要回写redis,完成数据一致性的同步工作
redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS);
}
}
}
}
return user;
}
现阶段redis不仅仅包含5种经单的数据类型了,其实一共已经有9种:
在redis中,命令不区分大小写,但是key区分大小写,帮助:help@类型:
千万、亿级数据收集+统计。需要能够 存的进+取的块+多统计,传统的关系型数据库在部分就很乏力。
位图,是一个数组,数组上的元素就是0、1
它的出现主要是解决了数据空间的问题,可以极大的节约存储空间,支持最大位数是2^32位,使用512M就可以存放42.9亿的字节信息。
处理场景:
应用签到:用户签到一天就是1个bit位,365天也就是365bit位,时间和空间都能够保证。
bitmap的基本命令(1亿位的bitmap,最大120M):
bitmap底层存放的就是二进制的ascII编码对应:
01100001对应的ascII为 a,如下可知:
bitmap的扩容机制,每增加8位就进行扩容。8bit=1byte。
名次解释:
基数:去重后的数据集
当需要统计网站UV、某个页面的UV、统计用户搜索关键词和个数,这类情境下就需要使用到去重复统计功能的基数估计算法-hyperloglog。优点和bitmap相同,统计元素非常大的时候,计算技术所需要的空间总是固定并且很小的,只需要12KB就能计算接近2^64个不同元素的基数,但是hyperloglog只能计算基数,不能想集合一样输入元素本身。
理论上使用bitmap也是可以的,但是个人感觉有两点问题,去重+数据增长。bitmap使用场景本身是二值统计并且虽然所占空间很小,但是当数据量庞大的时候,也是会逐步增加的。
概率算法:通过牺牲准确率来换取空间,对于不需要绝对精确率的场景下可以使用,因为概率算法不直接存储数据本身,通过一定的概率统计方法预估基数值,同时保定误差在一定范围内。hyperloglog就是一种概率算法。通过牺牲准确率来换取空间,误差在0.81%左右。
为什么redis集群的最大槽数是16384个?
Redis集群没有使用一执行Hash(通过hash算法确定放入到哪个节点)而是引入了哈希槽的概念。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放入到哪个槽,集群的每个节点负责一部分槽。但CRC16算法产生的hash值有16bit也就是2^16=65536,那为什么不使用65536二十16384?
hyperloglog的命令:
redis中提供了地图相关的操作GEO,可以实现附近的XX,如附近的人、附近的美食、附近的车辆等等。
例如用户需要打车,就是查找记录用户(x0,y0)附近r公里范围内的车辆。
GEO命令: