redis
NoSql
- Not Only Sql
- 水平(横向)扩展方便高效
- 数据达到300w考虑,正常4到500w,优化6到700w
- 高性能读取(reids每秒达到10w次)
- 高可用(搭建集群)
- 存数据,做缓存
- 常见类型
- 键值对数据库(Redis、Memcache)
- 列存储数据库(Hbase、Cassandra)
- 文档型数据库(MangoDB、CouchDB)
- 图形数据库(Neo4J、FlockDB)
分布式缓存
- 提升读取性能
- 分布式计算领域
- 为数据库降低查询压力
- 跨服务器缓存
- 内存式缓存
缓存方案对比
- Ehcache
- 优点
- 基于java开发
- 基于JVM缓存
- 简单、轻巧、方便
- 缺点
- 集群不支持
- 分布式不支持
- 优点
- Memcache
- 优点
- 简单的key-value存储
- 内存使用率比较高
- 多核处理,多线程
- 缺点
- 无法容灾
- 无法持久化
- 优点
- Redis
- 优点
- 丰富的数据结构
- 持久化
- 主从同步、故障转移
- 内存数据库
- 缺点
- 单线程
- 单核
- 优点
Redis简介
- NoSql
- 分布式缓存中间件
- key-value存储
- 提供海量数据存储访问
- 数据存储在内存里,读取更快
- 非关系型、分布式、开源、水平扩展
- Redis-REmote DIctionary Server
- Redis是一个使用ANSI C语言编写的开源数据库
- 高性能的key-value数据库
- 内存数据库,支持数据持久化
为什么Redis能这么快
- 完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高
- 数据结构简单,对数据操作也简单
- 采用单线程,单线程也能处理高并发请求,想多核也可启动多实例
- 使用多路I/O复用模型,非阻塞IO
- Redis采用的I/O多路复用函数:epoll/kqueue/evport/select
- 因地制宜
- 优先选择时间复杂度为O(1)的I/O多路复用函数作为底层实现
- 以时间复杂度为O(n)的select作为保底
- 基于react设计模式监听I/O事件
Redis安装
- 安装gcc编译环境
yum install gcc-c++
make && make install
- 设置redis开机自启
cd utils/
cp redis_init_script /etc/init.d
vim /etc/init.d/redis_init_script
#chkconfig 22345 10 90
#description: Start and Stop Redis
chkconfig redis_init_script on
Redis对象结构
- 数据类型(type)
- string
- hash
- list
- set
- sorted set
- 编码方式
- raw
- int
- ht
- zipmap
- linkedlist
- ziplist
- intset
- 数据指针
- 虚拟内存
- 其它信息
Redis数据结构
- string
- setex(并设置过期时间,单位秒)
- psetex(设置过期时间,单位毫秒)
- getrange word 0 2(取word键的值的0~2数据)
- getset(先get后set)
- mset(设置多个key)
- mget
- setnx(只有key不存在才能设置成功)
- strlen(字符串长度)
- msetnx(要么都成功,要么都失败;原子性)
- incr(数字加1)
- incrby(可自定义步长)
- decr(数字减1)
- decrby
- append(追加)
- hash
- hset
- hexists(hash是否存在某个键)
- hget
- hgetall
- hkeys
- hvals
- hlen
- hmget
- hmset
- hdel
- hsetnx
- list(可重复)
- lpush(放到最前面)
- llen
- lrange
- lset
- lindex
- lpop(移除第一个元素)
- rpop(移除最后一个元素)
- set
- sadd
- scard(返回元素数量)
- smembers(查看所有元素成员)
- sdiff(差集)
- sinter(交集)
- sunion(并集)
- srandmember(返回指定个数的随机元素)
- sismember(是否存在元素)
- srem(移除成员)
- spop(移除并返回随机元素)
- sortedset(有序集合)
- zadd
- zcard
- zscore(查看元素分数)
- zcount(返回指定区间分数的元素个数)
- zrank(返回指定元素索引)
- zincrby(为指定元素增加指定分数并返回增加完后的分数)
- zrange(查看索引范围内的元素)
Redis启动服务方式
- ./redis-server;./redis-cli(默认启动方式,端口6379)
- ./redis-server –port 6380;./redis-cli -p 6380(指定端口启动)
- ./redis-server ../redis.conf(指定配置文件启动)
- ./redis-cli -h 127.0.0.1(连接远程)
- ./redis-cli -a password(密码连接)
Redis基础命令
- info(查看系统信息)
- Keyspace(默认db0)
- flushdb(清除当前db)
- flushall(清除所有db)
- dbsize(当前db数量)
- save(redis持久化)
Redis键命令
- set
- get
- hset(hash)
- keys
- 该指令一次性返回所有匹配的key
- 键的数量过大会使服务卡顿
- scan
- del
- exists
- ttl(查看key剩余生存时间,单位为秒,返回-1则代表没有过期时间,-2代表不存在)
- expire(设置键的过期时间)
- type(查看值的类型)
- randomkey
- rename(重命名)
- 以nx结尾的命令多会先判断
Redis分布式锁命令
- setnx
-
set key value [EX seconds] [PX millisconds] [NX XX] - getset
- expire
- del
Redis持久化
- RDB(快照)持久化:保存某个时间点的全量数据快照
- 内存数据的全量同步,数据量大会由于I/O而严重影响性能
- 可能会因为Redis怪掉而丢失从当前至最近一次快照期间的数据
- 配置
# 如果1个缓存更新,则15分钟后备份
save 900 1
# 如果10个缓存更新,则5分钟后备份
save 300 10
# 如果10000个缓存更新,则1分钟后备份
save 60 10000
# yes(如果save出错,则停止写操作);no(可能造成数据不一致)
stop-writes-on-bgsave-error yes
# yes(开启rdb压缩模式);no(关闭,节约CPU消耗,但是文件会大)
rdbcompression
# yes(使用CRC64算法校验对rdb进行数据校验,有10%性能损耗);no(不校验)
- AOF(Append-Only-File)持久化:保存写状态
- 记录下除了查询以外的所有变更数据库状态的指令
- 以append的形式追加保存到AOF文件中(增量)
- 日志重写解决AOF文件大小不断增大的问题
- 调用fork(),创建一个子进程
- 子进程把新的AOF写到一个临时文件里,不依赖原来的AOF文件
- 主进程持续将新的变动同时写到内存和原来的AOF里
- 主进程获取子进程重写AOF完成信号,往新AOF同步增量变动
- 使用新的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)
- RDB-AOF混合持久化方式(默认配置4.0之后)
- RDB和AOF优缺点
- RDB优点:全量数据快照,文件小,恢复快
- RDB缺点:无法保存最近一次快照之后的数据
- AOF优点:可读性高,适合保存增量数据,数据不易丢失
- AOF缺点:文件体积大,恢复时间长
- RDB和AOF文件共存情况下的恢复流程:AOF->RDB
主从复制(读写分离)
- 从节点配置
# 主节点IP端口
replicaof 192.168.1.191 6379
# 主节点密码
masterauth 123
# 从节点数据是否只读
replica-read-only yes
# 是否无磁盘化复制
repl-diskless-sync no
# 无磁盘化复制同步前等待时间
repl-diskless-sync-delay 5
缓存过期处理及内存淘汰机制
- redis的高并发基于内存
- 处理过期的key
- 设置expire的key缓存过期了,但是服务器的内存还是会被占用,这是因为redis所基于的两种删除策略
- (主动)定期删除
# 定时随机检查过期的key,如果过期则被清理删除(每秒检查10次)
# 默认配置
hz 10
* (被动)惰性删除
# 当客户端请求一个已经过期的key时,redis会检查这个key是否过期,
过期则删除,返回nil。这种策略对CPU友好,不会有太多损耗,但是内存占用会比较高
- 内存淘汰管理机制
- 内存占满可以使用硬盘来保存,但是硬盘没有内存快,会影响redis性能 所以,当内存占用满了之后,redis提供了一套缓存淘汰机制(MEMORY MANAGEMENT)
# 当内存使用率到达,则开始清理缓存(字节)
maxmemory 3145728
# 淘汰策略
# noveiction(默认)旧缓存永不过期,新缓存设置不了,返回错误
# allkeys-lru(推荐)清楚最少用的旧缓存,然后保存新的缓存
# allkeys-random(不推荐)在所有的缓存种随机删除
# volatile-lru在那些设置了expire过期时间的缓存中,
清除最少使用的旧缓存,然后保存新的缓存
# volatile-random在那些设置了expire过期时间的缓存中,随机删除缓存
# volatile-ttl在那些设置了expire过期时间的缓存中,删除即将过期的
maxmemory-policy allkeys-lru
redis哨兵
- 用于监控redis集群中master状态的工具,是redis高可用解决方案,哨兵可以检测一个或多个redis master服务, 以及这些master服务的所有从服务;当某个master服务宕机后,会把这个master下的某个从服务升级为master来代替已宕机的master继续工作
- 配置
# 配置sentinel.conf
# 普通配置
# 哨兵端口
port 26379
# pid文件路径
pidfile "/usr/local/redis/sentinel/redis-sentinel.pid"
# 工作目录
dir "/usr/local/redis/sentinel"
# 守护进程运行哨兵
daemonize yes
# 保护模式(内网不需要开启,公网可以开启并绑定IP地址)
protected-mode no
# 日志地址
logile "/usr/local/redis/sentinel/redis-sentinel.log"
# 核心配置
# 配置哨兵
sentinel monitor mymaster 127.0.0.1 6379 2
# 密码
sentinel auth-pass 123
# master被sentinel认定为失效的间隔时间
sentinel down-after-milliseconds mymaster 30000
# 剩余的slaves重新和新的master做同步的并行个数
sentinel parallel-syncs mymaster 1
# 主备切换的超时时间,哨兵要去做故障转移,这个哨兵也是一个进程,
如果没有执行,超过这个时间,会由其它哨兵来处理
sentinel failover-timeout mymaster 180000
- 启动哨兵
redis-sentinel sentinel.conf
- spring boot集成redis哨兵配置
spring:
redis:
database: 1
password: 123
sentinel:
master: mymaster
nodes: 192.168.1.191:26379,192.168.1.192:26739,192.168.1.193:26739
redis集群
- 主从复制以及哨兵可以提高读的并发,但是单个master容量有限,数据达到一定程度会有瓶颈,这时可以通过水平扩展为多master-slave成为集群
- 哨兵模式其实也是一种集群,能够提高读请求的并发,但是容错方面有些问题,即master同步数据给slave的时候,其实是异步复制,如果这个时候master挂掉,那么slave上的数据就缺失
- 集群特点
- 每个节点知道彼此之间的关系,也知道自己的角色,彼此之间可以交互通信
- 客户端和集群建立连接,只需要和其中一个建立关系就行
- 某个节点挂掉,通过超过半数节点来进行检测,客观下线后主从切换
- redis中存在很多的插槽,又名槽节点,用于存储数据
- 集群配置
vim redis.conf
# 开启集群模式
cluster-enabled yes
# 每个节点需要一个配置文件,该文件用于存储集群模式下的集群状态等信息,由redis自己维护,
如果需要重新创建集群,删除该文件即可
cluster-config-file nodes-201.conf
# 超时时间,超时则认为master宕机,随后主备切换
cluster-node-timeout 5000
# 开启aof
appendonly yes
- 创建集群
# 如果使用的是redis3.x版本,需要使用redis-trib.rb来构建集群,新版本使用c语言构建
# 这里用新版redis构建方式
# 创建集群,主节点与从节点比例为1:1,1-3为主,4-6为从,1和4,2和5,3和6为主从关系
redis-cli --cluster create ip1:port1 ip2:port2 ip3:port3 ip4:port4 ip5:port5 ip6:port6 --cluster-replicas 1
- 检查集群信息
redis-cli --cluster check 192.168.1.191:6379
- 槽节点
- 用于装数据,主节点有,从节点没有
- 槽总数:16384
- 平均分配
- 槽存储数据(hash(key)%16384)
- spring boot集成redis集群配置
spring:
redis:
password: 123
cluster:
nodes: 192.168.1.191:6379,192.168.1.192:6379,192.168.1.193:6379,192.168.1.194:6379,192.168.1.195:6379,192.168.1.196:6379
缓存穿透
- 请求数据不存在数据库中,直接访问数据库的行为(无论数据库中是否有数据,查询后都放入缓存,设置有效期即可)
- 布隆过滤器(能够迅速判断一个元素是否在一个集合中)
缓存雪崩
- 大量缓存过期失效,同时大量请求访问,系统服务宕机
- 预防措施
- 永不过期
- 过期时间错开
- 多缓存结合
- 第三方redis