Redis集锦

参考:http://blog.51cto.com/yaocoder/888374

redis是什么

redis是单线程单进程,kv内存存储数据库。

为什么是单线程?
因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

单线程优缺点:
1、多线程涉及到锁
2、多线程的上下文切换会消耗cpu
3、无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善

redis快速的原因:
1、基于内存操作
2、数据结构简单:String、List、Set、Sorted Set、hashes
3、使用epoll,多路IO复用模型

让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗)
1、非阻塞【忙轮询】:采用死循环方式轮询每一个流,如果有IO事件就处理,这样可以使得一个线程可以处理多个流,但是效率不高,容易导致CPU空转
2、Select代理(无差别轮询):可以观察多个流的IO事件,如果所有流都没有IO事件,则将线程进入阻塞状态,如果有一个或多个发生了IO事件,则唤醒线程去处理。但是还是得遍历所有的流,才能找出哪些流需要处理。如果流个数为N,则时间复杂度为O(N)
3、Epoll代理:Select代理有一个缺点,线程在被唤醒后轮询所有的Stream,还是存在无效操作。 Epoll会哪个流发生了怎样的I/O事件通知处理线程,因此对这些流的操作都是有意义的,复杂度降低到了O(1)

         | 内核缓存区| 
 write A================read B                     
 当A有数据写入时,缓存区数据从无到有,即缓存区不为空,内核产生IO事件通知B去读;
 若内核缓存区写满,B还未能及时读,即缓存区满,内核产生IO事件通知A需要阻塞了;
 若B开始读内核缓存区数据,即缓存区不为满,内核产生IO事件通知A该干活了;
 若B读完了内核缓存区数据,A还未写入,即缓存区为空,则内核通知B阻塞。

redis淘汰策略

noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
allkeys-random: 回收随机的键使得新添加的数据有空间存放。
volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放

redis哈希槽

redis cluster集群使用,节点为奇数,并需要配从节点,单个slot 区间所有的节点不可用时会导致集群不准确。集群最大节点2^14。

Redis集群预分好16384个桶,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。三个主节点分别是:A, B, C 三个节点,它们可以是一台机器上的三个端口,也可以是三台不同的服务器。那么,采用哈希槽 (hash slot)的方式来分配16384个slot 的话,它们三个节点分别承担的slot 区间是(不一定是平均分配):
节点A覆盖0-5460;
节点B覆盖5461-10922;
节点C覆盖10923-16383.

获取数据:如果存入一个值,按照redis cluster哈希槽的算法: CRC16(‘key’)%16384 = 6782。 那么就会把这个key 的存储分配到 B 上了。同样,当我连接(A,B,C)任何一个节点想获取’key’这个key时,也会这样的算法,然后内部跳转到B节点上获取数据 。

redis内存优化

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面.

redis持有化方式

1、RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.

redis常用命令

lpush key value 返回列表的长度1
lpush key value2 返回列表的长度2
lrange key 0 -1 枚举列表 返回顺序后入先出
pexpire key milliseconds 设置有效期ms
expire key seconds 设置有效期s
PERSIST 永久有效
setnx key value 如果key有了,则不操作,set key if not exist,成功返回1,否则-1
get key 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。

redis分布式

流控lua脚本

String flowControl = " local key= KEYS[1]  local limit=ARGV[1]  local period=ARGV[2]  local currenttime=ARGV[3]"
			     +  " local lasttime = redis.call('lindex', limit-1)	"
			     + " if lasttime and currenttime - lasttime < period than return 'true' end "
			     + " local length = redis.call('lpush', key, currenttime) "
			     + " redis.call('pexpire', key, period*2) "
			     + " if length > limit*2 than redis.call('ltrim', key , 0 , limit+1) end "
			     + " return 'false' ";

设置有效期要比一个周期略大即可。
截断是防止每个周期内都有请求并都没打到流控限制,列表过长

分布式锁脚本

String acqLock = " local key= KEYS[1]  local value=ARGV[1]  local period=ARGV[2] "
			     + " local temp = redis.call('setnx', key, value)	"
			     + " if (temp == 1) than "
			     + "      redis.call('pexpire', key, period) "
			     + "      return 'true' "
			     + " else "
			     + "     return 'false' "
			     + " end ";
String resLock = " local key= KEYS[1]  local value=ARGV[1]  local period=ARGV[2] "
			     + " local temp = redis.call('get', key)	"
			     + " if (temp == nil) than "
			     + "      return 'true' "
			     + " elseif (value == temp)"
			     + "      redis.call('del', key) "
			     + "      return 'true' "
			     + " else "
			     + "     return 'false' "
			     + " end ";		     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值