文章目录
1. 介绍
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
- 官网: https://redis.io/
- 中文网站: http://redis.cn/
- DB-Engines: https://db-engines.com/en/ranking
- 与memcache对比
2. 安装
-
官网下载地址:http://redis.cn/
http://download.redis.io/releases/redis-6.0.6.tar.gz
-
下载(选择node01(192.168.109.132))
wget http://download.redis.io/releases/redis-6.0.6.tar.gz
如果没有wget指令:yum install wget -
解压
tar -zxvf redis-6.0.6.tar.gz -
编译
make
如果出现上述错误:
下载gcc:yum install gcc
清空之前编译残留:make distclean
继续执行编译:make
gcc版本太低,升级版本:
查看版本:gcc -v
升级:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
以上为临时启用,如果要长期使用gcc 9.1:
echo “source /opt/rh/devtoolset-9/enable” >>/etc/profile
清空之前编译残留:make distclean
继续执行编译:make
-
指定目录编译安装
将redis可执行文件移至指定目录
make install PREFIX=/usr/local/redis6
-
配置redis环境
vim /etc/profile
source /etc/profile -
运行redis自带的安装程序:
cd utils
./install_server.sh
如果出现一下错误:
vim install_server.sh
将以下进行注释
继续执行:./install_server.sh
-
查看状态
service redis_6379 status
-
客户端登录
3. 类型介绍
3.1 string
- string指令熟悉
APPEND key value
summary: Append a value to a key
since: 2.0.0
BITCOUNT key [start end]
summary: Count set bits in a string
since: 2.6.0
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
summary: Perform arbitrary bitfield integer operations on strings
since: 3.2.0
BITOP operation destkey key [key ...]
summary: Perform bitwise operations between strings
since: 2.6.0
BITPOS key bit [start] [end]
summary: Find first bit set or clear in a string
since: 2.8.7
DECR key
summary: Decrement the integer value of a key by one
since: 1.0.0
DECRBY key decrement
summary: Decrement the integer value of a key by the given number
since: 1.0.0
GET key
summary: Get the value of a key
since: 1.0.0
GETBIT key offset
summary: Returns the bit value at offset in the string value stored at key
since: 2.2.0
GETRANGE key start end
summary: Get a substring of the string stored at a key
since: 2.4.0
GETSET key value
summary: Set the string value of a key and return its old value
since: 1.0.0
INCR key
summary: Increment the integer value of a key by one
since: 1.0.0
INCRBY key increment
summary: Increment the integer value of a key by the given amount
since: 1.0.0
INCRBYFLOAT key increment
summary: Increment the float value of a key by the given amount
since: 2.6.0
MGET key [key ...]
summary: Get the values of all the given keys
since: 1.0.0
MSET key value [key value ...]
summary: Set multiple keys to multiple values
since: 1.0.1
MSETNX key value [key value ...]
summary: Set multiple keys to multiple values, only if none of the keys exist
since: 1.0.1
PSETEX key milliseconds value
summary: Set the value and expiration in milliseconds of a key
since: 2.6.0
SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
summary: Set the string value of a key
since: 1.0.0
SETBIT key offset value
summary: Sets or clears the bit at offset in the string value stored at key
since: 2.2.0
SETEX key seconds value
summary: Set the value and expiration of a key
since: 2.0.0
SETNX key value
summary: Set the value of a key, only if the key does not exist
since: 1.0.0
SETRANGE key offset value
summary: Overwrite part of a string at key starting at the specified offset
since: 2.2.0
STRALGO LCS algo-specific-argument [algo-specific-argument ...]
summary: Run algorithms (currently LCS) against strings
since: 6.0.0
STRLEN key
summary: Get the length of the value stored in a key
since: 2.2.0
type key 获取key值类型
object encoding key 获取key的编码;3种: int , embstr , raw
- bitmaps
BITPOS key bit [start] [end]
BITPOS k1 1 0 1 获取k1中字节下标0-1,1出现的开始位置
结果为:1
BITCOUNT key [start end]
BITCOUNT k1 0 1 获取k1中字节下标0-1,1出现的次数
结果为:3
BITOP:
- 案例:
用户系统,统计用户登录天数,窗口随机
tom第1天登录:
SETBIT tom 0 1
tom第100天登录:
SETBIT tom 99 1
tom第365天登录:
SETBIT tom 364 1
统计一共登录天数:BITCOUNT tom 0 -1
最后两周登录天数:BITCOUNT tom -2 -1
3.2 hash
HDEL key field [field ...]
summary: Delete one or more hash fields
since: 2.0.0
HEXISTS key field
summary: Determine if a hash field exists
since: 2.0.0
HGET key field
summary: Get the value of a hash field
since: 2.0.0
HGETALL key
summary: Get all the fields and values in a hash
since: 2.0.0
HINCRBY key field increment
summary: Increment the integer value of a hash field by the given number
since: 2.0.0
HINCRBYFLOAT key field increment
summary: Increment the float value of a hash field by the given amount
since: 2.6.0
HKEYS key
summary: Get all the fields in a hash
since: 2.0.0
HLEN key
summary: Get the number of fields in a hash
since: 2.0.0
HMGET key field [field ...]
summary: Get the values of all the given hash fields
since: 2.0.0
HMSET key field value [field value ...]
summary: Set multiple hash fields to multiple values
since: 2.0.0
HSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate hash fields and associated values
since: 2.8.0
HSET key field value [field value ...]
summary: Set the string value of a hash field
since: 2.0.0
HSETNX key field value
summary: Set the value of a hash field, only if the field does not exist
since: 2.0.0
HSTRLEN key field
summary: Get the length of the value of a hash field
since: 3.2.0
HVALS key
summary: Get all the values in a hash
since: 2.0.0
3.3 list
BLPOP key [key ...] timeout
summary: Remove and get the first element in a list, or block until one is available
since: 2.0.0
BRPOP key [key ...] timeout
summary: Remove and get the last element in a list, or block until one is available
since: 2.0.0
BRPOPLPUSH source destination timeout
summary: Pop an element from a list, push it to another list and return it; or block until one is available
since: 2.2.0
LINDEX key index
summary: Get an element from a list by its index
since: 1.0.0
LINSERT key BEFORE|AFTER pivot element
summary: Insert an element before or after another element in a list
since: 2.2.0
LLEN key
summary: Get the length of a list
since: 1.0.0
LPOP key
summary: Remove and get the first element in a list
since: 1.0.0
LPOS key element [RANK rank] [COUNT num-matches] [MAXLEN len]
summary: Return the index of matching elements on a list
since: 6.0.6
LPUSH key element [element ...]
summary: Prepend one or multiple elements to a list
since: 1.0.0
LPUSHX key element [element ...]
summary: Prepend an element to a list, only if the list exists
since: 2.2.0
LRANGE key start stop
summary: Get a range of elements from a list
since: 1.0.0
LREM key count element
summary: Remove elements from a list
since: 1.0.0
LSET key index element
summary: Set the value of an element in a list by its index
since: 1.0.0
LTRIM key start stop
summary: Trim a list to the specified range
since: 1.0.0
RPOP key
summary: Remove and get the last element in a list
since: 1.0.0
RPOPLPUSH source destination
summary: Remove the last element in a list, prepend it to another list and return it
since: 1.2.0
RPUSH key element [element ...]
summary: Append one or multiple elements to a list
since: 1.0.0
RPUSHX key element [element ...]
summary: Append an element to a list, only if the list exists
since: 2.2.0
3.4 set
无序,去重
SADD key member [member ...]
summary: 添加一个或者多个元素到集合中
since: 1.0.0
SCARD key
summary: 获取集合中的元素数量
since: 1.0.0
SDIFF key [key ...]
summary: 获取队列的差集(以最前面的key为基准)
since: 1.0.0
SDIFFSTORE destination key [key ...]
summary: 获取队列的差集,并存储在一个关键的结果集中
since: 1.0.0
SINTER key [key ...]
summary: 获取两个集合的交集
since: 1.0.0
SINTERSTORE destination key [key ...]
summary: 获取两个集合的交集,并存储在一个关键的结果集中
since: 1.0.0
SISMEMBER key member
summary: 确定一个给定的值是一个集合的成员
since: 1.0.0
SMEMBERS key
summary: 获取集合里面的所有元素
since: 1.0.0
SMOVE source destination member
summary: 移动集合里面的一个元素到另一个集合
since: 1.0.0
SPOP key [count]
summary: 删除并获取一个集合里面的元素
since: 1.0.0
SRANDMEMBER key [count]
summary: 从集合里面随机获取一个元素
since: 1.0.0
SREM key member [member ...]
summary: 从集合里面删除一个或多个元素
since: 1.0.0
SSCAN key cursor [MATCH pattern] [COUNT count]
summary: 迭代set里面的元素
since: 2.8.0
SUNION key [key ...]
summary: 获取集合的并集
since: 1.0.0
SUNIONSTORE destination key [key ...]
summary: 获取集合的并集,并存储在一个给定的结果集中
since: 1.0.0
案例:
抽奖系统
- SRANDMEMBER key [count]
正数:取出一个去重的结果集(数量不能超过已有集)
负数:取出一个带重复的结果集,结果一定满足你要的数量
0:不返回 - SPOP key [count]
随机取出你要的数量的去重结果集(更符合抽奖,中过奖的将不再参与下一轮)
3.5 sorted_set
BZPOPMAX key [key ...] timeout
summary: Remove and return the member with the highest score from one or more sorted sets, or block until one is available
since: 5.0.0
BZPOPMIN key [key ...] timeout
summary: Remove and return the member with the lowest score from one or more sorted sets, or block until one is available
since: 5.0.0
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
summary: 添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
since: 1.2.0
ZCARD key
summary: 获取一个排序的集合中的成员数量
since: 1.2.0
ZCOUNT key min max
summary: 返回分数范围内的成员数量
since: 2.0.0
ZINCRBY key increment member
summary: 增量一名成员在排序设置的评分
since: 1.2.0
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
summary: 获取交集并把结果赋值给一个新的key,weight 给每个可以设置权重,aggregate 最后score的函数,sum是求和,min最小,max最大
since: 2.0.0
ZLEXCOUNT key min max
summary: 指定字典区间内成员数量,[符号表示包含,(符号表示不包含,[min,[max 可以用-,+ 代替,例如:ZLEXCOUNT key - +
since: 2.8.9
ZPOPMAX key [count]
summary: 删除并返回有序集合key中的最多count个具有最高得分的成员
since: 5.0.0
ZPOPMIN key [count]
summary: 删除并返回有序集合key中的最多count个具有最低得分的成员
since: 5.0.0
ZRANGE key start stop [WITHSCORES]
summary: 返回存储在有序集合key中的指定范围的元素
since: 1.2.0
ZRANGEBYLEX key min max [LIMIT offset count]
summary: 返回指定成员区间内的成员,按成员字典正序排序, 分数必须相同
since: 2.8.9
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
summary: 返回key的有序集合中的分数在min和max之间的所有元素(包括分数等于max或者min的元素)
since: 1.0.5
ZRANK key member
summary: 返回有序集key中成员member的排名
since: 2.0.0
ZREM key member [member ...]
summary: 从有序集合中删除一个或多个成员
since: 1.2.0
ZREMRANGEBYLEX key min max
summary: 删除名称按字典由低到高排序成员之间所有成员
since: 2.8.9
ZREMRANGEBYRANK key start stop
summary: 移除有序集key中,指定排名(rank)区间内的所有成员
since: 2.0.0
ZREMRANGEBYSCORE key min max
summary: 移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员
since: 1.2.0
ZREVRANGE key start stop [WITHSCORES]
summary: 返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从大到小)来排列
since: 1.2.0
ZREVRANGEBYLEX key max min [LIMIT offset count]
summary: 返回已排序集合中的成员范围,按字典序排列,从高到低的字符串排序。
since: 2.8.9
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
summary: 返回有序集合中指定分数区间内的成员,分数由高到低排序
since: 2.2.0
ZREVRANK key member
summary: 返回有序集key中成员member的排名,其中有序集成员按score值从大到小排列。排名以0为底,也就是说,score值最大的成员排名为0
since: 2.0.0
ZSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate sorted sets elements and associated scores
since: 2.8.0
ZSCORE key member
summary: 返回有序集key中,成员member的score值
since: 1.2.0
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
summary: 计算给定的numkeys个有序集合的并集,并且把结果放到destination中
since: 2.0.0
案例:
实时热搜排名
sorted_set底层实现原理(skip list 跳跃表)
4. Pub/Sub
PSUBSCRIBE pattern [pattern ...]
summary: 订阅给定的模式(patterns)
since: 2.0.0
PUBLISH channel message
summary: 将信息 message 发送到指定的频道 channel
since: 2.0.0
PUBSUB subcommand [argument [argument ...]]
summary: PUBSUB 是自省命令,能够检测PUB/SUB子系统的状态
since: 2.8.0
PUNSUBSCRIBE [pattern [pattern ...]]
summary: 指示客户端退订指定模式,若果没有提供模式则退出所有模式
since: 2.0.0
SUBSCRIBE channel [channel ...]
summary: 订阅给指定频道的信息
since: 2.0.0
UNSUBSCRIBE [channel [channel ...]]
summary: 指示客户端退订给定的频道,若没有指定频道,则退订所有频道.
since: 2.0.0
订阅某个频道只能收到订阅之后的信息,频道之前的消息不能获取
消息是一个有三个元素的多块响应 :
第一个元素是消息类型:
subscribe: 表示我们成功订阅到响应的第二个元素提供的频道。第三个参数代表我们现在订阅的频道的数量。
unsubscribe:表示我们成功取消订阅到响应的第二个元素提供的频道。第三个参数代表我们目前订阅的频道的数量。当最后一个参数是0的时候,我们不再订阅到任何频道。当我们在Pub/Sub以外状态,客户端可以发出任何redis命令。
message: 这是另外一个客户端发出的发布命令的结果。第二个元素是来源频道的名称,第三个参数是实际消息的内容
5. transactions
DISCARD -
summary: 刷新一个事务中所有在排队等待的指令,并且将连接状态恢复到正常
since: 2.0.0
EXEC -
summary: 执行事务中所有在排队等待的指令并将链接状态恢复到正常 当使用WATCH 时,只有当被监视的键没有被修改,且允许检查设定机制时,EXEC会被执行
since: 1.2.0
MULTI -
summary: 标记一个事务块的开始。 随后的指令将在执行EXEC时作为一个原子执行
since: 1.2.0
UNWATCH -
summary: 刷新一个事务中已被监视的所有key
since: 2.2.0
WATCH key [key ...]
summary: 标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)
since: 2.2.0
MULTI 命令用于开启一个事务,它总是返回 OK 。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。
另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务
EXEC 命令的回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。
当客户端处于事务状态时, 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。
当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出:
WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。
被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。
- 举个例子:
当多个客户端同时对同一个键进行增 1 操作,就会产生竞争条件。如果客户端 A 和 B 都读取了键原来的值, 比如 10 , 那么两个客户端都会将键的值设为 11 , 但正确的结果应该是 12 才对。
如果在 WATCH 执行之后, EXEC 执行之前, 有其他客户端修改了 key 的值, 那么当前客户端的事务就会失败。 程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。
这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。
6. redis内存回收算法
6.1 Maxmemory配置指令
maxmemory配置指令用于配置Redis存储数据时指定限制的内存大小。通过redis.conf可以设置该指令,或者之后使用CONFIG SET命令来进行运行时配置。
例如为了配置内存限制为100mb,以下的指令可以放在redis.conf文件中。
maxmemory 100mb
设置maxmemory为0代表没有内存限制。对于64位的系统这是个默认值,对于32位的系统默认内存限制为3GB。
当指定的内存限制大小达到时,需要选择不同的行为,也就是策略。 Redis可以仅仅对命令返回错误,这将使得内存被使用得更多,或者回收一些旧的数据来使得添加数据时可以避免内存限制
6.2 回收策略
当maxmemory限制达到的时候Redis会使用的行为由 Redis的maxmemory-policy配置指令来进行配置。
以下的策略是可用的:
- noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
6.3 LRU与LFU的区别
1. LRU
- 概念
LRU(The Least Recently Used,最近最少未使用)是一种常见内存管理算法,最早应用于Linux操作系统,在Redis中也有广泛使用的。
LRU算法有这样一种假设:如果某个数据长期不被使用,在未来被用到的几率也不大;因此缓存容量达到上限时,应在写入新数据之前删除最久未使用的数据值,从而为新数据腾出空间。
- LRU算法图示
我们可以使用双向链表+哈希表来模拟实现LRU算法:
- 哈希表用来快速查找某个key是否存于缓存中
- 链表用来表示使用数据项的时间先后次序
LRU存储图示
当LRU的容量未到达上限时,对某个数据进行访问(包括添加,读取,修改),则只需要在链表头部插入新节点即可。
当LRU的容量到达上限时,需要添加某个数据,则需要移除链表最末端的键值(最久未使用),然后头插新节点。
容量未满,插入新值003
容量上限,插入新值004
访问数据003
2. LFU
- 概念
LFU(The Least Frequently Used,最不经常使用)也是一种常见的缓存算法。
和LRU类似,LFU同样有这样的假设:如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰;当存在两个或者更多个键具有相同的使用频次时,应该淘汰最久未使用的数据
- LFU算法图示
我们可以使用双哈希表 + 双链表来模拟实现LFU算法:
- key_table:用来快速查找某个key是否存于缓存中
- freq_table:以使用频次为键,存储相同使用频次的节点
LFU存储图示
当LFU的容量未到达上限时,对某个数据进行访问(包括添加,读取,修改),其使用频次加一,则只需要在对应链表头部插入新节点即可。
当LFU的容量到达上限时,需要添加某个数据,则需要移除当前使用频次最低的链表最末端的键值(最久未使用),然后在频次为1的链表头插新节点。
容量未满,插入新值005
访问数据001
容量上限,插入新值006
7. Redis 持久化
- RDB
- AOF
- aof文件解读
设置一个操作:
set k1 hello
星号* 后面的数字,表示下面有几个元素组成,两个元素select和0,选择0号库,$表示元素是由几个字节组成,select 6个字节,0一个字节
当没有开启rdb,aof混合时,aof-use-rdb-preamble no
自己手动执行 BGREWRITEAOF重写命令,会对aof指令进行合并
执行BGREWRITEAOF前
执行BGREWRITEAOF后
当开启rdb,aof混合时,aof-use-rdb-preamble yes
自己手动执行 BGREWRITEAOF重写命令,会将aof以前的指令重写为rdb,之后有新的操作,继续append到aof文件中
自动触发重写:
auto-aof-rewrite-min-size:表示运行 AOF 重写时文件最小体积,默认为 64MB。
auto-aof-rewrite-percentage:代表当前 AOF 文件空间(aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值
8. 主从复制
8.1 复制
- 启动三个redis实例,6379,6380,6381
- 6380,6381上执行:
REPLICAOF 127.0.0.1 6379
6379:
6380,6381:
从redis,只能读,不能写(可通过配置修改replica-read-only no)
- 当某个从挂掉时:
redis-server ./6381.conf --replicaof 127.0.0.1 6379
- 当主6379挂掉时,使6380变成主:
replicaof no one
6381执行:replicaof 127.0.0.1 6380
缺点:需要人工去维护主的故障问题
8.2 高可用
- 准备三台redis,三个哨兵
哨兵配置
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
- redis启动
redis-server ./6379.conf
redis-server ./6380.conf --replicaof 127.0.0.1 6379
redis-server ./6381.conf --replicaof 127.0.0.1 6379
- 哨兵启动
redis-server ./26379.conf --sentinel
redis-server ./26380.conf --sentinel
redis-server ./26381.conf --sentinel
- 6379停止服务
哨兵开始选举(推选6381成为主)
哨兵之间采用发布订阅的功能,进行通信
9. 分区
Redis分区主要有两个目的:
- 分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。
- 分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。
9.1 Twemproxy
- 安装:https://github.com/twitter/twemproxy/releases/download/0.5.0/twemproxy-0.5.0.tar.gz
- 解压:
tar -zxvf twemproxy-0.5.0.tar.gz - 编译:
./configure
make
src目录下生成可执行程序 nutcracker
- 生成系统文件
进入scripts目录
cp nutcracker.init /etc/init.d/twemproxy
chmod +x twemproxy
创建目录
mkdir /etc/nutcracker
进入twemproxy-0.5.0/conf下拷贝文件
cp ./* /etc/nutcracker/
进入src目录下
将可执行文件nutcracker加入到/usr/bin下
cp nutcracker /usr/bin/
- 修改配置文件
cd /etc/nutcracker/
vim nutcracker.yml
- 启动三台redis实例
redis-server ./6379.conf
redis-server ./6380.conf
redis-server ./6381.conf
- 启动twemproxy
service twemproxy start
- 验证
9.2 predixy
- 下载:https://github.com/joyieldInc/predixy/releases/download/1.0.5/predixy-1.0.5-bin-amd64-linux.tar.gz
- 解压:
tar -zxvf predixy-1.0.5-bin-amd64-linux.tar.gz - 修改配置文件
vim predixy.conf
Bind 127.0.0.1:7617
Include sentinel.conf
vim sentinel.conf
- 准备三台哨兵
哨兵配置
port 26379
sentinel monitor shard001 127.0.0.1 36379 2
sentinel monitor shard002 127.0.0.1 46379 2
redis-server ./26379.conf --sentinel
redis-server ./26380.conf --sentinel
redis-server ./26381.conf --sentinel
- 创建文件目录
36379,36380,46379,46380
两套主从
redis-server --port 36379
redis-server --port 36380 --replicaof 127.0.0.1 36379
redis-server --port 46379
redis-server --port 46380 --replicaof 127.0.0.1 46379
- 启动predixy
./predixy ../conf/predixy.conf
- 验证
9.3 几款产品的比较
特性 | predixy | twemproxy | codis | redis-cerberus |
---|---|---|---|---|
高可用 | Redis Sentinel或Redis Cluster | 一致性哈希 | Redis Sentinel | Redis Cluster |
可扩展 | Key哈希分布或Redis Cluster | Key哈希分布 | Key哈希分布 | Redis Cluster |
开发语言 | C++ | C | GO | C++ |
多线程 | 是 | 否 | 是 | 是 |
事务 | Redis Sentinel模式单Redis组下支持 | 不支持 | 不支持 | 不支持 |
BLPOP/BRPOP/BLPOPRPUSH | 支持 | 不支持 | 不支持 | 支持 |
Pub/Sub | 支持 | 不支持 | 不支持 | 支持 |
Script | 支持load | 不支持 | 不支持 | 不支持 |
Scan | 支持 | 不支持 | 不支持 | 不支持 |
Select DB | 支持 | 不支持 | 支持 | Redis Cluster只有一个DB |
Auth | 支持定义多个密码,给予不同读写及管理权限和Key访问空间 | 不支持 | 同redis | 不支持 |
读从节点 | 支持,可定义丰富规则读指定的从节点 | 不支持 | 支持,简单规则 | 支持,简单规则 |
多机房支持 | 支持,可定义丰富规则调度流量 | 不支持 | 有限支持 | 有限支持 |
统计信息 | 丰富 | 丰富 | 丰富 | 简单 |
10. 集群
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
Redis 集群的数据分片
Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:
- 节点 A 包含 0 到 5500号哈希槽.
- 节点 B 包含5501 到 11000 号哈希槽.
- 节点 C 包含11001 到 16384号哈希槽.
-
进入到redis安装目录:
utils/create-cluster
-
修改create-cluster
三主三从
-
启动实例
-
分配槽位
-
验证
连接客户端
redis-cli -c -p 30001
- 其他(客户端执行)
./create-cluster stop
./create-cluster clean
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1
移动槽位
redis-cli --cluster reshard 127.0.0.1:30001
查看槽位信息,(30001实例 移动了2000个给30002实例)
redis-cli --cluster info 127.0.0.1:30001
11. 击穿,穿透,雪崩
11.1 击穿
- 原因
某一个热点key,在不停地扛着高并发,无论是key的过期时间到了还是Redis内部的淘汰策略(LRU、LFU) 都会有缓存失效的一瞬间,持续的高并发访问就击破缓存直接访问数据库,导致数据库宕机
- 解决方案
1.设置热点数据"永不过期"
2.通过setnx命令实现锁机制。
其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后将数据放到redis缓存起来。后面的线程进来发现已经有缓存了,就直接走缓存。这里也存在一个问题那就是过期时间设置大小的问题,设置大了,如果第一个请求挂了,会导致后面的大量请求等待时间过长而超时,如果设置时间过短,自己没处理完别的请求进来了,这样循环下去,这也会存在一定的并发请求,可以开启一个守护线程来监控数据有没有从数据库中获取出来放入缓存,如果没有完成则适当延迟锁的过期时间。
11.2 穿透
- 原因
redis缓存和数据库中没有相关数据,redis中没有这样的数据,无法进行拦截,直接被穿透到数据库,导致数据库压力过大宕机。
- 解决方案
1.参数进行校验,不合法参数进行拦截。
2.添加IP黑名单,将一些违规操作的IP拉黑
3.可以对访问请求加一层过滤器,例如布隆过滤器、布谷鸟过滤器
11.3 雪崩
1.原因
在高并发下,大量缓存key在同一时间失效,大量请求直接落在数据库上,导致数据库宕机。
2.解决方案
1.不设置过期时间
2.随机设置key失效时间,避免大量key集体失效
3.跑定时任务,在缓存失效前刷进新的缓存.
4.通过setnx命令实现锁机制,先过去的线程更新一下所有key