您的位置:首页 > 数据库 > Redis

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
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功能,并且让脚本通过专用信道来推送日志消息。然后建立一个订阅者进程,并进行相应的处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: