Linux环境下的Redis
在Linux环境中安装redis
下载安装包
# wget http://download.redis.io/releases/redis-?.?.?.tar.gz
解压
tar -xvf 文件名.tar.gz
编译
make
安装
make install
启动Redis服务
直接启动
- 进入redis下的src目录,打开redis-server
# redis-server [port]
- 打开redis-cli
# redis-cli [-h host] [-p port]
指定配置文件启动*
编写指定配置文件 xxx.conf
打开服务时指定
# redis-server [配置文件]
持久化
什么是持久化
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为永久化。
持久化的方式
- 将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据(RDB)
- 将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程(AOF)
RDB方式
命令
save //作用:手动执行一次保存操作
bgsave //作用:手动启动后台保存操作,但不是立即执行
save second changes //作用:在一定时间内key的数量变化达到指定值时自动执行持久 化,后台是bgsave
特殊形式:
debug reload //服务器运行过程中保存
shutdown save //关闭服务器时指定保存数据
注意:save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会长时间阻塞,线上环境不建议使用;而bgsave是针对save阻塞问题做的优化,通过调用linux中的fork函数生成子进程保存,Redis中所有涉及到RDB操作都采用bgsave的方式,save命令可以放弃使用。
save指令的相关配置
-
dbfilename dump.rdb
说明:设置本地数据库文件名,默认值为dump.rdb
经验:通常设置为dump-端口号.rdb
-
dir
说明:设置存储.rdb文件的路径
经验:通常设置成存储空间较大的目录中,目录名称data
-
rdbcompression yes
说明:设置存储至本地数据库时是否压缩数据,默认为yes,采用LZF压缩
经验:通常默认为开启状态,如果设置为no,可以节省CPU运行时间,但会使存储的文件变大(巨大)
-
rdbchecksum yes
说明:设置是否进行RDB文件格式校验,该校验过程在写文件和读文件过程均进行
经验:通常默认为开启状态,如果设置为no,可以节约读写性能过程约10%时间消耗,但是存在一定的数据损坏风险
-
stop-writes-on-bgsave-error yes
说明:后台存储过程中如果出现错误现象,是否停止保存操作(bgsave的配置)
经验:通常默认为开启状态
对比
方式 | save指令 | bgsave指令 |
---|---|---|
读写 | 同步 | 异步 |
阻塞客户端指令 | 是 | 否 |
额外内存消耗 | 否 | 是 |
启动新进程 | 否 | 是 |
RDB的优缺点
优点:
- RDB时一个紧凑压缩的二进制文件,存储效率较高
- RDB内部存储的时redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
- RDB恢复数据的速度要比AOF快很多
- 应用:服务器中没X消失执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复
缺点:
- RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大可能性丢失数据
- bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
- Redis的众多版本中未进行RDB文件格式的版本同一,有可能出现各版本之间数据格式无法兼容现象
AOF方式
概念
- AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时重新执行AOF文件中的命令已达到恢复数据的目的。与RDB相比可以简单描述为将记录数据转变为记录数据产生的过程。
- AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方案。
AOF写数据的三种策略
-
always(每次)
每次写入操作均同步到AOF文件中,数据零误差,性能较低
-
everysec(每秒)
每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高
在系统突然宕机的情况下丢失1秒内的数据
-
no(系统控制)
由操作系统控制每次同步到AOF文件的周期,整体过程不可控
AOF功能开启
- 配置
appendonly yes|no //是否开启AOF持久化功能,默认为不开启状态
appendfsync always|everysec|no //AOF写数据策略
appendfilename filename //AOF持久化文件名,默认文件名为appendonly.aof,建议 配置为appendonly-端口号.aof
AOF重写
作用
- 降低磁盘占用量,提高磁盘利用率
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率
AOF重写方式
- 手动重写
bgrewriteaof
- 自动重写
auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percentage
RDB与AOF对比
持久化方式 | RDB | AOF |
---|---|---|
占用存储空间 | 小(数据级:压缩) | 大(指令级:重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略决定 |
资源消耗 | 高/重量级 | 低/轻量级 |
启动优先级 | 低 | 高 |
事务
简介
Redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰。
总结:一个队列中,一次性、顺序性、排他性的执行一系列命令。
事务的基本操作
multi //设置事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
exec //设置事务的结束位置,同时执行事务。与multi成对出现,成对使用
discard //终止当前事务的定义,发生在multi之后,exec之前
注意:已经执行完毕的命令对应的数据不会自动回滚,需要程序员在代码中实现回滚。
锁
事务锁:
watch key1 [key2...] //对key添加监视锁,在执行exec前如果key发生了变化,终止事 务执行
unwatch //取消对所有key的监视
分布式锁:
setnx lock-key value //使用setnx设置一个公共锁
del lock-key //删除一个公共锁
添加时间设定的锁:
expire lock-key second
pexpire lock-key milliseconds
利用setnx命令的返回值特征,有值返回则设置失败,无值返回则设置成功:
1.对于返回设置成功的,拥有控制权,进行下一步的具体业务操作
2.对于返回设置失败的,不具有控制权,排队或等待
删除策略
数据删除策略
Redis中数据的特征
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
- XX:具有时效性的数据
- -1:永久有效的数据
- -2:已经过期的数据或被删除的数据、未定义的数据
Redis中时效性数据的存储结构
目标
在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降,甚至引发服务器宕机或内存泄漏
定时删除
- 创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作。
- 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
- 缺点:CPU压力很大,无论CPU此时负载多高,均占用CPU,会影响Redis服务器响应时间和指令吞吐量
- 总结:用处理器性能换取存储空间
惰性删除
- 数据到达过期时间,不做处理,等下次访问该数据时删除
- 优点:节约CPU性能,发现必须删除的时候才删除
- 缺点:内存压力很大,出现长期占用内存的数据
- 总结:用存储空间换取处理器性能
定期删除
* Redis启动服务器初始化时,读取配置server.hz的值,默认为10
* 每秒钟执行server.hz次 serverCron() -> databaseCron() -> activeExpireCycle()
* activeExpireCycle()对每个expire[*](每个数据库对应一个expire)逐一进行检测,每 次执行250ms/server.hz
* 对某个expires[*]检测时,随机挑选W个key检测
* 如果key超时,删除key
* 如果一轮中删除的kshaney的数量>W*25%,循环该过程
* 如果一轮中删除的kshaney的数量≤W*25%,检查下一个expire[\*],0-15循环
* W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值
* 参数current_db用于记录activeExpireCycle()进入哪个expire[*]执行
- 周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度
- 特点1:CPU性能占用设置有峰值,检测频度可以自定义设置
- 特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
- 总结:周期性抽查存储空间
在Redis中,同时使用 惰性删除 与 定期删除 两种策略。
数据逐出策略
什么是逐出算法
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis会临时删除一些数据为当前指令清理内存空间。清理数据的策略称为逐出算法。
注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。
影像数据逐出的相关配置
maxmemory //最大可使用内存,为物理占用内存的比例,默认0,生产环境中一般 设置50%以上
maxmemory-samples //每次选取待删除数据的个数
maxmemory-policy //达到最大内存后的逐出策略
可选的逐出策略:
- 检测易失数据(可能会过期的数据集server.db[i].expires)
- volatile-lru:挑选最近使用时间最少的数据
- volatile-lfu:挑选最近使用次数最少的数据
- volatile-ttl:挑选将要过期的数据
- volatile-random:任意选择数据
- 检测全库数据(所有数据集server.db[i].dict)
- allkeys-lru:挑选最近使用时间最少的数据
- allkeys-lfu:挑选最近使用次数最少的数据
- allkeys-random:任意选择数据
- 放弃数据驱逐
- no-enviction:禁止驱逐,会引发OOM
服务器配置
基础配置
daemonize yes|no //设置服务器以守护进程的方式运行
bind 127.0.0.1 //绑定主机地址
port 6379 //设置服务器端口号
databases 16 //设置数据库数量
日志配置
loglevel debug|verbose|notice|warning //设置服务器的日志级别
logfile 端口号.log //日志记录文件名
客户端配置
maxclients 0 //设置同一时间最大客户端连接数
timeout //客户端闲置等待最大时常,达到最大值后关闭连接,关闭 设置为0
多服务器快捷配置
include /path/server-端口号.conf //导入并加载指定配置文件信息
include /path/server-端口号.conf //导入并加载指定配置文件信息
高级数据类型
Bitmaps
简介
Redis提供了Bitmaps这个“数据结构”可以实现对位的操作。 把数据结构加上引号主要因为:
- Bitmaps本身不是一种数据结构,实际上它就是字符串,但是它可以对字符串的位进行操作。
- Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
总结:设置对应的bit串,每一位的0/1值作为判定条件。如1010001,每一位对应一个用户是否访问。
操作
getbit key offset //获取指定key对应偏移量上的bit值
setbit key offset value //设置指定key对应偏移量上的bit值,取0或1
bitcount key [start end] //计算指定key中1的数量
bitop op destkey key1 [key2...] //对指定key进行位运算并将结果保存在destkey中
op的取值:and|or|not|xor
HyperLogLog
简介
HyperLogLog是用于统计基数的。
基数:集合去重后的元素个数。如:{1,3,5,7,5,7,8}的基数为{1,3,5,7,8}
操作
pfadd key element [element...] //添加数据
pfcount key [key...] //统计数据
pfmerge destkey sourcekey [sourcekey...] //合并数据
注意:
- 用于进行基数统计,不是集合,不是保存数据,只记录数量而不是记录数据
- 核心是基数估算算法,最终数值存在一定误差
- 误差范围:基数估计是结果是一个带有0.81%标准错误的近似值
- 耗空间极小,每个HyperLogLog key占用了12K的内存用于标记基数
- pfadd命令不是一次性分配12K内存使用,会随着基数的增加内存而增大
- pfmerge命令合并后占用的存储空间为12K,无论合并之前数据量多少
GEO
简介
GEO可以用于存储位置信息。
操作
geoadd key longitude latitude member [longitude latitude member...] //添加坐标点
geopos key member [member...] //获取坐标点
geodist key member1 member2 [unit] //计算坐标点距离
georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [count count] //根据坐标求范围内的数据
georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [count count] //根据点求范围内的数据
geohash key member [member...] //获取指定点对应的坐标hash值