redis大全

文章目录

一 redis与memcache异同

  1. redis 官网](http://www.redis.net.cn)
  2. redis可以用来做存储(storge), 而memccached是用来做缓存(cache) 这个特点主要因为其有”持久化”的功能.
  3. 存储的数据有”结构”,对于memcached来说,存储的数据,只有1种类型–”字符串”, 而redis则可以存储字符串,链表,哈希结构,集合,有序集合.

二 redis 安装八步曲

  1. 官方下载最新的稳定(stable)版
  2. 解压源码并进入目录,直接执行 make 命令(注:易发生时间戳错误,主要是因为 源码是官方configure过的,但官方configure时,生成的文件有时间戳信息,Make只能发生在configure之后,如果你的虚拟机的时间不对,比如说是2012年解决: date -s ‘yyyy-mm-dd hh:mm:ss’ 重写时间,再 clock -w 写入cmos)
  3. 可选步骤: make test 测试编译情况(可能出现: need tcl >8.4这种情况, yum install tcl)
  4. 安装到指定的目录,比如 /usr/local/redis ,make PREFIX=/usr/local/redis install(注: PREFIX要大写)
  5. make install之后,得到如下几个文件
    1. redis-benchmark 性能测试工具
    2. redis-check-aof 日志文件检测工(比如断电造成日志损坏,可以检测并修复)
    3. redis-check-dump 快照文件检测工具,效果类上
    4. redis-cli 客户端
    5. redis-server 服务端
  6. 复制配置文件 cp /path/redis.conf /usr/local/redis
  7. 启动与连接 /path/to/redis/bin/redis-server ./path/to/conf-file (redis可单机多实例操作,可指定端口号启动多个redis Server)
    例:[root@localhost redis]# ./bin/redis-server ./redis.conf
  8. 让redis以后台进程的形式运行,编辑conf配置文件,修改如下内容;
    daemonize yes

三 Redis key的常规操作命令

1. 添加

2. 删除

del key1 key2 … Keyn 删除一个或多个key值,返回值: 不存在的key忽略掉,返回真正删除的key的数量

3. 修改

rename key newkey 给key赋一个新的key名,果newkey已存在则newkey的原值被覆盖
renamenx key newkey 把key改名为newkey,返回: 发生修改返回1,未发生修改返回0(注: nx–> not exists, 即, newkey不存在时,作改名动作)

4. 查询

keys patter 取出匹配的所有key值,(但是会阻碍当前线程)
通配任意多个字符 patter 包含三个通配符 *, ? , []

  • *: 通配任意多个字符
  • ?: 通配单个字符
  • []: 通配括号内的某1个字符

randomkey 返回随机key

5. 移动database (注意: 一个redis进程,默认打开16个数据库,从0到15编号,如果想打开更多数据库,可以从配置文件修改)

move key db 把key从当前库移动到db库

6. 其他

exists key 判断key是否存在,返回1/0
type key 返回key存储的值的类型(string、link、set、order set、 hash)
ttl key 查询key的生命周期,返回: 秒数(注:对于不存在的key或已过期的key/不过期的key,都返回-1,Redis2.8中,对于不存在的key,返回-2)
expire key 整型值 设置key的生命周期,以秒为单位
pexpire key 毫秒数 设置生命周期
pttl key 以毫秒返回生命周期

四 String类型的操作

  1. set key value [ex|px value] [nx|xx value] 如: set a 1 ex 10 , 10秒有效
    eg:Set a 1 px 9000 , 9秒有效
    注: 如果ex=>秒数,px=>毫秒数 同时写,以后面的有效期为准
    如 set a 1 ex 100 px 9000, 实际有效期是9000毫秒
    nx: 表示key不存在时,执行操作
    xx: 表示key存在时,执行操作
  2. mset [key value]... 一次性设置多个键值
  3. get key 获取key的值
  4. mget key1 [key2...] 获取多个key的值
  5. setrange key offset value 把字符串的offset偏移字节,改成value (如果偏移量>字符长度, 该字符自动补0x00)
  6. append key value 把value追加到key的原值上
  7. getrange key start stop 是获取字符串中 [start, stop]范围的值 (对于字符串的下标,左数从0开始,右数从-1开始,start>=length, 则返回空字符串,stop>=length,则截取至字符结尾,如果start 所处位置在stop右边则返回空字符串)
  8. getset key newvalue 获取并返回旧值,设置新值
  9. incr key 指定的key的值加1,并返回加1后的值(不存在的key当成0,再incr操作,范围为64有符号)
  10. incrby key number
  11. incrbyfloat key floatnumber
  12. decr key
  13. decrby key number
  14. getbit key offset 获取值的二进制表示,对应位上的值(从左,从0编号)
  15. setbit key offset value 设置offset对应二进制位上的值,返回该位上的旧值(如果offset过大,则会在中间填充0, offset最大2^32-1,可推出最大的的字符串为512M)
  16. bitop operation destkey key1 [key2 ...] 对key1,key2…keyN作operation,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR (对于NOT操作, key不能多个)

五 list 链表结构

  1. lpush key value 把值插入到链接头部
  2. rpop key 返回并删除链表尾元素
  3. lrange key start stop 返回链表中[start ,stop]中的元素, 左数从0开始,右数从-1开始
  4. lrem key count value 从key链表中删除 value值(删除count的绝对值个value后结束,Count>0 从表头删除,Count<0 从表尾删除)
  5. ltrim key start stop 剪切key对应的链接,切[start,stop]一段,并把该段重新赋给key
  6. lindex key index 返回index索引上的值
  7. llen key 计算链接表的元素个数
  8. linsert key after|before search value 在key链表中寻找’search’,并在search值之前|之后,.插入value ( 一旦找到一个search后,命令就结束了,因此不会插入多个value)
  9. rpoplpush source dest 把source的尾部拿出,放在dest的头部,并返回 该单元值 [ task + bak 双链表完成安全队列]
  10. brpop ,blpop key timeout 等待弹出key的尾/头元素, Timeout为等待超时时间,如果timeout为0,则一直等待 [长轮询Ajax,在线聊天时,能够用到]
  11. Setbit [场景: 1亿个用户, 每个用户 登陆/做任意操作 ,记为 今天活跃,否则记为不活跃,每周评出: 有奖活跃用户: 连续7天活动每月评,等等]

六 set 集合相关命令(集合的性质: 唯一性,无序性,确定性)

  1. sadd key value1 value2 往集合key中增加元素
  2. srem value1 value2 删除集合中集为 value1 value2的元素,返回忽略不存在的元素后,真正删除掉的元素的个数
  3. spop key 返回并删除集合中key中1个随机元素
  4. srandmember key 返回集合key中,随机的1个元素.
  5. sismember key value 判断value是否在key集合中 是返回1,否返回0
  6. smembers key 返回集中中所有的元素
  7. scard key 返回集合中元素的个数
  8. smove source dest value 把source中的value删除,并添加到dest集合中
  9. sinter key1 key2 key3 求出key1 key2 key3 三个集合中的交集,并返回
  10. sinterstore dest key1 key2 key3 求出key1 key2 key3 三个集合中的交集,并赋给dest
  11. suion key1 key2.. Keyn 求出key1 key2 keyn的并集,并返回
  12. sdiff key1 key2 key3 求出key1与key2 key3的差集

七 order set 有序集合

  1. zadd key score1 value1 score2 value2 .. 添加元素,并根据score进行排序
  2. zrem key value1 value2 .. 删除集合中的元素
  3. zremrangebyscore key min max 按照socre来删除元素,删除score在[min,max]之间的
  4. zremrangebyrank key start end 按排名删除元素,删除名次在[start,end]之间的
  5. zrank key member 查询member的排名(升续 0名开始)
  6. zrevrank key memeber 查询 member的排名(降续 0名开始)
  7. ZRANGE key start stop [WITHSCORES] 把集合排序后,返回名次[start,stop]的元素,默认是升续排列,Withscores 是把score也打印出来
  8. zrevrange key start stop 把集合降序排列,取名字[start,stop]之间的元素
  9. zrangebyscore key min max [withscores] limit offset N 集合(升续)排序后,取score在[min,max]内的元素,并跳过 offset个, 取出N个
  10. zcard key 返回元素个数
  11. zcount key min max 返回[min,max] 区间内元素的数量
  12. zinterstore destination numkeys key1 [key2 ...][WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] 求key1,key2的交集,key1,key2的权重分别是 weight1,weight2 聚合方法用: sum |min|max 聚合的结果,保存在dest集合内

八 Hash 哈希数据类型相关命令

  1. hset key field value 把key中 filed域的值设为value(如果没有field域,直接添加,如果有,则覆盖原field域的值)
  2. hmset key field1 value1 [field2 value2]... 设置field1->N 个域, 对应的值是value1->N(对应PHP理解为 $key = array(file1=>value1, field2=>value2 …fieldN=>valueN))
  3. hget key field 返回key中field域的值
  4. hmget key field1 field2 fieldN 返回key中field1 field2 fieldN域的值
  5. hgetall key 返回key中,所有域与其值
  6. hdel key field 删除key中 field域
  7. hlen key 返回key中元素的数量
  8. hexists key field 判断key中有没有field域
  9. hinrby key field value 是把key中的field域的值增长整型值value
  10. hinrby float key field value 是把key中的field域的值增长浮点值value
  11. hkeys key 返回key中所有的field
  12. kvals key 返回key中所有的value

九 Redis 中的事务(实质是把操作放到队列中,提交时再执行)

1. Redis与 mysql事务的对比

类型 mysql redis
开启 start transaction muitl
语句 普通sql 普通命令
失败 rollback 回滚 discard 取消
成功 commit exec
  1. rollback与discard 的区别
  2. 如果已经成功执行了2条语句, 第3条语句出错.Rollback后,前2条的语句影响消失.Discard只是结束本次事务,前2条语句造成的影响仍然还在
  3. 在mutil后面的语句中, 语句出错可能有2种情况:语法就有问题,
    这种,exec时,报错, 所有语句得不到执行;语法本身没错,但适用对象有问题. 比如 zadd 操作list对象 Exec之后,会执行正确的语句,并跳过有不适当的语句.(如果zadd操作list这种事怎么避免? 这一点,由程序员负责)
  4. Redis的事务中,启用的是乐观锁,只负责监测key没有被改动.
    watch key1 key2 ... keyN 监听key1 key2…keyN有没有变化,如果有变, 则事务取消,起到监控事务的功能
    unwatch 取消所有watch监听

十 消息订阅

1. 使用办法:

订阅端: Subscribe 频道名称 (频道名称可用正则表达式)
发布端: publish 频道名称 发布内容

十一 Redis持久化配置

Redis的持久化有2种方式 (快照、日志)

1. RDB和AOF两种持久化机制的介绍

  1. RDB持久化机制,对redis中的数据执行周期性的持久化
  2. AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集
  3. 如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制
  4. 通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云,云服务
  5. 如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务
  6. 如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整
  7. 做冷备,RDB生成多个文件,每个文件都代表了某一个时刻的完整的数据快照,AOF也可以做冷备,只有一个文件,但是你可以,每隔一定时间,去copy一份这个文件出来;RDB做冷备,优势在哪儿呢?由redis去控制固定时长生成快照文件的事情,比较方便,提供数据恢复的时候,速度比AOF快; AOF做冷备,还需要自己写一些脚本去做这个事情,各种定时
  8. RDB,每次写,都是直接写redis内存,只是在一定的时候,才会将数据写入磁盘中;AOF,每次都是要写文件的,虽然可以快速写入os cache中,但是还是有一定的时间开销的,速度肯定比RDB略慢一些
  9. AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,来恢复出来内存中的所有数据的;RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可
  10. 综合(g,h,i)三项 rdb适合做冷备

2. Rdb 的配置:(快照)

save 900 1      // 900内,有1条写入,则产生快照 
save 300 1000   // 如果300秒内有1000次写入,则产生快照
save 60 10000  // 如果60秒内有10000次写入,则产生快照
(这3个选项都屏蔽,则rdb禁用)
stop-writes-on-bgsave-error yes  // 后台备份进程出错时,主进程停不停止写入?
rdbcompression yes    // 导出的rdb文件是否压缩
Rdbchecksum   yes //  导入rbd恢复时数据时,要不要检验rdb的完整性
dbfilename dump.rdb  //导出来的rdb文件名
dir ./  //rdb的放置路径

3. Rdb的优缺点:

  1. 优点:
    • RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据
    • DB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
    • 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
  2. 缺点:
    • 如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。这个问题,也是rdb最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多
    • RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。一般不要让RDB的间隔太长,否则每次生成的RDB文件太大了,对redis本身的性能可能会有影响的

4. AOF 的配置:(日志)

   appendonly no # 是否打开 aof日志功能
   appendfsync always  # 每1个命令,都立即同步到aof. 安全,速度慢
   appendfsync everysec # 折衷方案,每秒写1次
   appendfsync no      # 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof. 同步频率低,速度快,
   no-appendfsync-on-rewrite  yes: # 正在导出rdb快照的过程中,要不要停止同步aof
   auto-aof-rewrite-percentage 100 #aof文件大小比起上次重写时的大小,增长率100%时,重写
   auto-aof-rewrite-min-size 64mb #aof文件,至少超过64M时,重写

5. AOF 的优缺点

  1. 优点
    • AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,强制将os cache(操作系统缓存)刷入磁盘文件中,最多丢失1秒钟的数据。每隔1秒,就执行一次fsync操作,保证os cache中的数据写入磁盘中,redis进程挂了,最多丢掉1秒钟的数据
    • AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
    • AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
    • AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
  2. 缺点:
    • 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
    • AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的,如果你要保证一条数据都不丢,也是可以的,AOF的fsync设置成没写入一条数据,fsync一次,那就完蛋了,redis的QPS大降
    • 以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。
    • 唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢,还有做冷备,定期的备份,不太方便,可能要自己手写复杂的脚本去做,做冷备不太合适

6. AOF rewrite的原理剖析(分自动/手动重写)

7. redis限定了内存的使用大小,

8. redis的LUR,惰性清除法将不常用的数据从内存中删除,腾出一部分空间,

9. redis开启新的子进程将内存中的数据输出到aof文件中,将内存留给新的缓存数据,并可以对aof文件进行重写,缩小aof文件的大小

10. RDB和AOF到底该如何选择

  1. 不要仅仅使用RDB,因为那样会导致你丢失很多数据
  2. 也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
  3. 综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

11. 注意事项:

  1. 在dump rdb过程中,aof如果停止同步,会不会丢失? 不会,所有的操作缓存在内存的队列里, dump完成后,统一操作.
  2. aof重写是指什么? aof重写是指把内存中的数据,逆化成命令,写入到.aof日志里以解决 aof日志过大的问题.
  3. 如果rdb文件,和aof文件都存在,优先用谁来恢复数据? aof
  4. 2种是否可以同时用? 可以,而且推荐这么做
  5. 恢复时rdb和aof哪个恢复的快? rdb快,因为其是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行
  6. 如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整

十二 redis 服务器端命令

1. 命令

time 显示服务器时间 , 时间戳(秒), 微秒数
select dbname  切换数据库 
dbsize  当前数据库的key的数量
BGREWRITEAOF  后台进程重写AOF
BGSAVE  后台保存rdb快照
SAVE  保存rdb快照
LASTSAVE  上次保存时间
Slaveof master-Host port   把当前实例设为master的slave
Flushall  清空所有库所有键 
Flushdb  清空当前库所有键
Showdown [save/nosave]  
Slowlog   显示慢查询
nfo [Replication/CPU/Memory..]  查看redis服务器的信息   
Config get  获取配置项
Config set  设置配置项 

2. 注意事项

  1. 如果不小心运行了flushall? 立即 shutdown nosave ,关闭服务器,然后 手工编辑aof文件, 去掉文件中的 “flushall ”相关行, 然后开启服务器,就可以导入回原来数据.(如果,flushall之后,系统恰好bgrewriteaof了,那么aof就清空了,数据丢失.)
  2. 多慢才叫慢? 由slowlog-log-slower-than 10000 ,来指定,(单位是微秒)
  3. 服务器储存多少条慢查询的记录? 由 slowlog-max-len 128 ,来做限制

十三 运维时需要注意的参数

1. 内存 Memory

used_memory:859192 数据结构的空间
used_memory_rss:7634944 实占空间
mem_fragmentation_ratio:8.89 前2者的比例,1.N为佳,如果此值过大,说明redis的内存的碎片化严重,可以导出再导入一次.

2. 主从复制 Replication

role:slave
master_host:192.168.1.128
master_port:6379
master_link_status:up
  1. 运行时更改master-slave
    修改一台slave(设为A)为new master
    1. 命令该服务不做其他redis服务的slave
      命令: slaveof no one
    2. 修改其readonly为yes
  2. 其他的slave再指向new master A
    1. 命令该服务为new master A的slave
      命令格式: slaveof IP port

3. 持久化 Persistence

rdb_changes_since_last_save:0
rdb_last_save_time:1375224063

4. fork耗时 Status

latest_fork_usec:936 上次导出rdb快照,持久化花费微秒 (如果某实例有10G内容,导出需要2分钟,每分钟写入10000次,导致不断的rdb导出,磁盘始处于高IO状态.)

5. 慢日志

config get/set slowlog-log-slower-than
CONFIG get/SET slowlog-max-len 
slowlog get N 获取慢日志

十四 监控工具 sentinel

1. 原理

Sentinel不断与master通信,获取master的slave信息.监听master与slave的状态,如果某slave失效,直接通知master去除该slave.如果master失效,是按照slave优先级(可配置), 选取1个slave做 new master,把其他slave–> new master

2. Sentinel选项配置

port 26379 # 端口
sentinel monitor mymaster 127.0.0.1 6379 2 #给主机起的名字(不重即可), 当2个sentinel实例都认为master失效时,正式失效 
sentinel down-after-milliseconds mymaster 30000 //多少毫秒后连接不到master认为断开
sentinel can-failover mymaster yes #是否允许sentinel修改slave->master.如为no,则只能监控,无权修改
sentinel parallel-syncs mymaster 1 #一次性修改几个slave指向新的new master.
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh #在重新配置new master,new slave过程,可以触发的脚本

3. 问题:

sentinel与master通信,如果某次因为master IO操作频繁,导致超时,此时,认为master失效,很武断.
解决: sentnel允许多个实例看守1个master, 当N台(N可设置)sentinel都认为master失效,才正式失效.

十五 Redis key 设计技巧

  1. 把表名转换为key前缀 如, tag:

  2. 第2段放置用于区分区key的字段–对应mysql中的主键的列名,如userid

  3. 第3段放置主键值,如2,3,4…, a , b ,c

  4. 第4段,写要存储的列名

  5. 示例:用户表 -> key-value 存储

    userid username passwd email
    9 lili 111111 111@qq.com

    set user:userid:9:username lisi
    set user:userid:9:password 111111
    set user:userid:9:email lisi@163.com
    keys user:userid:9*

  6. 注意事项:
    在关系型数据中,除主键外,还有可能其他列也步骤查询,如上表中, username 也是极频繁查询的,往往这种列也是加了索引的.

转换到k-v数据中,则也要相应的生成一条按照该列为主的key-value

Set user:username:lisi:uid 9
这样,我们可以根据username:lisi:uid ,查出userid=9, 再查user:9:password/email …完成了根据用户名来查询用户信息

十六 php-redis扩展编译

  1. 到pecl.php.net 搜索redis
  2. 下载stable版(稳定版)扩展
  3. 解压
  4. 执行/php/path/bin/phpize (作用是检测PHP的内核版本,并为扩展生成相应的编译配置)
  5. configure --with-php-config=/php/path/bin/php-config
  6. make && make install

十七 redis插件的使用

// get instance
$redis = new Redis();
// connect to redis server
$redis->open('localhost',6380);
$redis->set('user:userid:9:username','wangwu');
var_dump($redis->get('user:userid:9:username'));

十八 redis 与关系型数据库的适合场景(书签系统)

1. mysql:

create table book (bookid int,title char(20)
)engine myisam charset utf8;

insert into book values (5 , 'PHP圣经'),(6 , 'ruby实战'),(7 , 'mysql运维'),(8, 'ruby服务端编程');

create table tags (tid int,bookid int,content char(20)
)engine myisam charset utf8;

insert into tags values (10 , 5 , 'PHP'),(11 , 5 , 'WEB'),(12 , 6 , 'WEB'),(13 , 6 , 'ruby'),(14 , 7 , 'database'),(15 , 8 , 'ruby'),(16 , 8 , 'server');

#既有web标签,又有PHP,同时还标签的书,要用连接查询
select * from tags inner join tags as t on tags.bookid=t.bookid where tags.content='PHP' and t.content='WEB';

2. key->value

#用kv 来存储
set book:5:title 'PHP圣经'
set book:6:title 'ruby实战'
set book:7:title 'mysql运难'
set book:8:title ‘ruby server’

sadd tag:PHP 5
sadd tag:WEB 5 6
sadd tag:database 7
sadd tag:ruby 6 8
sadd tag:SERVER 8

查: 既有PHP,又有WEB的书
Sinter tag:PHP tag:WEB  #查集合的交集

查: 有PHP或有WEB标签的书
Sunin tag:PHP tag:WEB

查:含有ruby,不含WEB标签的书
Sdiff tag:ruby tag:WEB #求差集

十九 微博项目的key设计

1. 表设计

A全局相关表

表名 global
列名 操作 备注
Global:userid incr 产生全局的userid
Global:postid incr 产生全局的postid

b用户相关的key(表)

表名 user
Userid Username Password Authsecret
3 Test3 1111 #U*Q(%_

===》key-value

Key前缀 user
User:Userid:* User:userid:*Username User:userid:*Password User:userid:*:Authsecret
User:userid:3 User:userid:3:Test3 User:userid:3:1111111 User:userid:3:#U*Q(%_

c微博相关的表设计

表名 post
Postid Userid Username Time Content
4 2 Lisi 1370987654f 测试内容

===》 key-value

Key前缀 post
Post:Postid:* Post:postid:*Userid Post:postid:*:Username Post:postid:*:Time Post:postid:*:Content
4 2 Lisi 1370987654f 测试内容

d、关注表(set集合)
Following:$userid

e、粉丝表(set集合)
Follower:$userid

f、推送表revicepost
Recivepost:$userid

g、拉取表(由推送主动改成拉取)
Pull:$userid:

2. 答疑:

  1. 上次我拉取了 A->5,67,三条微博, 下次刷新home.php, 从>7的微博开始拉取?拉取时,设定一个lastpull时间点, 下次拉取时,取>lastpull的微博
  2. 有很多关注人,如何取? 循环自己的关注列表,逐个取他们的新微博
  3. 取出来之后放在哪儿? pull:$userid的链接里
  4. 如果个人中心,只有前1000条? ltrim,只取前1000条
  5. 如果我关注 A,B两人, 从2人中,各取3条最新信息,这3+3条信息, 从时间上,是交错的, 如何按时间排序?我们发布时, 是发布的hash结构, 不能按时间来排序.
  6. 解决: 同步时,取微博后,记录本次取的微博的最大id,下次同步时,只取比最大id更大的微博

3. 结果分析

Time taken for tests:   32.690 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Non-2xx responses:      20000
Total transferred:      13520000 bytes
Total POSTed:           5340000
HTML transferred:       9300000 bytes
Requests per second:    611.80 [#/sec] (mean)
Time per request:       81.726 [ms] (mean)
Time per request:       1.635 [ms] (mean, across all concurrent requests)
Transfer rate:          403.88 [Kbytes/sec] received
                        159.52 kb/s sent
                        563.41 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.9      0      19
Processing:    14   82   8.4     81     153
Waiting:        4   82   8.4     80     153
Total:         20   82   8.2     81     153

Percentage of the requests served within a certain time (ms)
  50%     81
  66%     84
  75%     86
  80%     88
  90%     93
  95%     96
  98%    100
  99%    103
 100%    153 (longest request)

4. 测试结果:

  1. 50个并发, 20000次请求, 虚拟下,未做特殊优化,每次请求redis写操作6次.30+秒左右完成.
  2. 平均每秒发布700条微博, 4000次redis写入.后台定时任务 回归冷数据入 mysql

二十 附录 redis配置文件详解

==基本配置
daemonize no 是否以后台进程启动
databases 16 创建database的数量(默认选中的是database 0)

save 900 1    #刷新快照到硬盘中,必须满足两者要求才会触发,即900秒之后至少1个关键字发生变化。
save 300 10  #必须是300秒之后至少10个关键字发生变化。
save 60 10000 #必须是60秒之后至少10000个关键字发生变化。
stop-writes-on-bgsave-error yes    #后台存储错误停止写。
rdbcompression yes    #使用LZF压缩rdb文件。
rdbchecksum yes    #存储和加载rdb文件时校验。
dbfilename dump.rdb    #设置rdb文件名。
dir ./    #设置工作目录,rdb文件会写入该目录。

==主从配置
slaveof <masterip> <masterport> 设为某台机器的从服务器
masterauth <master-password>   连接主服务器的密码
slave-serve-stale-data yes  # 当主从断开或正在复制中,从服务器是否应答
slave-read-only yes #从服务器只读
repl-ping-slave-period 10 #从ping主的时间间隔,秒为单位
repl-timeout 60 #主从超时时间(超时认为断线了),要比period大
slave-priority 100    #如果master不能再正常工作,那么会在多个slave中,选择优先值最小的一个slave提升为master,优先值为0表示不能提升为master。

repl-disable-tcp-nodelay no #主端是否合并数据,大块发送给slave
slave-priority 100 从服务器的优先级,当主服挂了,会自动挑slave priority最小的为主服

===安全
requirepass foobared # 需要密码
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 #如果公共环境,可以重命名部分敏感命令 如config

===限制
maxclients 10000 #最大连接数
maxmemory <bytes> #最大使用内存

maxmemory-policy volatile-lru #内存到极限后的处理
volatile-lru -> LRU算法删除过期key
allkeys-lru -> LRU算法删除key(不区分过不过期)
volatile-random -> 随机删除过期key
allkeys-random -> 随机删除key(不区分过不过期)
volatile-ttl -> 删除快过期的key
noeviction -> 不删除,返回错误信息

#解释 LRU ttl都是近似算法,可以选N个,再比较最适宜T踢出的数据
maxmemory-samples 3

====日志模式
appendonly no #是否仅要日志
appendfsync no # 系统缓冲,统一写,速度快
appendfsync always # 系统不缓冲,直接写,慢,丢失数据少
appendfsync everysec #折衷,每秒写1次

no-appendfsync-on-rewrite no #为yes,则其他线程的数据放内存里,合并写入(速度快,容易丢失的多)
auto-AOF-rewrite-percentage 100 当前aof文件是上次重写是大N%时重写
auto-AOF-rewrite-min-size 64mb aof重写至少要达到的大小

====慢查询
slowlog-log-slower-than 10000 #记录响应时间大于10000微秒的慢查询
slowlog-max-len 128   # 最多记录128条

====服务端命令
time  返回时间戳+微秒
dbsize 返回key的数量
bgrewriteaof 重写aof (会造成线程阻塞)
bgsave 后台开启子进程dump数据
save 阻塞进程dump数据
lastsave 

slaveof host port 做host port的从服务器(数据清空,复制新主内容)
slaveof no one 变成主服务器(原数据不丢失,一般用于主服失败后)

flushdb  清空当前数据库的所有数据
flushall 清空所有数据库的所有数据(误用了怎么办?)

shutdown [save/nosave] 关闭服务器,保存数据,修改AOF(如果设置)

slowlog get 获取慢查询日志
slowlog len 获取慢查询日志条数
slowlog reset 清空慢查询

info []

config get 选项(支持*通配)
config set 选项 值
config rewrite 把值写到配置文件
config restart 更新info命令的信息

debug object key #调试选项,看一个key的情况
debug segfault #模拟段错误,让服务器崩溃
object key (refcount|encoding|idletime)
monitor #打开控制台,观察命令(调试用)
client list #列出所有连接
client kill #杀死某个连接  CLIENT KILL 127.0.0.1:43501
client getname #获取连接的名称 默认nil
client setname "名称" #设置连接名称,便于调试

====连接命令===
auth 密码 #密码登陆(如果有密码)
ping #测试服务器是否可用
echo "some content" #测试服务器是否正常交互
select 0/1/2... #选择数据库
quit #退出连接
posted @ 2019-05-05 01:42  南山道士  阅读(66)  评论(0编辑  收藏  举报