Redis 实战

技术选型

什么是 NoSQL?

  • Not Only Sql.
  • 传统项目使用纯数据库
  • 为互联网和大数据而生
  • 水平(横向)扩展方便高效
  • 高性能读取
  • 高可用
  • 存数据,做缓存

NoSql 常见分类

  • 键值对数据库 - Redis, Memcache
  • 列存储数据库 - Hbase, Cassandra
  • 文档型数据库 - MongoDB, CouchDB
  • 图形数据库 - Neo4j, FlockDB

什么是分布式缓存?

  • 提升读取速度性能
  • 分布式计算领域
  • 为数据库降低查询压力
  • 跨服务器缓存
  • 内存式缓存

什么是 Redis?

  • NoSql
  • 分布式缓存中间件
  • key-value存储
  • 提供海量数据存储访问
  • 数据存储在内存里,读取更快

缓存方案对比 - Memcache

优点:

  • 简单的key-value存储
  • 内存使用率比较高
  • 多核处理,多线程

缺点:

  • 无法容灾
  • 无法持久化

缓存方案对比 - Redis

优点:

  • 丰富的数据结构
  • 持久化
  • 主从同步、故障转移
  • 内存数据库

缺点:

  • 单线程
  • 单核

Redis 概知

Redis 官网

https://redis.io

Redis 安装

二进制包安装方式

二进制包:redis-5.0.5.tar.gz

安装前依赖准备

使用二进制方式安装Redis,需要先执行yum install -y gcc-c++命令去安装c的执行环境。
然后执行make命令和make install命令,或者可以直接合并为一条命令去执行make && make install

Redis 配置

Redis 配置文件

redis.conf:

  • 启用后台运行 - daemonize yes
  • 工作空间 - dir /usr/local/redis/working
  • 远程访问 - bind 0.0.0.0 如果要限制连接IP地址的话,就填写具体的IP即可
  • 连接密码 - requirepass password
  • 端口号 - REDISPORT 默认6379

Redis 命令

  • 启动 - ./redis_init_script start

Redis 实战

Redis 命令

  • redis-cli -a password shutdown:关闭redis
  • ./redis_init_script stop:关闭redis
  • redis-cli:进入到redis客户端
  • auth pwd:输入密码
  • set key value:设置缓存
  • get key:获得缓存
  • del key:删除缓存
  • redis-cli -a password ping:查看是否存活。如果存活着的话,会返回一个PONG

Redis 的数据类型 - string

  • string字符串
string: 最简单的字符串类型键值对缓存,也是最基本的
  • key相关
keys *: 查看所有的key(不建议在生产上使用,有性能影响)
type key: key的类型
  • string类型
get/set/del: 查询/设置/删除
set rekey data: 设置已经存在的key,会覆盖
setnx rekey data: 设置已经存在的key,不会覆盖

set key value ex time: 设置带过期时间的数据
expire key: 设置过期时间
ttl: 查看剩余时间,-1永不过期,-2过期

append key: 合并字符串
strlen key: 字符串长度

incr key: 累加1
decr key: 累减1
incrby key num: 累加给定数值
decrby key num: 累减给定数值

getrange key start end: 截取数据,end=-1代表到最后
setrange key start newdata: 从start位置开始替换数据

mset: 连续设值
mget: 连续取值
msetnx: 连续设值,如果存在则不设值
  • 其他
select index: 切换数据库,总共默认16个
flushdb: 删除当前下边db中的数据
flushall: 删除所有db中的数据

Redis 的数据类型 - hash

  • hash
hash: 类似map,存储结构化数据结构,比如存储一个对象(不能有嵌套对象)
  • 使用
hset key property value:
-> hset user name imooc
-> 创建一个user对象,这个对象中包含name属性,name值为imooc

hget username: 获得用户对象中name的值

hmset: 设置对象中的多个键值对
-> hset user age 18 phone 13888888888
hmsetnx: 设置对象中的多个键值对,存在则不添加
-> hset user age 18 phone 13888888888

hmget: 获得对象中的多个属性
-> hmget user age phone

hgetall user: 获得整个对象的内容

hincrby user age 2: 累加属性
hincrbyfloat user age 2.2: 累加属性

hlen user: 有多少个属性
hexists user age: 判断属性是否存在

hkeys user: 获得所有属性
hvals user: 获得所有值

hdel user: 删除对象

Redis的数据类型 - list

  • list
list: 列表,[a, b, c, d, ……]
  • 使用
lpush userList 1 2 3 4 5: 构建一个list,从左边开始存入数据
rpush userList 1 2 3 4 5: 构建一个list,从右边开始存入数据
lrange list start end: 获得数据

lpop: 从左侧开始拿出一个数据
rpop: 从右侧开始拿出一个数据

pig cow sheep chicken duck

llen list: list长度
lindex list index: 获取list下标的值

lset list index value: 把某个下标的值替换

linsert list before/after value: 插入一个新的值

lrem list num value: 删除几个相同数据

ltrim list start end: 截取值,替换原来的list

Redis的数据类型 - zset

  • sorted set
sorted set: 排序的set,可以去重可以排序,比如可以根据用户积分做排名,积分作为set的一个数值,根据数值可以做排序。set中的每一个member都带有一个分数
  • 使用
zadd zset 10 value1 20 value2 30 value3: 设置member和对应的分数
zrange zset 0 -1: 查看所有zset中的内容
zrange zset 0 -1 withscores: 带有分数

zrank zset value: 获得对应的下标
zscore zset value: 获得对应的分数
zcard zset: 统计个数
zcount zset 分数1 分数2: 统计个数

zrangebyscore zset 分数1 分数2: 查询分数之间的member(包含分数1 分数2)
zrangebyscore zset(分数1(分数2:查询分数之间的member(不包含分数1和分数2)
zrangebyscore zset 分数1 分数2 limit start end: 查询分数之间的member(包含分数1 分数2),获得的结果集再次根据下标区间做查询

zrem zset value: 删除member

Redis的持久化

  • RDB - `Redis DataBase
  • AOF - `Append Only File

Redis的持久化机制 - RDB

  1. 什么是RDB

RDB: 每个一段时间,把内存中的数据写入磁盘的临时文件,作为快照,恢复的时候把快照文件读进内存。如果宕机重启,那么内存里的数据肯定会没有的,那么在此启动redis后,则会恢复。

  1. 备份与恢复
  • 内存备份 --> 磁盘临时文件
  • 临时文件 --> 恢复到内存
  1. RDB优劣势
  • 优势
    • 每隔一段时间备份,全量备份
    • 灾备简单,可以远程传输
    • 子进程备份的时候,主进程不会有任何io操作(不会有写入修改或删除),保证备份数据的完整性
    • 相对AOF来说,当有更大文件的时候可以快速重启恢复
  • 劣势
    • 发生故障时,有可能会丢失最后异常的备份数据
    • 子进程所占用的内存比会和父进程一模一样,如会造成CPU负担
    • 由于定时全量备份是重量级操作,所以对于实时备份,就无法处理了
  1. RDB的配置
  • 保存位置,可以在redis.conf自定义:/usr/local/redis/working/dump.rdb
  • 保存机制:
save 900 1
save 300 10
save 60 10000
save 10 3

* 如果1个缓存更新,则15分钟后备份
* 如果10个缓存更新,则5分钟后备份
* 如果10000个缓存更新,则1分钟后备份
* 演示:更新3个缓存,10秒后备份
* 演示:备份dump.rdb,删除重启
  • stop-writes-on-bgsave-error
    • yes: 如果save过程出错,则停止写操作
    • no: 可能造成数据不一致
  • rdbcompression
    • yes: 开启rdb压缩模式
    • no: 关闭,会节约cpu损耗,但是文件会大,道理同nginx
  • rdbchecksum
    • yes: 使用CRC64算法校验对rdb进行数据校验,有10%性能损耗
    • no: 不校验

Redis的持久化机制 - AOF

AOF特点

  1. 以日志的形式来记录用户请求的写操作。读操作不会记录,因为写操作才会存存储。
  2. 文件以追加的形式而不是修改的形式。
  3. redisao恢复其实就是把追加的文件从开始到结尾读取执行写操作。

优势

  1. AOF更加耐用,可以以秒级别为单位备份,如果发生问题,也只会丢失最后一秒的数据,大大增加了可靠性和数据完整性。所以AOF可以每秒备份一次,使用fsync操作。
  2. log日志形式操作,如果磁盘满了,会执行redis-check-aof工具。
  3. 当书记太大的时候,redis可以在后台自动重写aof。当redis继续把日志追加到老的文件中去时,重写也是非常安全的,不会影响客户端的读写操作。
  4. AOF日志包含的所有写操作,会更加便于redis的解析恢复。

劣势

  1. 相同的数据,同一份数据,AOFRDB大。
  2. 针对不同的同步机制,AOF会比RDB慢,因为AOF每秒都会备份做些操作,这样相对与RDB来说就略低。每秒备份fsync没毛病,但是如果客户端的每次写入就做一次备份fsync的话,那么redis的性能就会下降。
  3. AOF发生过bug,就是数据恢复的时候数据不完整,这样显得AOF会比较脆弱,容易出现bug,因为AOF没有RDB那么简单,但是呢为了防止bug的产生,AOF就不会根据旧的指令去重构,而是根据当时缓存中存在的数据指令去做重构,这样就更加健壮和可靠了。

AOF的配置

# AOF 默认关闭,yes 可以开启
appendonly no

# AOF 的文件名
appendfilename "appendonly.aof"

# no:不同步
# everysec:每秒备份,推荐使用
# always:每次操作都会备份,安全并且数据完整,但是慢性能差
appendfsync everysec

# 重写的时候是否要同步,no可以保证数据安全
no-appendfsync-on-rewrite no

# 重写机制:避免文件越来越大,自动优化压缩指令,会fork一个新的进程去完成重写动作,新进程里的内存数据会被重写,此时旧的aof文件不会被读取使用,类似rdb
# 当前AOF文件的大小是上次AOF大小的100% 并且文件体积达到64m,满足两者则触发重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Redis 缓存过期处理与内存淘汰机制

引子

计算机内存有限,越大越贵,Redis的高并发高性能都是基于内存的,用硬盘的话GG。

已过期的key如何处理?

设置了expirekey缓存过期了,但是服务器的内存还是会被占用,这是因为redis所基于的两种删除策略

redis有两种策略

  1. (主动)定时删除
  • 定时随机的检查过期的key,如果过期则清理删除。(每秒检查次数在redis.conf中的hz配置)
  1. (被动)惰性删除
  • 当客户端请求一个已经过期的key的时候,那么redis会检查这个key是否过期,如果过期了,则删除,然后返回一个nil。这种策略对cpu比较友好,不会有太多的损耗,但是内存占用会比较高。

如果内存被 Redis 缓存占用满了怎么办?

内存占满了,可以使用硬盘来保存。但是没意义,因为硬盘没有内存快,回影响redis性能。
所以,当内存占用满了以后,redis提供了一套缓存淘汰机制:MEMORY MANAGEMENT

* noeviction: 旧缓存永不过期,新缓存设置不了,返回错误
* allkeys-lru: 清除最少用的就缓存,然后保存新的缓存(推荐使用)
* allkeys-random: 在所有的缓存中随机删除(不推荐)
* volatile-lru: 在那些设置了expire过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
* volatile-random: 在那些设置了expire过期时间的缓存中,随机删除缓存
* volatile-ttl: 在那些设置了expire过期时间的缓存中,删除即将过期的

Redis 哨兵模式

引子

Master挂了,如何保证可用性,实现继续读写

什么是哨兵

Sentinel(哨兵)是用于监控Redis集群中Master状态的工具,是Redis高可用解决方案,哨兵可以监视一个或多个redis master服务,以及这些master服务的所有从服务;当某个master服务宕机后,会把这个master下的某从服务升级为master来替代已宕机的master继续工作。

配置哨兵监控Master

创建并配置sentinel.conf

  • 普通配置
port 26379
pidfile "/usr/local/redis/sentinel/redis-sentinel.pid"
dir "/usr/local/redis/sentinel"
daemonize yes
protected-mode no
logfile "/usr/local/redis/sentinel/redis-sentinel.log"
  • 核心配置
# 配置哨兵
sentinel monitor mymaster 127.0.0.1 6379 2
# 密码
sentinel auth-pass <master-name> <password>
# master被sentinel认定为失效的间隔时间
sentinel down-after-milliseconds mymaster 30000
# 剩余的slaves重新和新的master做同步的并行个数
sentinel parallel-syncs mymaster 1
# 主备切换的超时时间,哨兵要去做故障转移,这个时候哨兵也是一个进程,如果他没有去执行,超过这个时间后,会由其他的哨兵来处理
sentinel failover-timeout mymaster 180000

启动哨兵 x3

redis-sentinel sentinel.conf

测试

  1. master挂了,看slave是否成为master
  2. master恢复,观察slave状态

结论

master挂了以后,由于哨兵监控,剩余slave会进行选举,选举后其中一个成为master,当原来的master恢复后,他会成为slave

解决原Master恢复后不同步问题

一般master数据无法同步给slave的方案检查如下:

  1. 网络通信问题,要保证互相ping通,内网互通。
  2. 关闭防火墙,对应的端口开放(虚拟机汇总建议永久关闭防火墙,云服务器的话需要保证内网互通)。
  3. 统一所有的密码,通过逐台检查机器以防某个节点被遗漏。
# Redis 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×