explain
这个文件存在的意义是记录工程问题以及所可能的目前的解决方案。
redis
大key问题和热key问题
https://help.aliyun.com/document_detail/353223.html
名词 | 解释 |
---|---|
大Key | 通常以Key的大小和Key中成员的数量来综合判定,例如:Key本身的数据量过大:一个String类型的Key,它的值为5 MB。Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10,000个。Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1,000个但这些成员的Value(值)总大小为100 MB。 |
热Key | 通常以其接收到的Key被请求频率来判定,例如:QPS集中在特定的Key:Redis实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1 MB的HASH Key每秒发送大量的HGETALL操作请求。CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的ZRANGE操作请求。 |
大key危害
看上面连接
大key解决方案
通俗来说大key说白是value太大了,所以需要优化是大value问题。
主要分为2种情况
- 可删除,可以删除的就需要进行删除处理。
- 不可删除。许多的value不可以删除,所以操作上来说就需要进行大key拆分了。
热key危害
负载不均衡,旱的旱死,劳的劳死。可能总警报,但还是不够用。
热key解决方案
将key加一个随机hash值,分发到不同的节点上。
关键点
怎么发现大key和热key
看上面连接
秒杀场景下超访问问题
https://crossoverjie.top/2018/04/28/sbc/sbc7-Distributed-Limit/
我100的库存,有100000人请求,其中大部分请求没必要走到后面的步骤,直接在前处理干掉。
关键代码
--lua 下标从 1 开始
-- 限流 key
local key = KEYS[1]
-- 限流大小
local limit = tonumber(ARGV[1])
-- 获取当前流量大小
local curentLimit = tonumber(redis.call('get', key) or "0")
if curentLimit + 1 > limit then
-- 达到限流大小 返回
return 0;
else
-- 没有达到阈值 value + 1
redis.call("INCRBY", key, 1)
redis.call("EXPIRE", key, 2)
return curentLimit + 1
end
lua脚本,给关键key设置访问次数,以及过期事件,将访问压力按时间切分限制,例如
public boolean limit() {
String key = String.valueOf(System.currentTimeMillis() / 1000);
Object result = null;
if (jedis instanceof Jedis) {
result = ((Jedis) this.jedis).eval(script, Collections.singletonList(key), Collections.singletonList(String.valueOf(limit)));
} else if (jedis instanceof JedisCluster) {
result = ((JedisCluster) this.jedis).eval(script, Collections.singletonList(key), Collections.singletonList(String.valueOf(limit)));
} else {
//throw new RuntimeException("instance is error") ;
return false;
}
if (FAIL_CODE != (Long) result) {
return true;
} else {
return false;
}
}
就是设置为1s内超过多少次访问不予访问。这个需要与过期时间进行交互,自己想想具体过程吧。和tm的消费卷系统差不多妈的。