php检测:
extension_loaded('redis')
安装:
linux 安装redis以及配置redis开机自启
ps -ef |grep redis 查看进程
netstat -aup|grep 6379 查看端口
windows下php7.1安装redis扩展以及redis测试使用全过程
linux php配置redis扩展
注意:
non-thread-safe 非 线程安全 与IIS 搭配环境
thread-safe
线程安全 与apache 搭配的 环境
安装扩展后 记得下载服务端并开启(服务端就是自己系统的的我的是64位)
PHP操作redis http://www.cnblogs.com/catcrazy/p/6415802.html
PHP Redis 全部操作方法 https://www.cnblogs.com/glory-jzx/p/5714173.html
redis 数据类型详解 以及 redis适用场景场合
1,string类型:
string类型是二进制类型,可以将图片和视屏,等等保存起来,也可以将一些静态文件保存起来,如js、css等等
2,list类型:
list类型是双向链表结构,如在微博中的我关注的列表或者论坛中所有回帖用户的id等等数据,同时list也能实现简单的消息队列,具体可以先用rpush把消息放入到队列尾部,再用lpop把消息从队列头部取出
3,set类型:
set类型是一种无序类型,在redis内部是通过 HashTable实现,查找和删除元素十分快速,可以用于记录一些不能重复的数据,例如每次注册的时候将用户名存起来,每次新的用户注册的时候,都可以先set查询该用户名是否被注册,效率极高,还有一种比较广泛的应用就是投票系统,比如一天用户只能投票一次,我们就可以使用今天的日期作为set的key,存取用户的投票行为,查询的时候也用日期查询,是不是感觉效率很高呢
4,sorted set 类型:
sorted set 类似于set ,只不过sorted set 是一种有序集合,在web中比较有用,如我们要对博客按照顶贴进行排序,我们就可以将排序的字段设置成sorted set 的score,将具体数值设置成具体的值,每次更新数据只需要用zadd命令修改score的值就可以了
5,hash类型:
hash类型是每个key对用一个HashTable,适合于存储对象,例如用户的信息对象,用户id作为key,具体信息作为value
典型的应用场景:缓存、计数器(转发数评论数播放数)、消息队列系统、排行榜、实时社交网络、实时系统、
持久化(文件存储数据)
配置 slave 服务器很简单,只需要在配置文件中加入如下配置
slaveof 192.168.1.1 6379 #指定 master 的 ip 和端口
扩容--监控部署--主从切换---读写分离
急迫需要动态扩容-----自动部署,自动加监控----如何对业务透明----是否读写分离,可以按需配置
redis_cli 自带的redis管理工具
耗时命令日志:
当一条命令执行时间超过限制时,redis会将该命令的执行时间等参数加入(slow log)日志 存储在内存中
可以通过配置文件的slowlog-log-slower-than 微秒(1000000=1s 默认10000) 设置超过设置的数则保存在slow log
通过配置文件的slowlog-max-len 条数 设置记录的条数
在redis_cli客户端 输入 slowlog get 获取详细的耗时命令
127.0.0.1:6379> keys * 1) "str" 2) "no-order" 3) "user:100" 4) "order" 127.0.0.1:6379> slowlog get 1) 1) (integer) 0 该日志的唯一ID 2) (integer) 1535255077 该命令执行的unix时间 3) (integer) 48000 改命令的耗时时间(微秒) 4) 1) "keys" 该命令 2) "*" 参数 127.0.0.1:6379>
命令监控:
monitor 监控reids执行的所有命令
在redis_cli 输入回车 显示ok后 后面执行的所有命令都会被打印出来 注意非常消耗性能只能用于开发调试纠错
ps:instagram 团队开发了一个基于monitor 命令的的redis查询分析程序redis-faina 直接下载redis-faina.py
其他管理工具:phpRedisAdmin、Rdbtools
虚拟内存 (适用于 value 比 key 大的情况) :redis很吃内存的 暂时把不经常访问的数据从内存放到磁盘中 从而腾出内存空间
multi和pipeline
Redis::MULTI方式会将命令逐条发给redis服务端。只有在需要使用事物时才选择Redis::MULTI方式,它可以保证发给redis的一系列命令以原子方式执行。但效率相应也是最低的。
Redis::PIPELINE方式,可以将一系列命令打包发给redis服务端。如果只是为了一下执行多条redis命令,无需事物和原子性,那么应该选用Redis::PIPELINE方式。代码的性能会有大幅度提升!
Redis的原子性有两点:
1 、单个操作是原子性的
2、多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来 (事物具有原子性)
原子操作的意思就是要么成功执行要么失败完全不执行。用现实中的转账比喻最形象,你转账要么成功,要么失败钱不动,不存在你钱转出去了,但收款方没收到这种成功一半失败一半的情况
redis 实现事务的原理:
1. 批量操作在发送 EXEC 命令前被放入队列缓存
2. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令都不会被执行
3. 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中
$redis->setnx('str','字符串'); print_r($redis->get('str')); //字符串 /*hash*/ $redis->hsetnx('user:100','myhash','我的哈希'); print_r($redis->hget('user:100','myhash')); //我的哈希 /*列表list*/ $redis->lpush('list', 'html'); $redis->lpush('list', 'css'); $redis->lpush('list', 'php'); $redis->ltrim('list', 0,3); $list = $redis->lrange('list', 0, -1); print_r($list); //Array ( [0] => php [1] => css [2] => html [3] => php ) /*sets 无序集合 自动去重*/ $redis->sadd('no-order','无序集合1'); $redis->sadd('no-order','无序集合2'); print_r($redis->smembers('no-order')); //Array ( [0] => 无序集合2 [1] => 无序集合1 ) /*有序集合*/ $redis->zadd('order',0,'有序集合1'); $redis->zadd('order',2,'有序集合2'); print_r($redis->zrange('order',0,-1,'withscores')); //Array ( [有序集合1] => 0 [有序集合2] => 2 )
存对象可以序列化后再存
存数组可以转为json在存
简介 =========================== redis是一个key-value存储系统。 和Memcached类似,它支持存储的value类型相对更多, 包括string(字符串)、hash哈希、list(链表【栈、队列】)、set(集合)和zset(有序集合)。 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。 在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。 区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。 Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。 它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。 性能 =========================== ACID ========================================================== ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
一个支持事务(Transaction)的数据库系统,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。 事物处理 整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 一致性 在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。 隔离性 两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。 持久性 在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。 具体操作: =================================== 1. 安装redis 并布置环境(指定后台运行) # tar -zxvf redis-2.4.17.tar.gz 解压 # cd redis-2.4.17 进入目录 # make 编译 # make PREFIX=/usr/local/redis install 指定目录安装 # cd /usr/local/redis/ 进入安装后的目录 # mkdir etc logs 新建两个目录 # cp /lamp/redis-2.4.17/redis.conf etc/ 复制配置文件 # cd etc/ # vi redis.conf 修改配置文件:开启后台运行、指定日志文件。 #./redis-server ../etc/redis.conf 启动 #netstat -tunpl |grep redis # ./redis-server /usr/local/redis/etc/redis.conf 启动 # ps -ef | grep redis 查看进程 # netstat -tunpl | grep 6379 查看端口 # ./redis-cli 客户端命令链接服务器 redis 127.0.0.1:6379> redis 127.0.0.1:6379>quit 退出 # pkill redis-server 结束redis进程。 或: # ./redis-cli shutdown 执行关闭
命令一览
Redis常用命令 ============================= 1. 键值相关命令 >keys * //返回键(key) $redis->key('*'); >keys list* //返回名以list开头的所有键(key) >exists list1 //判断键名为list1的是否存在 存在返回1 不存在返回0 $redis->exists('yourkey')>del list1 //删除一个键(名为list1) expire key time 设置键的过期时间 >expire list1 10 //设置键名为list1的过期时间为10秒之后
expireat 设置过期时间 接受的是时间戳
pexpireat key_name 毫秒记的时间戳 设置key的过期时间,过期后将不再可用 ttl key 查看key的过期时间 >ttl list1 //查看键名为list1的过期时间,若为-1表示以过期 pttl 以毫秒为单位返回key的剩余的过期时间 >move age 1 //将键名age的转移到1数据库中。 >select 1 //表示进入到1数据库中,默认在0数据库 >persist age //移除age的过期时间(设置为过期) >type yourKey 检测key的数据类型 $redis->type('yourKey'); 返回 整型 对应下面几个常量 Redis::REDIS_STRING - String 1 字符串 Redis::REDIS_SET - Set 2 无序集合 Redis::REDIS_LIST - List 3 双向链表 (栈或者队列) Redis::REDIS_ZSET - Sorted set 4 有序集合 Redis::REDIS_HASH - Hash 5 哈希 Redis::REDIS_NOT_FOUND - Not found / other 0 未知
dump 序列化给定key,并返回被序列化的值
randomkey 从当前数据库中随机返回一个key
rename 修改key的名称
renamenx 仅当newkey不存在时将key改名为newkey
flushdb:删除所有的数据 Redis的数据类型 ================================= 1. 共计5种数据类型:
string(字符串)、hash(哈希表) list(双向链表)、set(集合)和zset(有序集合) 2. String(子串类型) -------------------------------------------- set 命令:设置一个键和值,键存在则只覆盖,返回ok > set 键 值 例如: >set name zhangsan get 命令:获取一个键的值,返回值 > get 键 例如:>get name setnx命令:设置一个不存在的键和值(防止覆盖), > setnx 键 值 若键已存在则返回0表示失败 setex命令:设置一个指定有效期的键和值(单位秒) > setex 键 [有效时间] 值 例如: >setex color 10 red 不写有效时间则表示永久有效,等价于set setrange命令:替换子字符串 (替换长度由子子串长度决定) > setrange 键 位置 子字串 > setrange name 4 aa 将name键对应值的第4个位置开始替换 假如 name 的值为lichihua 执行前面的代码后 返回lichaaua 位置 从0算起 mset命令:批量设置键和值,成功则返回ok > mset 键1 值1 键2 值2 键3 值3 .... msetnx命令:批量设置不存在的键和值,成功则返回ok > msetnx 键1 值1 键2 值2 键3 值3 .... getset命令:获取原值,并设置新值 > getset 键 新值 原值没有返回nil
getrange命令:获取指定范围的值 >getrange 键 0 4 //获取指定0到4位置上的值 mget命令: 批量获取值 >mget 键1 键2 键3.... incr命令: 指定键的值做加加操作,返回加后的结果。 整型(正整数或负整数)才能递增 > 键 例如: >incr kid
incrby命令: 设置某个键加上指定值 > incrby 键 m //其中m可以是正整数或负整数 incrby 3 在原来的基础上加3 decr命令: 指定键的值做减减操作,返回减后的结果。 > decr 键 例如: >decr kid
decrby命令: 设置某个键减上指定值 > decrby 键 m //其中m可以是正整数或负整数 append命令:给指定key的字符串追加value,返回新字符串值的长度 >append 键 追加字串 strlen 求长度
>strlen 键名 //返回对应的值。
3. hashes类型 ------------------------------------------ hset(name, key, value)命令:设置一个哈希表的键和值 >hset hash名 键 值 如:>hset user:001 name zhangsan
hget(name,key)命令: 获取执行哈希名中的键对应值 hsetnx(hashname, key, value)命令:设置一个哈希表中不存在的键和值 >hsetnx hash名 键 值 //成功返回1,失败返回0 如:>hsetnx user:001 name zhangsan hmset命令: hmset user:001 username zhangsan age 20 sex 1 批量设置 hmget: user:001 username age sex:批量获取值 >hexists user:001 name //是否存在, 若存在返回1 >hlen user:001 //获取某哈希user001名中键的数量 >hdel user:001 name //删除哈希user:001 中name键 >hkeys user:002 //返回哈希名为user:002中的所有键。 >hvals user:002 //返回哈希名为user:002中的所有值。 >hgetall user:002 //返回哈希名为user:002中的所有键和值。
hincrby(name, key, amount=1)自增name对应的hash中的指定key的值,不存在则创建key=amount
hincrbyfloat(name, key, amount=1.0) 自增name对应的hash中的指定key的值,不存在则创建key=amount
hscan(name, cursor=0, match=None, count=None) 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆# 参数:
# name,redis的name
# cursor,游标(基于游标分批取获取数据)
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
# 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
# ...
# 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
hscan_iter(name, match=None, count=None) 利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# 如:
# for item in r.hscan_iter('xx'):
# print item
4. list类型(双向链表结构) -------------------------------------------- list即可以作为“栈”也可以作为"队列"。 操作:
lpush 键 值 向队列头部插入一个值 >lpush list1 "world" //在list1头部压入一个字串 >lpush list1 "hello" // 在list1头部压入一个字串
lrange 返回队列指定(索引)区间的值
>lrange list1 0 -1 //获取list1中内容 返回队列指定区间的值 0:表示开头 -1表示结尾。
rpush 向队列的尾部插入一个值 >rpush list2 "world" //在list2尾部压入一个字串 >rpush list2 "hello" // 在list2尾部压入一个字串 >lrange list2 0 -1 //获取list2中内容 0:表示开头 -1表示结尾。
linsert 在key对应的list的特定位置的钱或者后面添加字符串 >linsert list2 before hello there //在list2的hello前加入there
lset key index value 修改指定索引位置上的值 >lset list2 1 "four" 修改指定索引位置上的值
lrem key cout value 移除队列值 >lrem list2 2 "hello" //删除前两个hello值 >lrem list2 -2 "hello" //删除后两个hello值 >lrem list2 0 "hello" //删除所有hello值
ltrim key start stop 删除给定范围的值 >ltrim mylist8 1 3 //删除此范围外的值 >lpop list2 //从list2的头部删除元素,并返回删除元素 >rpop list2 //从list2的尾部删除元素,并返回删除元素 >rpoplpush list1 list2 //将list1的尾部一个元素移出到list2头部。并返回 >lindex list2 1 //返回list2中索引位置上的元素 >llen list2 //返回list2上长度
blpop key1 [key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
> blpop list1 100
> blpop list1 list2 100
brpop key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
> brpop list1 100
> brpop list1 list2 100
brpoplpush list1 another_list timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
rpushx key_name value1 [..valuen] 为依存在的队列(列表)尾部插入一个或者多个值
lpushx key_name value1 [..valuen] 为依存在的队列(列表)头部插入一个或多个值
5.无序集合set类型和操作 ------------------------------- >sadd myset "hello" //向myset中添加一个元素 成功返回1,失败(重复)返回0 >smembers myset //获取myset中的所有元素(结果是无序的) >srem myset "one" //从myset中删除一个one 成功返回1,失败(不存在)返回0 >spop myset //随机返回并删除myset中的一个元素 >srandmember myset //随机获取myset中的一个元素,但是不删除 > smove myset1 myset2 zhangsan:将myset1中zhangsan移动到myset2中 > scard myset1 返回myset1的个数 > sismember myset zhangsan:判断张三是否在myset中 >sdiff myset1 myset2 //返回两个集合的差集以myset1为标准,获取myset2中不存在的。
>sdiffstore dstset myset1 myset2 ...// 返回所有集合的差集,并保存到dstset中 >sinter myset1 myset2 myset3... // 返回N个集合中的交集 >sinterstore dstset myset1 myset2 ... // 返回N个集合的交集并存储到dstset中 > sunion myset1 myset2 ...//返回所有集合的并集 > sunionstore dstset myset1 myset2// 返回所有集合的并集,并存储到dstset中
sscan key index [MATCH pattern] [COUNT count] 迭代(遍历)集合中key的元值
>sscan myset1 0 match h*
6.有序集合zset
-----------------------------------------
zadd key_name score1 value1.. scoren valuen 向有序集合添加一个或者多个成员,或者更新已存在成员的分数 score位排序!
> zadd myzset 1 "one" 向myzset中添加one,排序为1排序
> zadd myzset 2 "two" 3 "three"
zrem key member [member ...] 移除有序集合中的一个或多个成员
> zrem myzset one:删除zset中one
zincrby key increment member 有序集合中对指定成员的分数加上增量 increment
> zincrby zset 2 one:如果one存在,则顺序增加2,如果one不存在,那么就是2 ???
zrank key member 返回有序集合中指定成员的索引
> zrank zset one:返回one在zset中排名(从小到大的排序)
zrevrank key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
> zrevrank zset one:返回one在zset中排名(从大到小的排序)
zrange key start stop [withscores] 通过索引区间返回有序集合成指定区间内的成员
> zrange zset 0 -1 withscores:根据score排序(根据score从小到大排序)
zrevrange key start stop [withscores] 返回有序集中指定区间内的成员,通过索引,分数从高到底
> zrevrange zset 0 -1 withscores:根据score排序(根据score从大到小排序)
zrangebyscore key min max [withscores] [limit offset count] 通过分数返回有序集合指定区间内的成员
> zrangebyscore zset 2 3 withscores:返回集合中score在给定区间的元素(包含2和5)
zcount key min max 计算在有序集合中指定区间分数的成员数
> zcount zset 2 3:返回集合中给定区间的数量
zcard key_name 获取有序集合的成员数
> zcard zset:返回集合中元素的个数
zscore key member 返回有序集中,成员的分数值
> zscore zset one:返回one元素的score
zremrangebyrank key start stop 移除有序集合中给定的排名区间的所有成员
> zremrangebyrank zset 3 3:删除集合中排名在给定区间的元素
zremrangebyscore key min max 移除有序集合中给定的分数区间的所有成员
> zremrangebyscore zset 1 2:将zset中从小到大排序结果的score在1-2之间的删除
zinterstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中 其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。默认情况下,结果集中某个成员的分数值是所有给定集下该成员分数值之和。 # 有序集 mid_test > ZADD mid_test 70 "Li Lei" (integer) 1 > ZADD mid_test 70 "Han Meimei" (integer) 1 > ZADD mid_test 99.5 "Tom" (integer) 1 # 另一个有序集 fin_test > ZADD fin_test 88 "Li Lei" (integer) 1 > ZADD fin_test 75 "Han Meimei" (integer) 1 > ZADD fin_test 99.5 "Tom" (integer) 1 # 交集 > ZINTERSTORE sum_point 2 mid_test fin_test (integer) 3 # 显示有序集内所有成员及其分数值 > ZRANGE sum_point 0 -1 WITHSCORES 1) "Han Meimei" 2) "145" 3) "Li Lei" 4) "158" 5) "Tom" 6) "199" zlexcount key min max 在有序集合中计算指定字典区间内成员数量 > ZADD myzset 0 a 0 b 0 c 0 d 0 e > ZADD myzset 0 f 0 g > ZLEXCOUNT myzset - + (integer) 7 > ZLEXCOUNT myzset [b [f (integer) 5 zrangebylex key min max [limit offset count] 通过字典区间返回有序集合的成员 > zadd myzset 0 a 0 b 0 c 0 d 0 e 0 f 0 g > zrangebylex myzset - [c 1) "a" 2) "b" 3) "c" > zrangebylex myzset [aaa (g 1) "b" 2) "c" 3) "d" 4) "e" 5) "f" zremrangebylex key min max 移除有序集合中给定的字典区间(min和max之间)的所有成员 min个max以[或者(开头 可以用-表示最小值+表示最大值 min和max顺序不能相反 > zadd zset 0 a 0 aa 0 abc 0 apple 0 b 0 c 0 d 0 d1 0 dd 0 dobble 0 z 0 z1 > zremrangebylex zset [d1 (dd 删除d1这个元素 > zremrangebylex zset [a [apple > zrange zset 0 -1 withscores > zremrangebylex zset - + zrevrangebyscore key max min [withscores] [limit offset count] 返回有序集中指定分数区间内的成员,分数从高到低排序 > ZADD salary 10086 jack > ZADD salary 5000 tom > ZADD salary 7500 peter > ZADD salary 3500 joe > ZREVRANGEBYSCORE salary +inf -inf # 逆序排列所有成员 1) "jack" 2) "peter" 3) "tom" 4) "joe" > ZREVRANGEBYSCORE salary 10000 2000 # 逆序排列薪水介于 10000 和 2000 之间的成员 1) "peter" 2) "tom" 3) "joe" zunionstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] 计算给定的一个或多个有序集的并集,并存储在新的 key 中 其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination,默认情况下,结果集中某个成员的分数值是所有给定集下该成员分数值之和 。 > ZADD zset1 1 "one" > ZADD zset1 2 "two" > ZADD zset2 1 "one" > ZADD zset2 2 "two" > ZADD zset2 3 "three" > zunionstore out 2 zset1 zset2 WEIGHTS 2 3 > zrange out 0 -1 WITHSCORES 1) "one" 2) "5" 3) "three" 4) "9" 5) "two" 6) "10" zscan key cursor [MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值)
Redis常用命令 ============================= 1. 键值相关命令 >keys * //返回键(key) $redis->key('*'); >keys list* //返回名以list开头的所有键(key) >exists list1 //判断键名为list1的是否存在 $redis->exists('yourkey') 存在返回1, 不存在返回0 >del list1 //删除一个键(名为list1)
expire key time 设置键的过期时间
>expire list1 10 //设置键名为list1的过期时间为10秒之后
ttl key 查看key的过期时间
>ttl list1 //查看键名为list1的过期时间,若为-1表示以过期
>move age 1 //将键名age的转移到1数据库中。 >select 1 //表示进入到1数据库中,默认在0数据库 >persist age //移除age的过期时间(设置为过期) >type yourKey 检测key的数据类型 $redis->type('yourKey'); 返回 整型 对应下面几个常量
Redis::REDIS_STRING - String 1 字符串
Redis::REDIS_SET - Set 2 无序集合
Redis::REDIS_LIST - List 3 双向链表 (栈或者队列)
Redis::REDIS_ZSET - Sorted set 4 有序集合
Redis::REDIS_HASH - Hash 5 哈希
Redis::REDIS_NOT_FOUND - Not found / other 0 未知
Redis高级实用特性 ================================== 1. 安全性:为Redis添加密码 ------------------------------- 1.进入配置文件: vi /usr/local/redis/etc/redis.conf 设置:requirepass redis的密码 2. 重启服务: # ./redis-cli shutdown 执行关闭 # ./redis-server /usr/local/redis/etc/redis.conf 启动 3. 登录(两种) # ./redis-cli 客户端命令链接服务器 >auth 密码值 //授权后方可使用 # ./redis-cli -a 密码 //连接时指定密码来进行授权 2. 主从复制 ------------------------------------------ 操作步骤: 1.先将linux虚拟机关闭,之后克隆一个。 2.启动两个虚拟机:master(主)和slave(从) 3. 在slave(从)中配置一下ip地址 # ifconfig eth0 192.168.128.229 # ping 一下看看通不通。 4. 配置从机 进入:配置文件 slaveof 192.168.128.228 6379 //配置连接主机的Redis的ip和端口 masterauth 密码 //配置连接密码 最后启动slave(从)机的Redis服务。 其他:可以通过info命令中的role属性查看自己角色是master、slave 3. 事务处理 -------------------------------------------- >multi //开启一个事务 >set age 10 //暂存指令队列 >set age 20 >exec //开始执行(提交事务) 或>discard //清空指令队列(事务回滚) 4. 乐观锁 ----------------------------------- 在事务前对被操作的属性做一个: > watch age >multi //开启一个事务(在此期间有其他修改,则此处会失败) >set age 10 //暂存指令队列 >set age 20 >exec //开始执行(提交事务) 或>discard //清空指令队列(事务回滚) 5. 持久化机制(通过修改配置文件做设置) ----------------------------------- 1. snapshotting(快照)默认方式 配置 save save 900 1 #900秒内如果超过1个key被修改,则发起快照保存 save 300 10 #300秒内容如超过10个key被修改,则发起快照保存 save 60 10000 2. Append-only file(aof方式) 配置 appendonly on 改为yes 会在bin目录下产生一个.aof的文件 关于aof的配置 appendonly yes //启用aof 持久化方式 # appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化 appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中 # appendfsync no //完全依赖os,性能最好,持久化没保证 6. 发布及订阅消息 ---------------------- 需要开启多个会话端口 会话1:>subscribe tv1 //监听tv1频道 会话2:>subscribe tv1 tv2 //监听tv1和tv2频道 会话3: >publish tv1 消息 //向tv1频道发送一个消息
unsubscribe 取消订阅所有频道
<?php //发布 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $message='新年快乐'; $ret=$redis->publish('中央广播电台',$message);
<?php //订阅 ini_set('default_socket_timeout', -1); //不超时 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $result=$redis->subscribe(array('中央广播电台'), 'callback'); function callback($instance,$channelName,$message){ echo $message; }
7. 使用虚拟内存 ------------------------------- 在redis配置文件中设置 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对象换入患处的工作线程数量
PHP_Redis ========================================= 一、为php环境安装Redis支持(加模块) 1. 将owlient-phpredis-2.1.1-1-g90ecd17.tar.gz文件传到服务器上 2. 解压文件后进入此目录 3. 由于目录中没有configure配置环境 执行 /usr/local/php/bin/phpize 来准备一个编译环境 4. 配置: 加配置 ./configure --with-php-config=/usr/local/php/bin/php-config 5. make 编译 6. make install 安装 7. 安装成功后就会在如下目录下产生一个redis.so文件 /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/ 8. 安装后,使用vi 进入 /usr/local/php/etc/php.ini 加上:extension=“redis.so” 9. 重启apache服务即可(查看phpinfo) 二、代码编写: $redis=new Redis(); 创建Redis对象 $redis->connect("localhost"); 连接Redis服务器 $redis->auth("123"); 使用密码做登陆验证 添加操作 $id=$redis->incr("userid"); 自增一个值 $redis->rpush("ids",$id); 在尾部追加一个值 $redis->hmset("key:$id",array("username"=>$username,"password"=>$password)); 添加数据 获取: $data=$redis->lrange("ids","0","-1"); //获取所有id号值 foreach($data as $val){ //遍历 $row=$redis->hgetall("key:$val"); //获取对应的信息 // .....输出到表格中 } 删除 $id=$_GET['id']; if($redis->lrem("ids",$id,1)){ if($redis->del("key:$id")){ echo "<script>location='index.php'</script>"; } } 详情 $data=$redis->hgetall("key:$id"); 修改: $redis->hmset("key:$id",array("username"=>$username,"password"=>$password));
1.复制php_igbinary.dll,php_redis.dll文件到php目录下的ext(扩展)目录下 2.打开php.ini配置文件,搜索extension,在最下面添加这两行代码 extension=php_igbinary.dll extension=php_redis.dll 3.重启apache,打开PHPinfo();,搜索redis redis Redis Support enabled Redis Version 2.2.2 $redis = new Redis(); $redis->connect('localhost', 6379); //普通set/get操作 $redis->set('library', 'predis'); $retval = $redis->get('library'); echo $retval; //显示 'predis' //setex set一个存储时效 $redis->setex('str', 10, 'bar'); //表示存储有效期为10秒 //setnx/msetnx相当于add操作,不会覆盖已有值 $redis->setnx('foo',12); //true $redis->setnx('foo',34); //false //getset操作,set的变种,结果返回替换前的值 $redis->getset('foo',56);//返回34 // incrby/incr/decrby/decr 对值的递增和递减 $redis->incr('foo'); //foo为57 $redis->incrby('foo',2); //foo为59 //exists检测是否存在某值 $redis->exists('foo');//true //del 删除 $redis->del('foo');//true //type 类型检测,字符串返回string(1),列表返回 list(3),set表返回set(2)/zset(4),hash表返回hash(5) $redis->type('foo');//不存在,返回none $redis->set('str','test'); $redis->type('str'); //字符串,返回string //append 连接到已存在字符串 $redis->append('str','_123'); //返回累加后的字符串长度8,此进str为 'test_123' //setrange 部分替换操作 $redis->setrange('str',0,'abc'); //返回3,参数2为0时等同于set操作 $redis->setrange('str',2,'cd');//返回4,表示从第2个字符后替换,这时'str'为'abcd' //substr 部分获取操作 $redis->substr('str',0,2);//表示从第0个起,取到第2个字符,共3个,返回'abc' //strlen 获取字符串长度 $redis->strlen('str'); //返回4 //keys 模糊查找功能,支持*号以及?号(匹配一个字符) $redis->set('foo1',123); $redis->set('foo2',456); $redis->keys('foo*'); //返回foo1和foo2的array $redis->keys('f?o?'); //同上 //randomkey 随机返回一个key $redis->randomkey(); //可能是返回 'foo1'或者是'foo2'及其它任何一存在redis的key //rename/renamenx 对key进行改名,所不同的是renamenx不允许改成已存在的key $redis->rename('str','str2'); //把原先命名为'str'的key改成了'str2' //expire 设置key-value的时效性,ttl 获取剩余有效期,persist 重新设置为永久存储 $redis->expire('foo', 1); //设置有效期为1秒 $redis->ttl('foo'); //返回有效期值1s $redis->expire('foo'); //取消expire行为 //dbsize 返回redis当前数据库的记录总数 $redis->dbsize(); /** hash表操作 */ //hset/hget 存取hash表的数据 $redis->hset('hash1','key1','v1'); //将key为'key1' value为'v1'的元素存入hash1表 $redis->hset('hash1','key2','v2'); $redis->hget('hash1','key1'); //取出表'hash1'中的key 'key1'的值,返回'v1' //hexists 返回hash表中的指定key是否存在 $redis->hexists ('hash1','key1'); //true or false //hdel 删除hash表中指定key的元素 $redis->hdel('hash1','key2'); //true or false //hlen 返回hash表元素个数 $redis->hlen('hash1'); //1 //hsetnx 增加一个元素,但不能重复 $redis->hsetnx('hash1','key1','v2'); //false $redis->hsetnx('hash1','key2','v2'); //true //hmset/hmget 存取多个元素到hash表 $redis->hmset('hash1',array('key3'=>'v3','key4'=>'v4')); $redis->hmget('hash1',array('key3','key4')); //返回相应的值 array('v3','v4') //hincrby 对指定key进行累加 $redis->hincrby('hash1','key5',3); //返回3 $redis->hincrby('hash1','key5',10); //返回13 //hkeys 返回hash表中的所有key $redis->hkeys('hash1'); //返回array('key1','key2','key3','key4','key5') //hvals 返回hash表中的所有value $redis->hvals('hash1'); //返回array('v1','v2','v3','v4',13) //hgetall 返回整个hash表元素 $redis->hgetall('hash1'); //返回array('key1'=>'v1','key2'=>'v2','key3'=>'v3','key4'=>'v4','key5'=>13) /* 队列操作 */ //rpush/rpushx 有序列表操作,从队列后插入元素 //lpush/lpushx 和rpush/rpushx的区别是插入到队列的头部,同上,'x'含义是只对已存在的key进行操作 $redis->rpush('fooList', 'bar1'); //返回一个列表的长度1 $redis->lpush('fooList', 'bar0'); //返回一个列表的长度2 $redis->rpushx('fooList', 'bar2'); //返回3,rpushx只对已存在的队列做添加,否则返回0 //llen返回当前列表长度 $redis->llen('fooList');//3 //lrange 返回队列中一个区间的元素 $redis->lrange('fooList',0,1); //返回数组包含第0个至第1个共2个元素 $redis->lrange('fooList',0,-1);//返回第0个至倒数第一个,相当于返回所有元素,注意redis中很多时候会用到负数,下同 //lindex 返回指定顺序位置的list元素 $redis->lindex('fooList',1); //返回'bar1' //lset 修改队列中指定位置的value $redis->lset('fooList',1,'123');//修改位置1的元素,返回true //lrem 删除队列中左起指定数量的字符 $redis->lrem('fooList',1,'_'); //删除队列中左起1个字符'_'(若有) //lpop/rpop 类似栈结构地弹出(并删除)最左或最右的一个元素 $redis->lpop('fooList'); //'bar0' $redis->rpop('fooList'); //'bar2' //ltrim 队列修改,保留左边起若干元素,其余删除 $redis->ltrim('fooList', 0,1); //保留左边起第0个至第1个元素 //rpoplpush 从一个队列中pop出元素并push到另一个队列 $redis->rpush('list1','ab0'); $redis->rpush('list1','ab1'); $redis->rpush('list2','ab2'); $redis->rpush('list2','ab3'); $redis->rpoplpush('list1','list2');//结果list1 =>array('ab0'),list2 =>array('ab1','ab2','ab3') $redis->rpoplpush('list2','list2');//也适用于同一个队列,把最后一个元素移到头部list2 =>array('ab3','ab1','ab2') //linsert 在队列的中间指定元素前或后插入元素 $redis->linsert('list2', 'before','ab1','123'); //表示在元素'ab1'之前插入'123' $redis->linsert('list2', 'after','ab1','456'); //表示在元素'ab1'之后插入'456' //blpop/brpop 阻塞并等待一个列队不为空时,再pop出最左或最右的一个元素(这个功能在php以外可以说非常好用) //brpoplpush 同样是阻塞并等待操作,结果同rpoplpush一样 $redis->blpop('list3',10); //如果list3为空则一直等待,直到不为空时将第一元素弹出,10秒后超时 /** set表操作 */ //sadd 增加元素,返回true,重复返回false $redis->sadd('set1','ab'); $redis->sadd('set1','cd'); $redis->sadd('set1','ef'); //srem 移除指定元素 $redis->srem('set1','cd'); //删除'cd'元素 //spop 弹出首元素 $redis->spop('set1'); //smove 移动当前set表的指定元素到另一个set表 $redis->sadd('set2','123'); $redis->smove('set1','set2','ab');//移动'set1'中的'ab'到'set2',返回true or false //scard 返回当前set表元素个数 $redis->scard('set2');//2 //sismember 判断元素是否属于当前表 $redis->sismember('set2','123'); //true or false //smembers 返回当前表的所有元素 $redis->smembers('set2'); //array('123','ab'); //sinter/sunion/sdiff 返回两个表中元素的交集/并集/补集 $redis->sadd('set1','ab'); $redis->sinter('set2','set1'); //返回array('ab') //sinterstore/sunionstore/sdiffstore 将两个表交集/并集/补集元素copy到第三个表中 $redis->set('foo',0); $redis->sinterstore('foo','set1'); //这边等同于将'set1'的内容copy到'foo'中,并将'foo'转为set表 $redis->sinterstore('foo',array('set1','set2')); //将'set1'和'set2'中相同的元素copy到'foo'表中,覆盖'foo'原有内容 //srandmember 返回表中一个随机元素 $redis->srandmember('set1'); /** 有序set表操作 */ //sadd 增加元素,并设置序号,返回true,重复返回false $redis->zadd('zset1',1,'ab'); $redis->zadd('zset1',2,'cd'); $redis->zadd('zset1',3,'ef'); //zincrby 对指定元素索引值的增减,改变元素排列次序 $redis->zincrby('zset1',10,'ab');//返回11 //zrem 移除指定元素 $redis->zrem('zset1','ef'); //true or false //zrange 按位置次序返回表中指定区间的元素 $redis->zrange('zset1',0,1); //返回位置0和1之间(两个)的元素 $redis->zrange('zset1',0,-1);//返回位置0和倒数第一个元素之间的元素(相当于所有元素) //zrevrange 同上,返回表中指定区间的元素,按次序倒排 $redis->zrevrange('zset1',0,-1); //元素顺序和zrange相反 //zrangebyscore/zrevrangebyscore 按顺序/降序返回表中指定索引区间的元素 $redis->zadd('zset1',3,'ef'); $redis->zadd('zset1',5,'gh'); $redis->zrangebyscore('zset1',2,9); //返回索引值2-9之间的元素 array('ef','gh') //参数形式 $redis->zrangebyscore('zset1',2,9,'withscores'); //返回索引值2-9之间的元素并包含索引值 array(array('ef',3),array('gh',5)) $redis->zrangebyscore('zset1',2,9,array('withscores' =>true,'limit'=>array(1, 2))); //返回索引值2-9之间的元素,'withscores' =>true表示包含索引值; 'limit'=>array(1, 2),表示最多返回2条,结果为array(array('ef',3),array('gh',5)) //zunionstore/zinterstore 将多个表的并集/交集存入另一个表中 $redis->zunionstore('zset3',array('zset1','zset2','zset0')); //将'zset1','zset2','zset0'的并集存入'zset3' //其它参数 $redis->zunionstore('zset3',array('zset1','zset2'),array('weights' => array(5,0)));//weights参数表示权重,其中表示并集后值大于5的元素排在前,大于0的排在后 $redis->zunionstore('zset3',array('zset1','zset2'),array('aggregate' => 'max'));//'aggregate' => 'max'或'min'表示并集后相同的元素是取大值或是取小值 //zcount 统计一个索引区间的元素个数 $redis->zcount('zset1',3,5);//2 $redis->zcount('zset1','(3',5)); //'(3'表示索引值在3-5之间但不含3,同理也可以使用'(5'表示上限为5但不含5 //zcard 统计元素个数 $redis->zcard('zset1');//4 //zscore 查询元素的索引 $redis->zscore('zset1','ef');//3 //zremrangebyscore 删除一个索引区间的元素 $redis->zremrangebyscore('zset1',0,2); //删除索引在0-2之间的元素('ab','cd'),返回删除元素个数2 //zrank/zrevrank 返回元素所在表顺序/降序的位置(不是索引) $redis->zrank('zset1','ef');//返回0,因为它是第一个元素;zrevrank则返回1(最后一个) //zremrangebyrank 删除表中指定位置区间的元素 $redis->zremrangebyrank('zset1',0,10); //删除位置为0-10的元素,返回删除的元素个数2 /** 排序操作 */ //sort 排序 $redis->rpush('tab',3); $redis->rpush('tab',2); $redis->rpush('tab',17); $redis->sort('tab'); //返回array(2,3,17) //使用参数,可组合使用 array('sort' => 'desc','limit' => array(1, 2)) $redis->sort('tab',array('sort' => 'desc')); //降序排列,返回array(17,3,2) $redis->sort('tab',array('limit' => array(1, 2))); //返回顺序位置中1的元素2个(这里的2是指个数,而不是位置),返回array(3,17) $redis->sort('tab',array('limit' => array('alpha' => true))); //按首字符排序返回array(17,2,3),因为17的首字符是'1'所以排首位置 $redis->sort('tab',array('limit' => array('store' => 'ordered'))); //表示永久性排序,返回元素个数 $redis->sort('tab',array('limit' => array('get' => 'pre_*'))); //使用了通配符'*'过滤元素,表示只返回以'pre_'开头的元素 /** redis管理操作 */ //select 指定要操作的数据库 $redis->select('mydb'); //指定为mydb,不存在则创建 //flushdb 清空当前库 $redis->flushdb(); //move 移动当库的元素到其它库 $redis->set('foo', 'bar'); $redis->move('foo', 'mydb2'); //若'mydb2'库存在 //info 显示服务当状态信息 $redis->info(); //slaveof 配置从服务器 $redis->slaveof('127.0.0.1',80); //配置127.0.0.1端口80的服务器为从服务器 $redis->slaveof(); //清除从服务器 //同步保存服务器数据到磁盘 $redis->save(); //异步保存服务器数据到磁盘 $redis->bgsave(); //?? $redis->bgrewriteaof(); //返回最后更新磁盘的时间 $redis->lastsave(); //set/get多个key-value $mkv = array( 'usr:0001' => 'First user', 'usr:0002' => 'Second user', 'usr:0003' => 'Third user' ); $redis->mset($mkv); //存储多个key对应的value $retval = $redis->mget(array_keys($mkv)); //获取多个key对应的value print_r($retval); //批量操作 $replies = $redis->pipeline(function($pipe) { $pipe->ping(); $pipe->flushdb(); $pipe->incrby('counter', 10); //增量操作 $pipe->incrby('counter', 30); $pipe->exists('counter'); $pipe->get('counter'); $pipe->mget('does_not_exist', 'counter'); }); print_r($replies); //CAS,事务性操作 function zpop($client, $zsetKey) { $element = null; $options = array( 'cas' => true, // Initialize with support for CAS operations 'watch' => $zsetKey, // Key that needs to be WATCHed to detect changes 'retry' => 3, // Number of retries on aborted transactions, after // which the client bails out with an exception. ); $txReply = $client->multiExec($options, function($tx) use ($zsetKey, &$element) { @list($element) = $tx->zrange($zsetKey, 0, 0); if (isset($element)) { $tx->multi(); // With CAS, MULTI *must* be explicitly invoked. $tx->zrem($zsetKey, $element); } }); return $element; } $zpopped = zpop($redis, 'zset'); echo isset($zpopped) ? “ZPOPed $zpopped” : “Nothing to ZPOP!”, “ ”; //对存取的key加前缀,如: 'nrk:' $redis->getProfile()->setPreprocessor(new KeyPrefixPreprocessor('nrk:')); //分布式存储的一些方法 $multiple_servers = array( array( 'host' => '127.0.0.1', 'port' => 6379, 'database' => 15, 'alias' => 'first', ), array( 'host' => '127.0.0.1', 'port' => 6380, 'database' => 15, 'alias' => 'second', ), ); use PredisDistributionIDistributionStrategy; class NaiveDistributionStrategy implements IDistributionStrategy { private $_nodes, $_nodesCount; public function __constructor() { $this->_nodes = array(); $this->_nodesCount = 0; } public function add($node, $weight = null) { $this->_nodes[] = $node; $this->_nodesCount++; } public function remove($node) { $this->_nodes = array_filter($this->_nodes, function($n) use($node) { return $n !== $node; }); $this->_nodesCount = count($this->_nodes); } public function get($key) { $count = $this->_nodesCount; if ($count === 0) { throw new RuntimeException('No connections'); } return $this->_nodes[$count > 1 ? abs(crc32($key) % $count) : 0]; } public function generateKey($value) { return crc32($value); } } //配置键分布策略 $options = array( 'key_distribution' => new NaiveDistributionStrategy(), ); $redis = new PredisClient($multiple_servers, $options); for ($i = 0; $i set(“key:$i”, str_pad($i, 4, '0', 0)); $redis->get(“key:$i”); } $server1 = $redis->getClientFor('first')->info(); $server2 = $redis->getClientFor('second')->info(); printf(“Server '%s' has %d keys while server '%s' has %d keys. ”, 'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
redis 队列解决秒杀解决超卖:
思路:利用lpop移除并返回移除的值,失败返回false;当redis缓存中的商品数量不足则跳过减库存的步骤
<?php require_once './Db.php'; //记录哈希值守护进程 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $res=$redis->lpop('goods_store');//移除并返回列表 if($res){ $pdo=Db::instance('127.0.0.1', 'root', 'root', 'test', 'utf8'); $id=mt_rand(20,30); //$where['id'] =['>',1]; $where['id'] =$id; $res=$pdo->table('good')->where($where)->setDec('goods_store',1); var_dump($res); }else{ echo '秒杀失败'; } 入队页面(有多少商品入多少次队): <?php $redis=new Redis(); $redis->connect('127.0.0.1',6379); $store=10; for($i=0;$i<$store;$i++){ $redis->lpush('goods_store',1); } var_dump($redis->lRange('goods_store',0,-1));
connect($host,$port,$timeout,$reserved,$retry_interval,$read_timeout); 链接redis 返回boolean host: string. can be a host, or the path to a unix domain socket port: int, optional timeout: float, value in seconds (optional, default is 0 meaning unlimited) reserved: should be NULL if retry_interval is specified retry_interval: int, 连接断开后每隔多长时间后重试单位毫秒 read_timeout: float, value in seconds (optional, default is 0 meaning unlimited)