Redis(3)
Redis最主要的数据类型
redis自动适应的,程序员在使用redis的时候一般感知不到。
String类型:
- raw:最基本的字符串。底层是byte数组。
- int:redis可以用在作为计数,当value就是整数,value就会直接用int保存(内部)。
- embstr:短字符串进行的优化,比较长的话就用raw。
hash
- hashtable:redis内部中哈希表内部实现,和java中实现可能不一样。
- ziplist:压缩列表,针对一些特殊场景,对数据压缩,从而解锁空间,在hash表里面元素比较少的时候。顺序遍历,因为元素比较少,所以遍历之后是o(1).
如果key比较多对应的value也很多,value中有很多hash,就可以通过压缩减小内存。
同一个数据类型可能背后的编码方式不一样。
list
- LinkedList:方便插入删除
- ziplist:压缩列表。
实际上从redis3.2开始就引入了quicklist,quicklist是一个链表每个元素都是一个ziplist。
set
- intset:集合中都是整数就会从hashtable优化成intset。
zset(权重)
- skiplist:类似于达到了二叉平衡搜索树。使用跳表可以提高redis的效率。
有序集合相当于除了存储必要的成员(member),还要存储权重(分数)。
通过观察内部的真实数据类型。
实际上在源码阶段,Redis会对上述数据结构进行优化,达到节省空间的结果。
比如redis有个hash表,redis保证插入删除操作保证o(1),可能叫hash,但是内部是不是哈希不好说。
Redis会根据当前的实际情况进行编码方式。
Redis的单线程
redis只使用一个线程处理所有的命令请求,不是说一个服务器进程内部只有一个线程。多线程实在处理网络io。
假设有多个客户端同时操作同一个客户端,同时使用incr counter,进行自增。此时两个客户端也相当于并发的发起了请求,但是并不会存在线程安全的问题,因为Redis是单线程模型,就保证了Redis是串行的。这几个请求就会在redis中排队。
redis能使用单线程实际上主要是因为redis的核心业务逻辑是短平快的,不太消耗cpu。
Redis虽然是单线程,为什么这么快(必考面试题):
-
参照数据库(MySQL)相比比较快。
- redis访问的是内存。
- redis核心功能相比于数据库更简单,redis干的活比较少。(数据库对删除插入有更复杂的支持,要花更多开销,数据库中的各种约束,主键约束,插入得查一下什么的)。
- redis是单线程模型,避免了一些不必要的线程开销,加锁导致的业务阻塞什么的。
- 处理网络io的时候,使用了epoll这样的io多路复用机制(一个线程管理多个socket)。
针对tcp,服务器每次给客户端服务,都要给客户端安排一个socket,一个服务器要服务多个客户端,同时就有很多socket,这些socket并没有无时不刻在传输数据,很多情况下客户端和服务器并没有通信那么频繁,同一时刻只有少数socket是活的,io多路复用就是一个线程处理多个socket。
(IO多路复用)一个线程同时干很多事情,能高效完成这三件事,是因为传输过程并没有那么频繁,大部分 时间都在等,等的过程之中,就可以抽空做其他事情,epoll类似于事件通知机制,谁想要线程调用,就通知一下。
String操作:
Redis字符串实际上就是按照二进制的方式存储,存的是啥,取出来就是啥。使得String能存的数据很丰富。但是String限制了大小为512M。
再谈SET
设置key并且设置为存活十秒。ex为s,ps为ms。
重新set key相当于更新数字。key不存在则是创建新的key。
注意:如果刚才设置一个旧的数据并且设置了expire,如果新的覆盖掉了,也会使得expire的时间消失。
删库:FLUSHALL(把redis上的所有键值对一波带走)!!!!!!!!!
set nx:
如果已经有key1的时候再进行设置就返回一个nil,没有的话就成功。
set XX:
必须存在才能设置,和上面的NX相反。
mset:一次操作多个键值对
通过一次网络通信,一次操作多个key,实际上就是再mset后面加多个key和value。但是也不能操作太多,如果操作太多有可能会阻塞redis。时间复杂度o(n)。n为个数。
setnx
只有在key3不存在的时候才会设置成功,如果key3存在setnx设置失败。
setex:指定一个key以及时间秒数
再谈GET
GET只能获取String类型的value,获取其他类型的会报错,比如如果你获取list,他就会报错。
mget:
mget实际上和mset方法使用差不多。
Incr系列
redis实际上可以作为一个计数器。
incr(针对value+1)
此时key对应的value必须是整数(64位),此操作的返回值就是加一后的值。
如果这时候不存在一个key,但是实际上会创建一个key,并且把这个key当作0使用。
incrby(针对value+n,加减正负都可以)
可以加n操作。
decr
decrby
incrbyfloat(针对value加或者减小数)
既可以算浮点数,也可以算整数。
字符串的相关操作
append:
如果key已经存在(并且是String类型),就直接拼接,如果不存在这个key,就创建一个(类似于set)。返回值:返回的是字节,redis不会对字符编码做文章。xshell默认字符编码是utf8,也就是一个汉字三个字节。
加上--raw,就可以翻译二进制。
getrange
返回key对应的string的子串,由start和end确定(两边都是闭区间)。
如果为-1的话就代表最后一个元素。如果是0和-1的话就是获取所有的数据。
setrange
表示从第几个字符进行开始替换,结束就是看value长度 ,如果添加的地方是空的,添加到后面的字节,只不过会把空的内容填充成0x00(一个字节)。
strlen(获取到字符串长度(字节为单位))
java中的char是使用unicode(一个汉字两个字节),但是String用的是utf8(一个汉字三个字节)。
strlen+key(必须要String类型),如果key不存在返回0。
String内部编码:
字符串内部编码有三种方式:object encoding key来查找底部是什么表示。
- int:存储整数的情况。
- embstr:针对比较短的字符串(压缩字符串)进行保存,小数也可以存储。
- raw:比较长的的字符串(比较长的使用,普通字符串)。
小数运算,要把字符串转成小数进行相加,然后再转回去。但是整数就是直接相加。
String类型的应用场景
缓存:
由于访问mysql的时候速度比较慢,所以很多时候就会访问Redis,可以把热点数据存在redis上面,(把最近使用的数据作为redis)就可以由redis直接返回而不用经过数据库(mysql),没有就继续查询MySQL,并且把数据写入redis中。
上述策略存在一个问题,随着时间的推移,肯定会有越来越多的key在redis中,此时redis中的数据就越来越多了。
解决思路:
- 在数据给redis的时候设置一个过期时间。
- redis也在内存不足的时候,提供了一种淘汰机制。
假设用户根据uid获取用户信息:
接着从Redis中获取信息,根据userinfo+uid:
如果缓存命中,则直接拿取,如果没有命中则再次访问数据库。
计数:
比如记录视频播放次数,比如用户每播放一次视频,相应的视频播放数就会+1,如果在数据库中存储数据的话,每一次update语句都对数据库进行修改,那么就会消耗很大,所以我们直接用redis,对播放数进行+1。
session是浏览器存储数据的机制,cookie是浏览器存储数据的机制,都通过键值对的方式进行存储。通常会将session放在redis中让每个web服务器共享。
短信验证码:
用户输入手机号进行获取验证码。
原文地址:https://blog.csdn.net/syx050403/article/details/144628575
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!