有RPopLPush/ BRPopLPush,弹出来返回给client的同时,把自己又推入另一个list,LLen获取列表的长度 。
2.5 Set
Set就是Set,可以将重复的元素随便放入而Set会自动去重,底层实现也是hash table 。
2.6 Sorted Set
有序集,元素放入集合时还要提供该元素的分数 。
Sorted Set的实现是hash table(element->score, 用于实现ZScore及判断element是否在集合内),和skip list(score->element,按score排序)的混合体 。skip list有点像平衡二叉树那样,不同范围的score被分成一层一层,每层是一个按score排序的链表 。
ZAdd/ZRem是O(log(N)),ZRangeByScore/ZRemRangeByScore是O(log(N)+M),N是Set大小,M是结果/操作元素的个数 。可见,原本可能很大的N被很关键的Log了一下,1000万大小的Set,复杂度也只是几十不到 。当然,如果一次命中很多元素M很大那谁也没办法了 。
2.8 Lua
Redis2.6内置的Lua 支持,可以在Redis的Server端一次过运行大量逻辑,就像存储过程一样,避免了海量中间数据在网路上的传输 。
Lua自称是在语言里关于快的标准,Redis选择了它而不是流行的JAVA 。
因为Redis的单线程架构,整个默认是在一个事务里的 。
里涉及的所有Key尽量用变量,从外面传入,使Redis一开始就知道你要改变哪些key 。(but why?)
Eval每次传输一整段比较费带宽,可以先用 Load载入,返回哈希值 。然后用EvalHash执行 。因为就是SHA-1,所以任何时候执行返回的哈希值都是一样的 。
内置的Lua库里还很贴心的带了CJSON,可以处理json字符串 。
一段用Redis做Timer的示例代码,下面的被定期调用,从以触发时间为score的sorted set中取出已到期的Job,放到list中给Client们blocking popup 。
— KEYS: [ 1]job:sleeping, [ 2]job:ready
— ARGS: [ 1]currentTime
— Comments: result isthe job id
local jobs=redis. call(‘zrangebyscore’, KEYS[ 1], ‘-inf’, ARGV[ 1])
local count = table.maxn(jobs)
ifcount> 0then
— Comments: remove fromSleeping Job sorted set
redis. call(‘zremrangebyscore’, KEYS[ 1], ‘-inf’, ARGV[ 1])
— Comments: add tothe Ready Job list
— Comments: can optimize touse lpush id1,id2,… forbetter performance
fori= 1,count do
redis. call(‘lpush’, KEYS[ 2], jobs[i])
end
end
在Redis使用过程中,Lua脚本的支持无疑给开发者提供一个非常友好的开发环境,从而大幅度解放用户的创造力 。如果使用得当,Lua脚本可以给性能和资源消耗带来非常大的改善 。取代将数据传送给CPU,脚本允许你在最接近数据的地方执行逻辑,从而减少网络延时和数据的冗余传输 。
在Redis中,Lua一个非常经典的用例就是数据过滤或者将数据聚合到应用程序 。通过将处理工作流封装到一个脚本中,你只需要调用它就可以在更短的时间内使用很少的资源来获取一个更小的答案 。
2.9使用合适的数据结构
不管是内存使用或者是性能,有的时候数据结构将产生很大的影响,下面是一些可以参考的最佳实践:
1、使用hash取代将数据存储为数千(或者数百万)独立的字符串 。哈希表是非常有效率的,并且可以减少你的内存使用(因为小Hashes会被编码成一个非常小的空间);同时,哈希还更有益于细节抽象和代码可读 。
2、合适时候,使用list代替set 。如果你不需要使用set特性,List在使用更少内存的情况下可以提供比set更快的速度 。
3、Sorted sets是最昂贵的数据结构,不管是内存消耗还是基本操作的复杂性 。如果你只是需要一个查询记录的途径,并不在意排序这样的属性,那么轻建议使用哈希表 。
4、Redis中一个经常被忽视的功能就是bitmaps或者bitsets(V2.2之后) 。Bitsets允许你在Redis值上执行多个bit-level操作,比如一些轻量级的分析 。
5、使用bit位级别操作和byte字节级别操作来减少不必要的内存使用
4、数据一致性:事务
用Multi(Start Transaction)、Exec(Commit)、Discard(Rollback)实现 。在事务提交前,不会执行任何指令,只会把它们存到一个队列里,不影响其他客户端的操作 。在事务提交时,批量执行所有指令 。《Redis设计与实现》中的详述 。
注意,Redis里的事务,与我们平时的事务概念很不一样:
它仅仅是保证事务里的操作会被连续独占的执行 。因为是单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的 。
推荐阅读
- 详解限流算法,图示漏桶算法与令牌桶算法
- Spring Boot启动原理解析
- Oracle用户进程和后台进程详解
- C++ 一篇搞懂多态的实现原理
- 什么是青砖茶,青砖茶的特点是什么
- 史上最详细的Linux网卡ifcfg-eth0配置详解
- 荧光灯如何选购 荧光灯工作原理
- 什么是Redis
- 从原理到实战,彻底搞懂Nginx
- MySql主从复制,从原理到实践
