Redis个人笔记

来源:互联网 发布:阿列克谢耶维奇 知乎 编辑:程序博客网 时间:2024/06/06 08:23

以下仅是个人笔记,不适合初学者。想学习使用请先搜索redis指令


公司用的是mysql+redis+memcached+mongodb,所以稍微学一下



redis是key-value内存数据库,相较于memcached可进行数据持久化。


##数据结构


支持五种数据结构:字符串,集合,散列,列表,有序集合类型


编码方式有:raw、int、ht、[zipmap](http://www.cnblogs.com/igloo1986/archive/2012/08/27/2658730.html)、linkedlist、ziplist、intset


zipmap可能比较难懂


- hash对应value内部实际是一个Hashmap,数据少时类一维数组,数据量大时用hashmap;value对应为zipmap和ht;


- set内部实现是一个value永远为null的hashmap,实际通过计算hash的方式快速重排,这是set能快速判断一个成员是否在集合内的原因。


- sorted set用hashmap和跳跃表实现存储保证有序。hashmap:成员和score;跳跃表:所有成员。




##内存优化手段及参数
Redis实际上内存管理成本很高,Redis内部实现没有对内存分配方面做过多的优化,在一定程度上会存在内存碎片


- __VM__选项.这个本来是作为Redis存储超出物理内存数据的一种数据在内存与磁盘换入换出的一个持久化策略,但是其内存管理成本也非常的高,并且我们后续会分析此种持久化策略并不成熟,所以要关闭VM功能,请检查你的__redis.conf__文件中 __vm-enabled__ 为 __no__。


- __redis.conf__中的__maxmemory__选项,该选项是告诉Redis当使用了__多少物理内存__后就开始__拒绝__后续的__写入请求__,该参数能很好的保护好你的Redis不会因为使用了过多的物理内存而导致swap,最终严重影响性能甚至崩溃。


- 另外Redis为不同数据类型分别提供了一组参数来控制内存使用,我们在前面详细分析过Redis Hash是value内部为一个HashMap,如果该Map的成员数比较少,则会采用类似__一维线性__的紧凑格式来存储该Map, 即省去了大量指针的内存开销,这个参数控制对应在redis.conf配置文件中下面2项:


>- `hash-max-zipmap-entries 64 `</br>
- `hash-max-zipmap-value 512 `</br>


> `hash-max-zipmap-entries`
>含义是当value这个Map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的HashMap。


>`hash-max-zipmap-value` 含义是当 value这个Map内部的每个成员值长度不超过多少字节就会采用线性紧凑存储来节省空间。


>以上2个条件任意一个条件超过设置值都会转换成真正的__HashMap__,也就不会再节省内存了,那么这个值是不是设置的越大越好呢,答案当然是否定的,HashMap的优势就是查找和操作的时间复杂度都是O(1)的,而放弃Hash采用一维存储则是O(n)的时间复杂度,如果


>成员数量很少,则影响不大,否则会严重影响性能,所以要权衡好这个值的设置,总体上还是最根本的时间成本和空间成本上的权衡。


>同样类似的参数还有:


>`list-max-ziplist-entries 512`
说明:list数据类型多少节点以下会采用去指针的紧凑存储格式。


>`list-max-ziplist-value 64 `
说明:list数据类型节点值大小小于多少字节会采用紧凑存储格式。


>`set-max-intset-entries 512 `
说明:set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。


##Redis的持久化机制


#####四种持久化方式:
- 定时快照方式(snapshot):定时器事件
- 基于语句追加文件的方式(aof):每条会使Redis内存数据发生改变的命令都会追加到一个log文件中
- 虚拟内存(vm)(已被放弃)
- Diskstore方式:B-tree的方式


前两种是基于全部数据都在内存中,即小数据量下提供磁盘落地功能,而后两种方式则是作者在尝试存储数据超过物理内存时,即大数据量的数据存储(目前只支持前两种)




##Redis持久化磁盘IO方式及其带来的问题


有Redis线上运维经验的人会发现Redis在物理内存使用比较多,但还没有超过实际物理内存总容量时就会发生不稳定甚至崩溃的问题,有人认为是基于快照方式持久化的fork系统调用造成内存占用加倍而导致的,这种观点是不准确的,因为fork 调用的copy-on-write机制是基于操作系统页这个单位的,也就是只有有写入的脏页会被复制,但是一般你的系统不会在短时间内所有的页都发生了写入而导致复制,那么是什么原因导致Redis崩溃的呢?


答案是__Redis的持久化使用了Buffer IO造成的__,所谓Buffer IO是指Redis对持久化文件的写入和读取操作都会使用物理内存的Page Cache,而大多数数据库系统会使用Direct IO来绕过这层Page Cache并自行维护一个数据的Cache,而当Redis的持久化文件过大(尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内存中作为操作系统对该文件的一层Cache,而这层Cache的数据与Redis内存中管理的数据实际是重复存储的,虽然内核在物理内存紧张时会做Page Cache的剔除工作,但内核很可能认为某块Page Cache更重要,而让你的进程开始Swap ,这时你的系统就会开始出现不稳定或者崩溃了。我们的经验是当你的Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了。




###总结:


根据业务需要选择合适的数据类型,并为不同的应用场景设置相应的紧凑存储参数。
当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能以及最大的内存使用量。
如果需要使用持久化,根据是否可以容忍重启丢失部分数据在快照方式与语句追加方式之间选择其一,不要使用虚拟内存以及diskstore方式。
不要让你的Redis所在机器物理内存使用超过实际内存总量的3/5。




参考:http://www.infoq.com/cn/articles/tq-redis-memory-usage-optimization-storage


##OTHERS


####Redis 事务
- 原子性,multi...exec
- watch:监控一个或多个键,一旦一个键被修改或者删除,之后的事务就不会执行


####生存时间
- expire命令设置键的生存时间,到时间该键将被自动删除
- ttl查看剩余时间(返回-1表示已被删除或者没有设置生存时间)
- redis作为__缓存系统__时,可以限制redis使用的最大内存,并让redis按照一定的规则淘汰不需要的缓存键。
修改配置文件的`maxmemory`参数,限制redis最大可用内存大小。
 
0 0
原创粉丝点击