Redis

redis 介绍

一个把数据存储在内存中的高速缓存

可以用来存储字符串,哈希结构,链表,因此常用来提供数据结构服务

redis 优势

  1. Key-Value内存数据库

  2. 读写性能强悍

  3. 支持丰富的数据结构:List,Hash,Map, Set, Sorted set (排序的集合),消息订阅与发布(pub/sub)

  4. 可持久化存储 (memchaced不可持久化),通过一种机制把存储在内存上的数据,也存储在硬盘中.

优点:高速安全(可持续化)丰富的数据结构
缺点:消耗内存(内存使用固定),效率较低(持久化以磁盘存储)

redis 和 memcached区别

  • redis可以用来做存储(storge),memcached用来做缓存(cache

  • 存储的数据有“结构”,对于memcacehd来说,存储的数据,只有一种类型:字符串,而reids则可以存字符串,链表,hash结构,集合,有序集合。

都是内存高速缓存数据库,但是redis比memcached支持更多数据类型,且redis可持久化.

// memcached redis
类型 内存数据库 内存数据库
数据类型 在定义value是就要固定数据类型 不需要,有字符串,链表,集合和有序集合
虚拟内存 不支持 支持
过期策略 支持 支持
分布式 magent master-slave, 一主一从,一主多从
存储数据安全 不支持 使用 save存储到dump.rdb中
灾难恢复 不支持 append only file (aof)用户数据恢复

文件目录

redis-benchmark  reids性能测试工具
redis-check-aof  检查aof日志工具
redis-check-dump 查看rdb日志工具
redis-cli 连接用的客户端
redis-server  redis服务进程

redis 使用范围

端口

redis端口:6379

redis使用范围

  1. 计数器. incr count

  2. SNS社区服务

  3. 内存高速缓存

  4. 利用redis的集合及数据过期策略,做一个防攻系统

  5. 利用消息订阅与发布功能 可以做聊天系统

  6. 利用list可以做消息队列服务

List把一串数据连在一起。

编译安装

git clone https://github.com/antirez/redis.git
cd redis
make

修改redis配置文件

vim redis.conf
daemonize yes // 控制前后台运行

启动redis

./redis-server reids.conf
./reids-cli

文件下的可执行文件

redis-server: redis服务器的daemon启动程序
redis-cli: redi命令行操作工具
redis-benchmark: redis性能检测工具,测试redis在当前系统及配置下的读写性能
redis-stat: redis 状态检测工具,可以检测reids当前状态参数及延迟状况

初步使用

set key value // 设置
get key // 获取
incr key // 计数
key * // 获取全部

redis持久化的两种方式

  • 将数据按照规定的频率保存到硬盘上 原子操作(速度快)

    尽量不要使用保存数据文件方式,会把以前的数据从新保存一遍 (mv)
  • 将对数据有修改的操作的命令 保存到文件中, 文件后缀为.aof

appendonly on // 开启操作命令保存到文件中的方式
appendsync everysec // 保存的频率
appendfilename appendonly.aof // 保存文件的名字

通用key操作

redis命令手册

key

keys pattern // 查询相应的key

允许模糊查询key
有3个通配符*,?,[]
*任意通配符
?单个通配符

randomkey // 获取随机的key
type key  // 判断key值的类型
exists key // 判断是否存在key

del key // 删除key
rename oldKey newKey // 修改key名字 (如果原有已经存在key,则覆盖)
renamenx oldKey newKey // 修改已经存在的key值,失败

keys * // 查看所有key的值
del key // 删除指定的key
exists key  // 判断指定key 是否存在,不存在返回0,存在返回1
ttl key // 剩余时间 (秒) key存在,永久有效返回-1,不存在返回-2,其它返回剩余时间
pexpire key time // 设置过期时间 (毫秒)
expire key time // 设置过期时间(秒)
persist key // 设置永久有效

基础类型

String

set key value [ex 生命周期的秒数]/[px 毫秒数] [nx|xx]
set site sf.com ex 10 

expx不要同时存在,同时存在报错
ng表示key不存在时,执行操作
xx表示key存在时,执行操作

flusdb // 冲刷db

mset key value key value // 一次性设置多个键值
mget key1 key2 key3 // 一次性获取多个值

setrange key offset value // 把字符串的offset偏移字节,改成value

如果偏移量>字符串长度该字符自动补\x00

appned key value // 把value追加到key的原值上
getrange key start stop // 获取字符串[start, stop]范围的值 // 对于字符串下标左数从0开始,右数从-1开始
getset key newValue  // 获取旧值设置新值 // 返回旧值

strlen key // 字符串长度
get key // 获取字符串
set key value // 设置字符串
mset key value key value // 同时设置多个key值
mget key key // 同时获取多个key值

incr key // 存储值加一
decr key // 存储值减一
incrby key number // 存储值加number
decrby key number // 存储值减number
incrbyfloat key number // 存储值加number(number为浮点数)
decrbyfloat key number // 存储值减number(number为浮点数)

配置文件

daemonize yes // 控制前后台运行
bind ip // 连接的ip
timeout 0 // 超过多长时间没返回就超时
loglevel notice // 日志级别

save 900 1  // 900秒 有1次数据操作,就同步到硬盘中去
save 300 10 // 300秒 之内有10次操作,就同步到硬盘中去
save 60 10000 // 60秒之内有10000次操作,就同步到硬盘中去

dbfilename dump.rdb // 硬盘存储的数据

slaveof   // 主从服务器
databases 16 // 可以指定存储位置,默认使用的是`0`

使用1号数据库
Redis_第1张图片

move key 数据库编号 // 移动数据到其它库中
move key 1 

数据结构

String, List(链表),Set,HashSortedSet(有序集合),Pub/Sub(发布/订阅)

List

List多个元素链在一起的一串东西.

特点:在任何位置增加或删除元素都很快
缺点:不支持随机存取

是每个元素都是string类型的双向链表
头指针 --> data --> 尾指针

基本组成:空间,头指针,指向下一个元素的指针。

lpush key value1 value2 // 从left写入链表 
rpush  key value1 value2 // 从right写入链表
lrenge key start top  // 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定 // lrange key 0 -1
lpop key // 移除并返回列表 key 的头元素。
rpop key // 移除并返回right的最后一个单元值
lindex key index // 获取指定index的值
llen key // 获取List的长度
ltrim key start stop // 从List中截取指定的开始和结束,包括开始和结束字符
lrem key count value // 从List链表中删除 // lrem answer 1 b // 通过值来删除,指定count个数

Redis_第2张图片

linsert key after|before search value // 沿着List找值,然后在值之前或之后插入新值. // linsert num after b hh // 没查询到,返回-1,插入失败。

lpoprpush source dest // 把srouce的尾部拿出来,放在dest的头部

lpoprpush是一个原子性操作,如果自己实现通过lpoprpush来操作,中间过程中如果有其它操作,就破坏原子性

场景:task + bak 双链表完成安全队列

业务逻辑:
1:rpoplpush task job
2: 接收返回值,并做业务处理
3: 如果成功,rpop job清除任务,彻底删除;如果不成功,下次从bak表里取任务,继续执行

Redis_第3张图片

brpop key timeout // 等待弹出key的尾元素
blpop key timeout // 等待弹出key的头元素

timeout 为等待超时时间,如果timeout为0,则一直等待。

场景: 长轮询Ajax,在线聊天

位图法统计活跃用户

1:记录用户登陆:
每天按日期生成一个位图,用户登陆后,把user_id位上的bit位置1

2: 把1周的位图 and 计算,
位上位1的,即使连续登陆的用户

setbit mon 100000000 0
setbit mon 3 1
setbit mon 5 1
setbit mon 7 1
setbit thur 100000000 0
setbit thur 3 1
setbit thur 5 1
setbit thur 8 1
setbit wen 100000000 0
setbit wen 3 1
setbit wen 4 1
setbit wen 6 1
bitop and res mon thur wen

优点:

  1. 节约空间,1亿人每天的登陆情况,用1亿bit,约10M的字符就能表示

  2. 计算快,计算方便

Set

特点:

  • 无序性

  • 确定性 (描述是确定的)

  • 唯一性 (Set的值是唯一,不重复,独一无二)

sadd key value1 value2 // 写入集合中
smembers key // 获取集合所有元素
sismember key value // 判断value是否存在key中
srem key // 移除指定key
spop key // 返回并删除集合key的1个随机元素
srendmember key // 返回随机的元素
scard key // 返回集合中的长度

smove srouce dest value // 把srouce中的value删除,并添加到dest集合中
sunion key1 key2 key3... // 集合的并集
sinter key1 key2... // 集合的交集
sdiff key1 key2 // 集合的差集

sinterstoure result key1 key2 kye3  // 把集合中的结果保存起来

SortedSet

Order Set 有序集合
集合本来是无序,既然是有序集合,必然是需要一个排序的因子(排序的一句,使用什么来排序),每个元素都需要一个score

每一个元素都带有一个权重score,加入到有序集合里的所有元素都根据score进行了排序

zadd key score1 value1 score2 value2 // 写入有序集合中
zadd key website 10 sf.gg 9 google.com 
zrange key 0 -1 [withscores] // 取出所有 // 默认升序 // 指定widthsrouces,一并取出指定的srouce
zrangebyscoure key min max [withscores] limit offset N // 取srouce的[min, max]之内的元素,并跳过offset,取出N个 // 指定widthsrouces,一并取出指定的srouce

zrank key member // 查询member在集合中的位置
zrevrank key member // 倒序查看member在集合中的位置

zrem  key value1 value2 // 根据value来删除指定元素
zremrangebyscore key min max  // 根据score来删除指定[min, max]范围的元素
zcard key // 返回元素个数
zcount key min max // 返回[min, max]区间内的元素数量
zinterstore destination numbers key1 key2 [WEIGHTS weight] aggregate [sum|min|max] // key1,key2的交集,权重是weight。聚合方法是sum|min|max, 聚合的结果放入des中

Hash

Hash类似PHP的关联数组.
很多单元不是通过索引,而是通过键来标记.
Hash是一个复合结构,每一个值都是有一个独特的键,指向Hash结构

hset key field value // Hash设置
hget key field // 获取Hash给定的key值
hmset key filed1 value  field2 value  // 哈希表 key 中,一个或多个给定域的值。
hmget key field1 field2 // 返回哈希表 key 中,一个或多个给定域的值。
hgetall key // 返回给定key的所有field
hdel key field // 删除key中field域
hlen key // 返回中的元素数量
hexists key field // 判断key中有没有field域 
hkeys key // 返回key的所有键
hvals key // 返回key的所有值

Redis_第4张图片

事务

一组操作在同一时间执行,其中有一个失败了,可以回滚到原来操作。

redis支持简单的事务
redis的事务中,只负责监测key有没被改动。改动了,拒绝执行所有队列中的命令。

redis与mysql事务的对比:

// mysql redis
开启 start transaction mutil
语句 普通sql 普通命令
失败 rollback 回滚 discard 取消
成功 commit exec

注:rollback与discard的区别
如果已经成功执行了2条语句,第3条语句错误
rollback后,前2条的语句影响消失
discard姿势结束本次事务,前2条语句造成的影响仍然还在

注:在mutil后的语句中,语句出错可能有2中情况
1: 语法就有问题。
这种exec时,报错,所有语句得不到执行
2: 语法本身没错,但使用对象有问题。比如 zadd操作Link对象exec之后,会执行正确的语句,并跳过不适当的语句。

执行过程,把命令放在队列中,exec集中执行,其中一个命令类型不对,前面执行命令成功。
reids是单进程

错误:

Redis_第5张图片

multi
    命令1
    命令2
exec

Redis_第6张图片

在执行事务的时候,把执行命令放入队列里面中.

放入队列中,管道里暂时不执行

multi
incr count
incr count
incr count
exec

Redis_第7张图片

锁应用

redis的事务中,只负责监测key有没被改动。改动了,拒绝执行所有队列中的命令。(自由锁)

watch key1 key2...keyN // 监听key1,key2...keyN有没有变化,如果有(key1,key2...keyN中间任意一个有变,则事务就不干),则事务取消
unwatch  // 取消所有watch监听

Pub/Sub

subscribe channel // 订阅
publish channel message // 发布

rdb快照

rdb快照持久化

持久化:即把数据存储与断点不会丢失的设备中,通常是硬盘。

常见的持久化方式:

  • 主从:通过主从服务器保持和持久化,如mongoDB的replication sets配置

  • 日志:操作生成相关日志,并通过日志来恢复数据,

  • couchDB对于数据内容,不修改,只追加,则文件本身即是日志,不会丢失数据。

reids持久化的方式:

  • rdb

  • aof

rdb的工作原理:

rdb 快照是照内存.
每隔N分钟或N次写操作后,从内存dump数据形成rdb文件,压缩,放在备份目录

redis-server的主进程和rdb导出的子进程,一旦达到触发条件,就调用rdbdump进程。

因为导出的是二进制印象,恢复速度非常快。

rdb快照相关参数:

save 900 1 // 刷新快照到硬盘中,必须满足两者要求才触发,即900秒之后至少1一个关键字发生变化。
save 300 10 // 必须是300秒之后只至少10个关键字发生变化
save 60 10000 // 必须是60秒之后至少10000个关键字发生变化 
// 屏蔽save三个选项,则rdb禁用。找不到导出规则,则永远都不导出

stop-writes-on-bgsave-error yes // 后台导出存储错误了,则停止写入(如果后台保存出错,还一直写入,造成数据不一致)
rdbcompression yes // 使用LZF压缩rdb文件
rdbchecksum yes // 存储和加载rdb文件时校验
dbfilename dump.rdb // 设置rdb文件名
dir ./ // 设置工作目录,rdb文件会写入该目录

reids.conf中的配置项

clipboard.png

从后往前看,时间越来越长,条件越来越松。

rdb的缺陷:

在2个保存点之前,断电,将会丢失1-N分钟的数据。
处于对持久化的更精细要求,redis增添了aof(append only file)方式

现在reids处理持久化数据,一般是rdbaof配合使用。

aof

aof日志持久化

工作原理:
reids-server进程接受命令,把执行的命令通过aof子进程写到文本文件.

appendonly on // 是否打开 aof日志功能

appencfsync always // 每一个命令,都立即同步到aof,安全,速度慢
appendfsync everysec // 每秒写一次,折中方案
appendfsync no 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof。同步频率低,速度快

no-appendfsync-on-rewrite yes // 正在到处rdb快照的过程中,要不要停止同步aof
auto-aof-rewrite-precentage 100 // aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb // aof文件,至少超过64M时,重写。

注:在dump.rdb过程中,aof如果停止同步,会不会丢失?
不会,所有的操作缓存在内存的队列里,dump完成后,统一操作

aof重写时指什么?

aof重写是指把内存中的数据,逆化成命令,写入到aof日志里,以解决aof日志过大的问题。

场景:同一个key,操作100次。

把内存中的key/value逆化成相关的命令
所有的key在内存中有一个具体的状态

如:

set age 0
incr age
incr age
...
incr age

get age // 100

// 逆化成 (最终结果,最终状态)
set age 100

aof重写的条件

auto-aof-rewrite-percentage 100 aof文件大小比起上次重写时的大小,增长率100%时,重写 // 如果只有这个条件,前期aof文件为0重写很频繁,加后面一个条件制约(需要达到64mb)
auto-aof-rewrite-min-size 64mb 

命令重写:

bgrewriteaof

如果rdb文件和aof文件都存在,优先用谁来恢复数据?

aof

2种可以同时使用么?

可以,reids推荐这种用法

恢复时,rdb和aof哪个恢复快

rdb快,因为其是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行。

主从复制

reids集群。

集群的作用:

  • 主从备份 防止主机宕机

  • 读写分离,分担maste的任务

  • 任务分离,如从服务器分别备份工作与计算工作

  • master宕机后,可以直接切换到slave1

集群方式:

  • 星型

  • 直线型

Redis_第8张图片

主从通信过程

master和slave之前如何达到同步

Redis_第9张图片

主从配置

master配置:
1: 关闭rdb快照(备份工作交给slave)
2: 可以开启aof

slaveof localhost 6379

slave配置:
1: 声明slave-of
2: 配置密码[如果master有密码]
3: [某1个]slave打开rdb快照功能
4: 配置是否只读[slave-read-only]

./src/redis-cli -p 6381

缺陷:

每次salave断开后(无论是主动断开,还是网络故障)
再连接master,都要master全部dump出来rdb,再aof(同步的过程都要重新执行一遍)

注:多台slave,不要一下启动起来,否则master可能IO剧增

redis运维简单命令

time // 查看时间戳与微妙数
dbsize // 查看当前库中的key数量
bgrewriteaof // 后台进程重写aof
bgsave // 后台保存rdb快照 // 后台进程在做dump
save // 保存rdb快照
lastsave // 上次保存时间
slaveof // 设置slave服务器

flushall // 清空所有db
flushdb // 清空当前db
shutdown [""|save|nosave] // 断开连接,关闭服务器

如果不小心运行flushall,立即 shutdown nosave,关闭服务器然后手工编辑aof文件,去掉文件中的flushall相关行,然后开启服务器,就可以导入原来数据。
如果,flushall之后,系统恰好bgrewriteaof了,那么aof就清空了,数据丢失。

info // 服务器的信息
info Stats
info CPU

1:内存
# Memory
user_memory: 1946832 // 数据结构的空间
user_memory_rss: 602516 // 实占空间
mem_fragmentatation_ratio: 3.09 // 前2者的比例,1N为佳,如果此值过大,说明redis的内存的碎片化严重,可以到处再导入一次
2: 主从复制
# Replication
role: slave
master_host: 192.168.1.10
master_prot: 6379
master_link_status: up
3:持久化
# Persistence
rdb_changes_since_last_save: 0
rbd_last_save_time: 1342356063
4:fork耗时
# Status
latest_for_usec: 963 // 上次导出rdb快照,持久化花费微秒 //  注:如果某实例有10G内容,导出需要2分钟,每分钟写入10000次,导致不断的rdb导出,磁盘始处于高IO状态。

config get requirepass // 获取配置
config set requirepass value  // 设置配置 // 特殊的选项,不允许用此命令设置,如slave-of,需要用单独的slaveof命令来设置
slowlog // 显示慢查询 (执行命令比较慢,记录起来)
config get showlog-log-slower-than

多久才叫慢

sholog-log-slower-than 10000 来指定(单位微秒)

服务器存储多少条慢查询的记录

slowlog-max-len 128来做限制

aof恢复与rdb服务器间迁移

aof恢复

场景:不小心flushall怎么办?

aof,但是存在一种aof重写情况。
当不小心运行flushall,要立即运行shutdown nosave,保证防止发生aof重写的情况。要指定nosave选项,不让保存到重写aof中。
关闭redis之后,把aof的文件修改,flushall命令删除。然后重启redis。

rdb服务器迁移

拷贝需要迁移的rdb文件,文件名为当前redis配置的redis.conf中的dbfilename选项配置相同。

注意:
在redis进程处于运行时,rdb处于打开状态。复制文件时,占据同样的句柄,导致rdb文件复制是相同。

sentinel监控

运行时,手工,更改master,slave

在redis,运行过程,master宕机,切换slave为master。
通过:

config get
config set

修改一台slave为master

  • 命令该服务不做其他redis服务的slave
    命令:slaveof no one

  • 修改其readonly为yes
    其它的slave指向刚设置的master的slave

  • 命令该服务为new master 的slave
    命令:slaveof ip port

其中要作为master的slave操作

slaveof no one // 设置为master
config  set read-read-only no // 可写

其它的slave操作

slaveof localhost 6380

sentinel监控

sentinel监控的作用:监控master,如果出现问题,把其中某一台的slave切换成master,其中的slave作为new master的slave

sentinel.conf配置文件

sentinel monitor def_master 127.0.0.1 6379 2  // 2 表示默认30秒2次没回应,master失效。
sentinel auth-pass def_master passwd

master被当前sentinel实例认定为“失效”的间隔时间
如果当前sentinel与master直接的通讯中,在指定时间内没有响应或者响应错误代码,那么当前sentinel就认为master失效(SDOWN,“主观”失效)
默认为 30秒

sentinel down-after-milliseconds def_master 30000

当sentinel实例是否允许实施“failover”(故障转移)
no表示当前sentinel为“观察者”(只参与“投票”,不参与实施failover)
全局中至少有一个为yes

sentinel can-failover def_master yes // 失效之后允不允许把slave修改成master

启动sentinel

sentinel进程还是通过redis-server来实现的。

./src/redis-server ./sentinel.conf --sentinel

redis key 设计技巧

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

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

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

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

用户表user,转换为key-value存储 :

userid username password emial
9 lisa 123456 [email protected]
set user:userid:9:username lisa
set user:userid:9:password 123456
set user:userid:9:emial [email protected]

get user:userid:9:username
keys user:userid:9*

注意:
在关系型数据库中,除主键外,还有可能其他列也步骤查询。
如上表中,username也是极频繁查询的,往往这种列也是加了索引的。
转换到k-v数据中,则也要相应的生成一条按照该列为主的key-value
通过冗余信息来维护,主键/主索引。
不会导致过度冗余,只维护一个主键,然后其它信息通过主键来查询。

set username:list:uid 9

php操作redis

安装phpredis,以.so 文件扩展形式存在

安装

  • 进入phpredis源码目录,执行phpize

  • 配置,./configuer --with-php-config=/phpconfig所在目录

  • make && make install

  • 修改php配置文件

    [reids]
    extension="reids.so"
  • 重启php

使用php操作redis

connect('127.0.0.1');
    if ($connect_result) {
        $members = array('red', 'tan', 'pink', 'cyan');
        $redis->sadd('setname', 'red', 'tan', 'pink', 'cyan');
        $getmem = $reids->smembers('setname');
        var_dump($getmem);
        $redis->close();
    }

工具

nomn查看系统资源使用率

nmon -s 1 -c 20 -f -m ./

-s 间隔多长时间,去抓取系统资源利用率的快照,包括系统资源,网络,硬盘
-c 执行多长时间
-f 结果存文件
-m 文件路径

把生成文件,使用树型结构展示,使用nmon analysre(windows)工具

redis-benchmark reids性能测试:

redis-benchmark -n 1000 // 1000次请求

模拟1000个客户端发起1万次测试请求,并统计linux系统资源使用情况。

redis-benchmark -c 1000 –n 10000 –csv

你可能感兴趣的:(redis)