Redis是Remote Dictionary Server(远程数据服务)的缩写,由意大利人Antirez(Salvatore Sanfilippo)开发的一款内存高速缓存数据库,它使用C语言编写,其数据模型为key-value
,并支持丰富的数据结构(类型),如string
、list
、hash
、set
、sorted sort
。可持久化,保证数据安全。
Redis小八卦,Salvatore Sanfilippo(antirez)是VMWare大善人聘请专心写Redis。Redis默认端口 6379 是手机按键上MERZ对应的号码,MERZ是意大利女歌手Alessia Merz梅尔兹的代名词。
Redis是一个key-value
的NoSQL产品,和MemCached类似,但它存储的value
类型相对更加丰富,包括string
字符串、list
链表、set
集合、zset
有序集合、hash
哈希。
与MemCached一样,为保证效率,数据都是缓存在内存中,区别是Redis会周期性把内存中的数据写入到硬盘(数据持久化、安全)。由于Redis支持的value类型众多,也被称之为结构化的NoSQL数据库。
在开发网站的时候有些数据在短时间内不会发生变化,而他们还要被频繁访问,为了提高用户请求速度并降低站点的负载,就把这些数据放到一个读取速度更快的介质上,或通过较少的计算量就可以获得该数据,该行为就称为对数据的缓存,该截止可是文件、数据库、内存,而内存常用做数据缓存。
缓存的两种形式中,页面缓存经常用在CMS内容管理系统里,数据缓存经常用在页面里的具体数据中。例如新闻页面适合做页面缓存,商城页面比较适合分区块做数据缓存。
MySQL数据库的数据实际上以文件形式存储在硬盘里,对于web应用而言,资源瓶颈大多出现在数据库上。常用缓存(cache)分为数据缓存和页面缓存(smarty),使用缓存技术可减轻数据库的负载。
Nosql简介
web2.0时代,nosql产品非常火热,常见产品如redis/memcached/mongodb.
nosql产品的特点:不使用严格的表结构,数据查询一般都不再使用sql查询
世界上正在使用的nosql产品 www.nosql-database.org
NoSQL产品的比较
KV存储 redis/memcached
文档存储 mongoDB(JSON)
Redis是一个KV的nosql产品,数据是在内存中存储,同时支持数据持久化操作,所以这个产品对数据完整性更加的友好.
Redis和Memcached比较
- redis不仅仅支持简单的KV类型的数据,同时提供list、set、zset、hash等数据结构的存储。
- redis支持master-slave主从模式应用
- redis支持数据持久化,可将内存中数据保存到硬盘,重启后可再起加载到内存。
- redis单个value的最大限制为1GB,memcached只能保存1MB的数据。
Redis数据类型
3.1 String 字符串类型
redis中的字符串是一个字节序列,redis中的字符串是二进制安全的,这意味着他们的长度不由任何特殊的终止字符决定.因此可在一个字符串中存储高达512MB的任何内容.
set name junchow
get name
set和get是redis命令,name是redis中使用的键名
- set 设置键值对
- get 通过键名获取键值
- incr 可对某个key的value进行+1
- decr 可对某个key的value进行-1
set age 20
get age
incr age
decr age
incrby 指定键名进行增加
incrby age 20
get age
decrby 指定键名进行减少
decrby age 20
get age
keys * 获取所有字键名
keys *
redis的key是如何设计的呢?
思考原先在mysql中数据是如何存储的
- 将mysql表名换成key的前缀
- 将mysql主键放在前缀后面,一般使用冒号分割.
- 将对应记录的主键值作为key的值
- 将mysql其他字段作为key的第四部分
例如:
// 将主键id为1名为junchow的用户保存到it表
it_user:id:1:username junchow
it_user:id:1:gender 1
it_user:id:1:email [email protected]
// 获取所有字段
keys it_user:id:1*
// 获取1号用户的姓名
get it_user:id:1:username
3.2 Hash 数据类型
//设置值
hset userinfo name junchow
//解析
hset : cmd
key: userinfo
value: name junchow
//等价于
$userinfo = array('name'=>'junchow')
//获取值
hget userinfo name
redis中的hash类型php中的关联数组
//设置多个hash值
hmset userinfo age 30 email [email protected]
//获取单个
hget userinfo age
hget userinfo email
//获取所有
hgetall userinfo
3.3 List 链表数据
链表类型类似于队列或栈的数据结构,链表可视为存储数据的容器.链表的左侧被称为头部,右侧被称为尾部.
链表可模拟出队列(先进先出),也可以模拟栈(先进后出).
//从左侧装入 lpush
lpush link1 A
lpush link1 B
//从右侧转入 rpush
rpush link2 A
rpush link2 B
//获取数据
lrange link1 0 -1
//lrange 表示从左侧开始获取link1中,0表示开始位置, -1表示结束位置.
B A
//从左侧弹出 lpop
lpop link1
// 从右侧弹出 rpop
rpop link1
链表数据结构在实际项目中有那些地方可以使用呢?
应用场景
后台要统计一下最近登录的10个用户,使用mysql来完成,形成这样一条sql.
SELECT * FROM user ORDER BY login_time DESC LIMIT 10;
若使用redis中的链表实现,将用户登录组件的id从左侧存入链表.
lpush loginuser alice
lpush loginuser ben
lpush loginuser carl
lpush loginuser deny
lpush loginuser elva
...
当链表中存储数据超过10个后
rpop
3.4 Set 无序集合类型
集合是数学里面常见概念,是一类无序数据的归总.集合满足三个特点:
- 无序性:集合中的元素是没有顺序之分的
- 唯一性:集合中的元素彼此是不能重复的
- 确定性:集合中的元素个数是确定的
集合运算
- 交集:集合之间公共的部分
- 并集:集合全部的元素
- 差集
集合命令
//向集合setvar添加元素
sadd setvar 1
sadd setvar 2
sadd setvar 3
//从集合setvar中获取元素
smembers setvar
//判断元素1是否在集合setvar中,成功返回1,失败返回0
sismember setvar 1
//从集合中移除元素,成功返回1,失败返回0
srem setvar 1
//从集合中随机弹出元素
spop setvar
//使用sunion求集合并集
sunion setvar myset
应用场景
- QQ中好友标签
- 社交类型网站中好友关系展示,例如好友推荐,共同好友
案例分析
1.设计4个用户
set sns_user:id:1:username alice
set sns_user:id:1:email [email protected]
set sns_user:id:2:username ben
set sns_user:id:2:email [email protected]
set sns_user:id:3:username carl
set sns_user:id:3:email [email protected]
set sns_user:id:4:username deny
set sns_user:id:4:email [email protected]
keys sns_user:id*
2.设计好友的集合
sadd set:user:id:3:friend 1
sadd set:user:id:3:friend 2
smembers set:user:id:3:friend
sadd set:user:id:2:friend 1
smembers set:user:id:2:friend
3.获取共同好友
sinter set:user:id:2:friend set:user:id:3:friend
4.获取所有好友
sunion set:user:id:2:friend set:user:id:3:friend
5.推荐好友
sdiff set:user:id:3:friend set:user:id:2:friend
3.5 Zset 有序集合类型
三大特点:
- 有序性
- 唯一性
- 确定性
有序集合需要给集合中每个元素权重值
操作命令:
//添加集合元素
zadd class:php 1 asion
zadd class:php 2 mark
zadd class:php 3 lily
zadd class:php 4 jack
//获取集合元素
zrange class:php 0 -1
//获取集合内容时显示权重信息
zrange class:php 0 -1 withscores
4. PHP操作Redis
connect($host, $port) or die('redis connect fail!');
//存取KV值
$key = 'username';
$val = 'junchow';
$redis->set($key,$val);
$val = $redis->get($key);
//删除指定键
$redis->delete($key);
//若不存在键设置值
$val = 'zhoujun';
$redis->setnx($key,$val);
//判断指定键是否存在
$redis->exists($key);
//递增递减
$key = 'age';
$val = 20;
$redis->incr($key);
$redis->decr($key);
//打印测试
var_dump($redis->get($key));
?>
5. Redis安全问题
操作redis时,默认无需客户端提供认证信息,即无需密码即可对redis实现操作,这本身是非常危险的,因此有必要开启redis的认证功能.
- 修改
/etc/redis/redis.conf
- 开启
requirepass foobared
,默认密码为foobared - 重启redis服务
sudo pkill -9 redis-server
sudo redis-server /etc/redis/redis.conf
sudo redis-cli -h 127.0.0.1 -p 6379
//成功登录后认证
auth foobared
//连接时认证
sudo redis-cli -h 127.0.0.1 -p 6379 -a foorbared
注意:由于redis.conf
中的requirepass
保存的是明文,所以要注意redis.conf文件的权限.
PHP操作Redis - 连接并认证
connect($host, $port);
$redis->auth($pass) or die('redis connected fail, please check password!');
?>
6. Redis 的持久化
redis为了本身数据安全和完整性,会把内存中的数据按一定方式同步到磁盘中,这个过程被称之为持久化操作.当下次再启动redis时会把磁盘上保存的数据重新加载到内存中.
常见持久化方式由两种:
- 基于快照的方式 : redis按一定周期将内存中的数据同步到磁盘文件中
- 基于日志文件的追加 : redis会把数据造成更改的命令记录到日志文件中,再次重启时执行日志文件中的命令,达到数据的还原.
基于快照的持久化
- 修改/etc/redis/redis.conf配置文件
# 若900秒内对键key进行过1次操作,则将内存数据同步到磁盘文件
save 900 1
# 若300秒内对键key进行过10次操作,则将内存数据同步到磁盘文件
save 300 10
# 若60秒内对键key进行过10000次操作,则将内存数据同步到磁盘文件
save 60 10000
redis持久化文件保存在哪里呢?
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir /var/lib/redis
保存在 /var/lib/redis/dump.rdb
可使用bgsave
命令手工出发快照持久化
基于日志追加方式持久化
修改/etc/redis/redis.conf配置文件,开启基于文件追加模式的持久化.
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
将 appendonly
设置为yes
,设置appendfilename
追加文件的名称.
备份文件的周期
# 只要存在对redis数据造成更改的操作,都要记录到磁盘文件上
# appendfsync always
# 每秒进行一次把对redis数据造成更改的操作记录到磁盘
appendfsync everysec
# 完全交给操作系统来完成,即操作系统不繁忙的时候会把对redis进行数据造成更改的操作记录到磁盘
# appendfsync no
重启redis服务
service redis-server restart