redis 学习记录
2015-05-03 17:45
169 查看
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted
set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。[1]
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
redis的官网地址,非常好记,是redis.io。(特意查了一下,域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
目前,Vmware在资助着redis项目的开发和维护。
doc http://doc.redisfans.com/index.html
使用Redis开发应用程序是一个很愉快的过程,但是就像其他技术一样,基于Redis的应用程序设计你同样需要牢记几点。在之前,你可能已经对关系型数据库开发的那一整个套路了然如胸,而基于Redis的应用程序开发也有许多相似的地方,但是你必须牢记以下两点——Redis是个内存数据库,同时它是单线程的。因此,在使用Redis时,你需要注意以下几点:
1. 掌控储存在Redis中的所有键
数据库的主要功能是储存数据,但是对于开发者来说,因为应用程序需求或者数据使用方法的改变,忽略存储在数据库中的某些数据是非常正常的,在Redis中同样如此。你可能忽视期满某些键,也可能因为应用程序的某个模块弃用而忘掉这些数据。
无论哪种情况,Redis都存储了一些不再使用的数据,平白无故的占用了一些空间。Redis的弱结构数据模式让集中储存的内容很难被弄清,除非你为键使用一套非常成熟的命名法则。使用合适的命名方法会简化你的数据库管理,当你通过你的应用程序或者服务做键的命名空间时(通常情况下是使用冒号来划分键名),你就可以在数据迁移、转换或者删除时轻松的识别。
Redis另一个常见用例是作为热数据项作的第二数据存储,大部分的数据被保存在其他的数据库中,比如PostgreSQL或MongoDB。在这些用例中,当数据从主存储移除时,开发者经常会忘记删除Redis中对应的数据。这种存在跨数据存储的情况下,通常需要做级联删除,这种情况下,可以通过在Redis配置保存特定数据项的所有识别符来实现,从而保证数据在主数据库被删除后,系统会调用一个清理程序来删除所有相关副本和信息。
2. 控制所有键名的长度
在上文我们说过要使用合适的命名规则,并且添加前缀来识别数据走向,因此这一条看起来似乎与之违背。但是,请别忘记,Redis是个内存数据库,键越短你需要的空间就越少。理所当然,当数据库中拥有数百万或者数十亿键时,键名的长度将影响重大。
举个例子:在一个32位的Redis服务器上,如果储存一百万个键,每个值的长度是32-character,那么在使用6-character长度键名时,将会消耗大约96MB的空间,但是如果使用12-character长度的键名时,空间消耗则会提升至111MB左右。随着键的增多,15%的额外开销将产生重大的影响。
3. 使用合适的数据结构
不管是内存使用或者是性能,有的时候数据结构将产生很大的影响,下面是一些可以参考的最佳实践:
取代将数据存储为数千(或者数百万)独立的字符串,可以考虑使用哈希数据结构将相关数据进行分组。哈希表是非常有效率的,并且可以减少你的内存使用;同时,哈希还更有益于细节抽象和代码可读。
合适时候,使用list代替set。如果你不需要使用set特性,List在使用更少内存的情况下可以提供比set更快的速度。
Sorted sets是最昂贵的数据结构,不管是内存消耗还是基本操作的复杂性。如果你只是需要一个查询记录的途径,并不在意排序这样的属性,那么轻建议使用哈希表。
Redis中一个经常被忽视的功能就是bitmaps或者bitsets(V2.2之后)。Bitsets允许你在Redis值上执行多个bit-level操作,比如一些轻量级的分析。
4. 使用SCAN时别使用键
从Redis v2.8开始,SCAN命令已经可用,它允许使用游标从keyspace中检索键。对比KEYS命令,虽然SCAN无法一次性返回所有匹配结果,但是却规避了阻塞系统这个高风险,从而也让一些操作可以放在主节点上执行。
需要注意的是,SCAN 命令是一个基于游标的迭代器。SCAN 命令每次被调用之后, 都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。同时,使用SCAN,用户还可以使用keyname模式和count选项对命令进行调整。
SCAN相关命令还包括SSCAN 命令、HSCAN 命令和 ZSCAN 命令,分别用于集合、哈希键及有续集等。
5. 使用服务器端Lua脚本
在Redis使用过程中,Lua脚本的支持无疑给开发者提供一个非常友好的开发环境,从而大幅度解放用户的创造力。如果使用得当,Lua脚本可以给性能和资源消耗带来非常大的改善。取代将数据传送给CPU,脚本允许你在最接近数据的地方执行逻辑,从而减少网络延时和数据的冗余传输。
在Redis中,Lua一个非常经典的用例就是数据过滤或者将数据聚合到应用程序。通过将处理工作流封装到一个脚本中,你只需要调用它就可以在更短的时间内使用很少的资源来获取一个更小的答案。
专家提示:Lua确实非常棒,但是同样也存在一些问题,比如很难进行错误报告和处理。一个明智的方法就是使用Redis的Pub/Sub功能,并且让脚本通过专用信道来推送日志消息。然后建立一个订阅者进程,并进行相应的处理。
set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。[1]
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
redis的官网地址,非常好记,是redis.io。(特意查了一下,域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
目前,Vmware在资助着redis项目的开发和维护。
doc http://doc.redisfans.com/index.html
5种基本type:String hash list set zset strings string是最简单类型,是二进制安全的 包含任何数据比如图片和对象序列化 set name hello get key setnx 如果k存在返加0 nx note exist 不覆盖,不存在设置新值 setnx name hello setex 设置k的值为string类型的value 并且指定有效期 setex namex 10 jak 10秒有效期 setrange 设置 指定key的value值 的子字符串 get name xiaomingxxxxxx@126.com setrange name 8 aaaaaa 从下标开始 替换指定长度跟替换的一样 get name mset 一次设置多个key的值 失败全不成功 mset k1 xiaoming k2 xiaohong msetnx note exis 不会覆盖已经存在的key getset 设置key的值 并返回key的旧值 getset k1 hello getrange 获取key的value的子字符串 getrange k1 0 3 从0到第3个返回 mget 批量获取 mget k1 k2 incr 递增 set k3 10 incr k3 incrby k4 10 加指定值 key不存在 则设置key 为认为原来的value为0 incrby k4 -10 decr 对key的值做减减 decrby 指定减 append 给指定key的字符串追加value append k1 world 返回长度 strlen 返回值长度 strlen k1
hashset类型 是一个string类型的field和value的映射表,它的添加、删除操作都是0(1)(平均) hash特别适合用于存储对象,相较于将对象的每个字段存成单个string 类型 将一个对象存在hash中会暂用很少的内在,并且可以方便的存取整个对象 hset 设置hash field为指定值 如果key不存在 则先创建 hset myhash field hello hset user:001 name jak hget user:001 name hsetnx user:002 name hello hmset 批量设值 hmset myhash field hello field2 world hmget 获取所有健 hmget user:002 name age x 批量返回 hincrby user:002 age 10 自增 hexists hash表字段是否存在 hexists user:002 age hlen返回指定hash的key数 hlen user:002 hdel 删除指定hash的field字段 hdel myhash age hkeys 返回hash所有字段 hkeys user:002 hvals 返回hash所有value hvals user:002 hgetall 获取某个hash中全部的字段和值 hgetall user:002
==================list start=========================== list是一个链表结构,主要功能是push,pop, 获取一个范围的所有值等等,操作中key理解为链表的名字。 redis的list类型其实就是一个每个子元素都是string类型的双向链表。 我们可以通过push pop操作从链表的头部或者尾部添加删除元素 这样list即可以作为栈,又可以作为队列。 push 压入一个元素 pop 弹出一个元素 lpush 从头部压入一个元素 先进后出 lpush mylist world lpush mylist hello lrange mylist 0 -1 取元素 hello world rpush从尾部压入元素 先进先出 队列 rpush list2 jak rpush list2 tom lrange list2 0 -1 jak tom linsert 在key对应list的特定位置前或后添加字符串 linsert list2 before jak sum lset 设置list中指定下标元素替换掉 lset list2 1 updatev lrem 从key对应list中删除N个和value相同的元素 (n<0从尾删除,N=0全部删除) lrem list2 2 jak 删除 几个元素 ltrim 保留指定key的值范围内的数据 ltrim list2 1 -1 把第0个删掉 lpop 从list的头部删除元素 并返回删除元素 lpop list2 rpop 从尾部弹出一个元素 rpop list2 lpoplpush 从第一个list的尾部移除元素并添加到第二个list的头部 lpoplpush list2 list3 lindex 返回名称为key的list中index位置的元素 linex list2 0 lindex list2 1 llen 返回key对应list的长度s llen list2 ==================list end===========================
===========sets 无序集合================ sadd myset1 one sadd myset1 two sadd myset1 two 不能增加重复值 smembers myset1 查看元素 srem 删除 srem myset1 one spop 随机弹出元素 sdiff 返回所有给定key与第一个Key的差集 sdiff myset1 myset2 sdiffstore 存储差集的值 sdiffstore myset3 myset1 myset2 sinter 交集 sinter myset1 myset2 sinterstore 存储交集的值 sunion 返回所有给定key的并集 sunion myset1 myset2 sunionstore 存储并集 smove 从第一key对应的set中移除元素并添加到第二个对诮的set中 smove myset1 myset2 three 把three从1移到2中 scard 返回名称key的集合个数 sismember 测试元素是否是名称为key的Set的元素 sismember myset1 two 返回1代表是 sismember myset1 twox 返回0代表不是 srandmember 随机返回集合的一个元素 ,但不删除元素 srandmember myset1 ====================
=================sorted sets 有序集合======================= 是set的一个升级版本 加一个顺序属性 zset会自动重新排序, 可以理解为有两列的mysql表 一列存value 一列为顺序,操作过程中 key可以理解为名称 zadd 向名称为key的zset中添加元素member,score用于排序 如果该元素存在,则更新其顺序 zadd myzset 1 one zadd myzset 2 two zadd myzset 3 two 会把顺序更新为3 zrange myzset 0 -1 withscores 0第一个位置 -1 最后一个 zrem 删除名称为key的zset中的元素member zrem myzset1 one zincrby 以指定值增加 如果在名称为key的zset中已经存在元素 memebre,则该元素的score增加incremernt否则 向该集合中添加该元素,其score的值为increment zincrby myzset 4 two 对顺序号进行增加 -数为减 zrank 返回名称为key的zset中memebr元素的排名 (按score从小到大排序) 即下标 zrank myzset1 two zrevrank 返回名称为key的zset中memebr元素的排名 (按score从大到小排序) 即下标 zrevrank myzset three zrevrange index降序排序 zrevrange myzset 0 -1 withscores zrangebyscore 返回2到3区间的元素 zrangebyscore myzset 2 3 withscores zcount 返回集合中score在给定区间的数量 zcount myzset 2 10 zcard 返回集合中所有个数 zcard myzset zremrangebyrank 删除集合中排名在给定区间的元素 zremrangebyrank myzset 2 3<pre code_snippet_id="657920" snippet_file_name="blog_20150503_5_8689354" name="code" class="html">排名zremrangebyscore 删除集合中给定区间的元素 zremrangebyscore myzset 1 2 删除指定的1-2的元素
<pre code_snippet_id="657920" snippet_file_name="blog_20150503_5_8689354" name="code" class="html">(代表索引 删除从2-3区间的元素)==================end==========================================
常用命令 redis提供了丰富的命令对数据库和各种数据库类型进行操作. 这些命令可以在linux终端使用 1 健值相关命令 2 服务器相关命令 keys 返回给定pattern 的所有key keys * 返回所有健 keys my* exists 确认一个key是否存在 exists myset 返回0不存在 1存在 del 删除一个key expire 设置一个key的过期时间 expire name 10 ttl name 查看还有多少时间过期 (3.0)-2为过期 move 将当前数据库中的key转移到其它数据库中 select 0 进入0数据库 se age 20 get age move age 1 将age 移到1数据库 get age select 1 进入1数据库 get age persist 移除给定key的过期时间 如果expire age 200 ttl age persiste age 对age健 取消过期时间 randomkey 随机返回key空间的一个key randomkey rename 重命名 rename set2 set200 type 返回key的类型 type myzset ===========健值 相关命令 end====== ============== 服务器相关命令 ping 测试连接是否存活 ping PONG 正常 echo 在命令行打印一些内容 echo helloworld 输出什么显示什么 select 选择数据库 redis 数据库编号0-15我们可以任意选择一个数据库进行存取 quit退出客户端连接 dbsize 返回当前数据中key的数目 info 获取服务器的信息和统计 config get 实时传储收到的请求 config get dir config get * 返回所有可选项 flushdb 删除当前选择数据库中的所有key fuushall 删除所有数据库中的key ==========end================
=========高级应用================== 安全性 主从复制 事务处理 持久化机制 发布订阅消息 虚拟内存的使用 安全性============ 设置客户端连接后进行任何其他指定前需要使用 的密码 vi /usr/local/redis/etc/redis.conf #requirepass foobared requirepass mypass auth 授权(密码) 登陆时 redis-cli -a 密码 主从复制============= slave server 拥有master的数据 Master可以拥有多个slave 不会阻塞master 在同步数据时master继续处理client 提高系统的伸缩性 redis.config改 slaveof 192.168.72.130 6379 #指定master的ip和端口 masterauth password #这是主机的密码 info查看主从 role ==============事务处理===================== client在一个连接中发出multi命令时, 这个连接会进入一个事务上下文, 该连接后续的命令不会立即执行, 而是先放到一个队列中,当执行exec命令时,redis会顺序的执行队列中的所有命令 getage multi 把所有命令放入队列 setage 10 setage 20 exec 执行队列中所有命令 discard 清空事务队列 回滚 乐观锁复杂事务控制 session1 get age watch age 监控值(可以对key加乐观锁) 从调用后发生过变化 则整个事务失败,exec discard,unwatch会清空 multi session2 set age 1000 get age session1 set age exec 失败 get age ======持久化机制===== 需要经常将内存中的数据同步到硬盘来保持持久化 1:snapshotting(快照)默认 将数据存入二进制文件 dump.rdb 可以配置 save 900 1 # 900秒内超过1个key被修改,则发起快照保存 save 300 10 # 300秒内超过10个key被修改,则发起快照保存 2:append-only file(aof)方式 将我们的写 改存入文件 由于快照是在一个时间内发起快照,所以redis意外 down掉的话,就会丢失最后一次的修改的数据 aof比快照方式更好的持久化性,是由于在aof时,redis会将每一个收到 的写命令都 会通过writer函数追加到文件中,当reids重启时会通过重新 执行文件中保存的写命令来在内在中重建整个数据库的内容 可以通过配置文件告诉redis我们想要通过fsync函数强制os写入磁盘的时机 appendonly yes //启用aof持久化方式 appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化 appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中 appendfsync no //完全依赖os,性能最好,持久化没保证 ======================发布级订阅消息 发布订阅(pub/sub)是一种消息通信模式。主要的目的是解除消息发布者 和订阅者之间的耦合,redis作为一个pub/sub的serve. 在订阅者和发布者之间起到了消息路由的功能 订阅者可通过subscribe和psubscribe命令向redis server订阅自已 感兴趣的消息类型,redis将信息类型称为通道 channel。当发布者通过publish命令向redis server v发送特定类型的信息时, 订阅该信息类型的全部client都会收到此消息 客户端1: subscribe tv1 tv2 订阅此频道 服务端: psubscribe tv1 helloworld 向tv1发布消息 =========================虚拟内存的使用 把经常不使用的数据交换到磁盘上 vm-enabled yes #开启vm 功能 vm-swap-file /tmp redis.swap #交换出来的value保存的文件路径 vm-max-memory 1000000 #redis使用的最大内在上限 vm-page-size 32 #每个页面的大小32 字节 vm-pages 134217728 #最多使用多少页面 vm-max-threads 4 #用于执行value对象换入的工作线程数量
使用Redis开发应用程序是一个很愉快的过程,但是就像其他技术一样,基于Redis的应用程序设计你同样需要牢记几点。在之前,你可能已经对关系型数据库开发的那一整个套路了然如胸,而基于Redis的应用程序开发也有许多相似的地方,但是你必须牢记以下两点——Redis是个内存数据库,同时它是单线程的。因此,在使用Redis时,你需要注意以下几点:
1. 掌控储存在Redis中的所有键
数据库的主要功能是储存数据,但是对于开发者来说,因为应用程序需求或者数据使用方法的改变,忽略存储在数据库中的某些数据是非常正常的,在Redis中同样如此。你可能忽视期满某些键,也可能因为应用程序的某个模块弃用而忘掉这些数据。
无论哪种情况,Redis都存储了一些不再使用的数据,平白无故的占用了一些空间。Redis的弱结构数据模式让集中储存的内容很难被弄清,除非你为键使用一套非常成熟的命名法则。使用合适的命名方法会简化你的数据库管理,当你通过你的应用程序或者服务做键的命名空间时(通常情况下是使用冒号来划分键名),你就可以在数据迁移、转换或者删除时轻松的识别。
Redis另一个常见用例是作为热数据项作的第二数据存储,大部分的数据被保存在其他的数据库中,比如PostgreSQL或MongoDB。在这些用例中,当数据从主存储移除时,开发者经常会忘记删除Redis中对应的数据。这种存在跨数据存储的情况下,通常需要做级联删除,这种情况下,可以通过在Redis配置保存特定数据项的所有识别符来实现,从而保证数据在主数据库被删除后,系统会调用一个清理程序来删除所有相关副本和信息。
2. 控制所有键名的长度
在上文我们说过要使用合适的命名规则,并且添加前缀来识别数据走向,因此这一条看起来似乎与之违背。但是,请别忘记,Redis是个内存数据库,键越短你需要的空间就越少。理所当然,当数据库中拥有数百万或者数十亿键时,键名的长度将影响重大。
举个例子:在一个32位的Redis服务器上,如果储存一百万个键,每个值的长度是32-character,那么在使用6-character长度键名时,将会消耗大约96MB的空间,但是如果使用12-character长度的键名时,空间消耗则会提升至111MB左右。随着键的增多,15%的额外开销将产生重大的影响。
3. 使用合适的数据结构
不管是内存使用或者是性能,有的时候数据结构将产生很大的影响,下面是一些可以参考的最佳实践:
取代将数据存储为数千(或者数百万)独立的字符串,可以考虑使用哈希数据结构将相关数据进行分组。哈希表是非常有效率的,并且可以减少你的内存使用;同时,哈希还更有益于细节抽象和代码可读。
合适时候,使用list代替set。如果你不需要使用set特性,List在使用更少内存的情况下可以提供比set更快的速度。
Sorted sets是最昂贵的数据结构,不管是内存消耗还是基本操作的复杂性。如果你只是需要一个查询记录的途径,并不在意排序这样的属性,那么轻建议使用哈希表。
Redis中一个经常被忽视的功能就是bitmaps或者bitsets(V2.2之后)。Bitsets允许你在Redis值上执行多个bit-level操作,比如一些轻量级的分析。
4. 使用SCAN时别使用键
从Redis v2.8开始,SCAN命令已经可用,它允许使用游标从keyspace中检索键。对比KEYS命令,虽然SCAN无法一次性返回所有匹配结果,但是却规避了阻塞系统这个高风险,从而也让一些操作可以放在主节点上执行。
需要注意的是,SCAN 命令是一个基于游标的迭代器。SCAN 命令每次被调用之后, 都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。同时,使用SCAN,用户还可以使用keyname模式和count选项对命令进行调整。
SCAN相关命令还包括SSCAN 命令、HSCAN 命令和 ZSCAN 命令,分别用于集合、哈希键及有续集等。
5. 使用服务器端Lua脚本
在Redis使用过程中,Lua脚本的支持无疑给开发者提供一个非常友好的开发环境,从而大幅度解放用户的创造力。如果使用得当,Lua脚本可以给性能和资源消耗带来非常大的改善。取代将数据传送给CPU,脚本允许你在最接近数据的地方执行逻辑,从而减少网络延时和数据的冗余传输。
在Redis中,Lua一个非常经典的用例就是数据过滤或者将数据聚合到应用程序。通过将处理工作流封装到一个脚本中,你只需要调用它就可以在更短的时间内使用很少的资源来获取一个更小的答案。
专家提示:Lua确实非常棒,但是同样也存在一些问题,比如很难进行错误报告和处理。一个明智的方法就是使用Redis的Pub/Sub功能,并且让脚本通过专用信道来推送日志消息。然后建立一个订阅者进程,并进行相应的处理。
相关文章推荐
- Redis学习记录之protocol简析(二十四)
- redis学习记录08-分片
- Redis学习记录之Sentinel(二十九)
- Redis学习记录之命令Set(十二)
- Redis学习记录之keyspace notification简析(二十三)
- redis学习记录
- REDIS 学习网页记录
- redis学习记录-关于MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist
- Redis学习记录(一) - Linux下的Redis的安装
- redis学习记录01-初识redis
- 菜鸟刚开始接触redis,记录一下学习的过程,以免忘记
- nosql学习记录 - redis (1)
- Redis学习记录之命令HyperLogLog(十四)
- Redis学习记录之Transaction(十八)
- Redis学习记录之Java中的初步使用
- Redis学习记录之下载安装(三)
- Redis学习记录之配置文件(三)
- Redis学习记录之Transaction简析(十九)
- 初步学习shiro+redis+springMVC的集成配置,做一下记录文档吧
- redis学习记录(redis的持久化操作、基于java的jedis操作)