-
Redis作为现代应用架构的核心组件,其缓存失效问题可能引发严重的系统故障。本文将全面剖析缓存穿透、击穿和雪崩三大问题的本质区别、形成机制,并提供从基础到高级的完整防御策略。一、问题本质与核心区别1. 缓存穿透(Cache Penetration)定义:查询不存在的数据,导致请求穿透缓存层直达数据库。典型场景包括:恶意攻击:使用随机ID发起大量请求业务异常:数据被删除但缓存未同步清除特征指标:缓存命中率骤降至接近0%QPS异常高涨(可能达到正常值的10倍以上)数据库CPU利用率持续100%2. 缓存击穿(Cache Breakdown)定义:热点key过期瞬间,大量并发请求直接冲击数据库。常见于:秒杀商品库存查询热门新闻详情获取明星账号动态读取关键数据:单个key的访问量占总量50%以上数据库瞬时QPS可达平时峰值的100倍持续时间短(通常1-5秒)3. 缓存雪崩(Cache Avalanche)定义:大量key同时失效或Redis集群宕机,导致请求洪峰压垮数据库。主要诱因:批量导入数据设置相同TTLRedis主从切换或集群故障缓存服务重启影响范围:超过30%的key同时失效数据库负载持续高位(5分钟以上)可能引发级联故障二、分层防御体系构建1. 缓存穿透解决方案(1)空值缓存策略// Java示例:缓存空对象 public Product getProduct(String id) { String key = "product:" + id; Product product = redis.get(key); if (product != null) { return product instanceof NullProduct ? null : product; } product = db.query("SELECT * FROM products WHERE id=?", id); if (product == null) { redis.setex(key, 300, new NullProduct()); // 缓存5分钟 return null; } redis.setex(key, 3600, product); return product; } 优化要点:空对象设置较短TTL(建议5分钟)真实数据写入时需清除空缓存(2)布隆过滤器实现# Python布隆过滤器示例 from pybloom_live import ScalableBloomFilter bf = ScalableBloomFilter(initial_capacity=1000000, error_rate=0.001) # 预热阶段加载所有有效ID for id in db.query("SELECT id FROM products"): bf.add(id) def get_product(id): if not id in bf: # 拦截不存在ID return None # ...正常缓存查询逻辑... 性能数据:内存占用:100万元素约需1.8MB查询耗时:0.01ms/次误判率可配置(通常0.1%-1%)(3)多级校验机制接口层:基础格式校验(如ID长度、类型)业务层:业务规则校验(如用户权限)系统层:限流熔断(如每秒最多50次相同查询)2. 缓存击穿防御方案(1)分布式互斥锁// Go实现Redis分布式锁 func GetProduct(id string) (Product, error) { key := fmt.Sprintf("product:%s", id) // 尝试获取缓存 if val, err := redis.Get(key); val != "" { return parseProduct(val) } // 获取分布式锁 lockKey := fmt.Sprintf("lock:%s", key) locked, err := redis.SetNX(lockKey, 1, 10*time.Second) if err != nil || !locked { time.Sleep(100 * time.Millisecond) return GetProduct(id) // 递归重试 } defer redis.Del(lockKey) // 二次检查缓存 if val, _ := redis.Get(key); val != "" { return parseProduct(val) } // 数据库查询 product, err := db.QueryProduct(id) if err != nil { return Product{}, err } // 更新缓存 redis.SetEx(key, 3600, serializeProduct(product)) return product, nil } 注意事项:锁超时时间应大于缓存重建时间(建议5-10秒)必须实现锁释放机制(try-finally模式)考虑锁竞争时的退避策略(如指数退避)(2)逻辑过期策略// NodeJS实现逻辑过期 async function getProduct(id) { const key = `product:${id}`; let data = await redis.get(key); if (data) { const { value, expire } = JSON.parse(data); if (Date.now() <= expire) { return value; } // 异步更新缓存 updateCacheInBackground(id); return value; } // 缓存未命中处理... } async function updateCacheInBackground(id) { const product = await db.queryProduct(id); const newData = { value: product, expire: Date.now() + 3600000 // 1小时后逻辑过期 }; await redis.set(`product:${id}`, JSON.stringify(newData)); } 优势:物理上永不过期,避免集中失效后台异步更新,保证可用性代码复杂度较高,适合核心业务3. 缓存雪崩应对策略(1)差异化过期时间-- 批量设置缓存时添加随机因子 UPDATE products SET cache_time = CASE WHEN is_hot THEN 3600 + FLOOR(RAND() * 600) -- 热门数据加0-10分钟随机 ELSE 1800 + FLOOR(RAND() * 900) -- 普通数据加0-15分钟随机 END; 推荐随机范围:基础TTL ≤ 1小时:±10%随机浮动基础TTL > 1小时:±5%随机浮动(2)多级缓存架构用户请求 → CDN缓存 → Nginx缓存 → Redis集群 → 本地缓存 → 数据库某电商实践数据:接入多级缓存后,数据库QPS下降82%99分位响应时间从340ms降至45ms缓存命中率提升至99.3%(3)服务降级方案# Spring Cloud Gateway配置示例 spring: cloud: gateway: routes: - id: product-service uri: lb://product-service predicates: - Path=/api/products/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 100 # 每秒100个请求 redis-rate-limiter.burstCapacity: 200 # 峰值200 - name: CircuitBreaker args: name: productFallback fallbackUri: forward:/fallback/product三、监控与应急体系1. 核心监控指标指标名称计算方式告警阈值缓存命中率缓存命中数/总请求数<90%穿透请求比例空结果数/总查询数>5%持续5分钟热点key访问占比TOP10 key访问量/总访问量单个key>30%缓存重建耗时平均缓存重建时间>500ms2. 应急处理预案穿透攻击应急:启用IP黑名单(如1分钟内50次无效请求)临时开启全量布隆过滤器降级返回静态默认数据击穿事件处理:手动延长热点key TTL触发缓存预热限流保护后端服务雪崩恢复步骤:逐步重建缓存(按业务优先级)临时启用本地缓存数据库限流保护四、高级架构方案1. 热点探测系统// 基于滑动窗口的热点发现 public class HotKeyDetector { private ConcurrentHashMap<String, LongAdder> counters; private ScheduledExecutorService executor; public void increment(String key) { counters.computeIfAbsent(key, k -> new LongAdder()).increment(); } public void start() { executor.scheduleAtFixedRate(() -> { counters.entrySet().stream() .filter(e -> e.getValue().sum() > 1000) // 阈值 .forEach(e -> notifyHotKey(e.getKey())); counters.clear(); }, 1, 1, TimeUnit.SECONDS); // 每秒统计 } } 2. 自适应缓存策略# 机器学习预测缓存TTL class TTLOptimizer: def __init__(self): self.model = load_model('ttl_predictor.h5') def predict_ttl(self, key, features): # features: 访问频率、时间模式、业务权重等 return self.model.predict(features) # 动态设置缓存 def set_adaptive_cache(key, value): features = extract_features(key) ttl = optimizer.predict_ttl(key, features) redis.setex(key, ttl, value) 3. 混合存储架构 +---------------------+ | Redis Cluster | | (最新热数据) | +----------+----------+ | +----------+----------v----------+----------+ | Tiered Storage Controller | +----------+----------+----------+----------+ | +----------v----------+ | SSD Cache | | (温数据) | +----------+----------+ | +----------v----------+ | Disk Storage | | (冷数据) | +---------------------+ 五、未来演进方向硬件加速:使用FPGA加速布隆过滤器持久内存优化缓存持久化RDMA网络提升集群同步效率AI集成:基于访问模式预测缓存失效智能动态调整TTL异常访问模式识别云原生方案:Kubernetes自动弹性伸缩服务网格集成缓存策略跨云多活缓存同步Redis缓存问题的有效解决需要构建从基础防御到高级预测的完整体系。在实际应用中,建议根据业务特征组合多种方案,并建立完善的监控告警机制。随着技术的持续发展,智能化的缓存管理将成为新的趋势,但理解这些基础问题的本质仍是构建稳健系统的关键。
-
Redis作为高性能的内存数据库,其Pipeline和事务功能是提升吞吐量的利器,但若使用不当反而会导致性能下降甚至数据不一致。本文将深入解析这两大特性的实现原理、适用场景及常见误区,帮助开发者充分发挥Redis的潜能。一、Pipeline:网络延迟的克星1. 核心工作原理Pipeline通过批处理机制将多个命令打包发送,显著减少网络往返时间(RTT)。传统模式下每个命令需要等待响应后才能发送下一个,而Pipeline允许客户端连续发送多个命令,最后一次性读取所有响应。性能对比实验:执行100次SET操作普通模式:100次RTT ≈ 100ms(假设1ms/次)Pipeline模式:1次RTT ≈ 1ms吞吐量提升可达100倍Java(Jedis)实现示例:try (Jedis jedis = jedisPool.getResource()) { Pipeline pipeline = jedis.pipelined(); for (int i = 0; i < 1000; i++) { pipeline.set("key_" + i, "value_" + i); } List<Object> results = pipeline.syncAndReturnAll(); } 2. 关键优化技巧合理分批:单批次命令不宜过多(建议500-1000个)大数据集拆分为多个Pipeline批次集群环境注意:// Redis Cluster需确保所有key在同一个slot String slotKey = "{user123}.cart"; pipeline.hset(slotKey, "item1", "5"); pipeline.hset(slotKey, "item2", "3"); 资源控制:监控内存使用(info memory)避免单个Pipeline占用过多缓冲区二、Redis事务:有限的原子性保障1. 事务特性解析Redis事务通过MULTI/EXEC命令实现,具有三大特点:弱原子性:全部执行或全部不执行,但中间命令错误不会回滚无隔离性:其他客户端能在EXEC前看到中间结果无回滚机制:语法错误时整个事务失败,运行时错误继续执行典型事务流程:MULTI SET user:1:balance 100 INCRBY user:2:balance 100 EXEC 2. 与Pipeline结合的最佳实践性能优化方案:Pipeline pipeline = jedis.pipelined(); pipeline.multi(); // 开启事务 for (OrderItem item : orderItems) { pipeline.hincrBy("inventory", item.getSku(), -item.getQty()); } pipeline.exec(); // 提交事务 List<Object> results = pipeline.syncAndReturnAll(); 注意事项:事务内命令会排队直到EXEC,不宜包含耗时操作WATCH命令可实现乐观锁,但会降低并发度集群模式下事务所有key必须位于同一节点三、常见误区与避坑指南1. Pipeline使用陷阱误区后果解决方案单批次命令过多内存溢出/响应延迟分批处理,每批500-1000命令混合读写操作读操作获取过期数据读写分离,或使用MULTI+EXEC忽略集群限制跨slot执行失败使用hash tag确保同slot2. 事务认知误区“Redis事务像数据库事务”:实际:无回滚、无隔离级别案例:余额扣减成功但积分增加失败不会自动回滚“WATCH能解决所有并发问题”:WATCH user:1:balance balance = GET user:1:balance MULTI SET user:1:balance $(balance - 100) EXEC // 可能因其他修改而失败 高并发场景下重试次数可能暴增“事务一定能提升性能”:实测:纯写场景Pipeline+事务比纯Pipeline慢15-20%仅需原子性时使用事务,纯批处理优先Pipeline四、性能对比与调优数据1. 吞吐量基准测试模式命令数耗时(ms)QPS单命令10,0005,2001,923Pipeline10,00052192,307Pipeline+事务10,00063158,730测试环境:本地Redis 6.2,网络延迟0.1ms2. 内存消耗监控# 监控Pipeline内存 127.0.0.1:6379> INFO memory used_memory_human:1.2G # 执行前 used_memory_human:1.8G # 万级Pipeline执行中 安全阈值建议:单Pipeline内存增长不超过实例maxmemory的5%监控mem_fragmentation_ratio(>1.5需预警)五、典型应用场景1. 电商购物车更新public void batchUpdateCart(String userId, Map<String, Integer> items) { try (Jedis jedis = jedisPool.getResource()) { Pipeline pipeline = jedis.pipelined(); String cartKey = "cart:" + userId; items.forEach((skuId, quantity) -> { if (quantity > 0) { pipeline.hset(cartKey, skuId, quantity.toString()); } else { pipeline.hdel(cartKey, skuId); } }); pipeline.sync(); } } 2. 社交平台计数器# 使用事务保证原子性 WATCH user:1000:followers MULTI INCR user:1000:followers INCRBY user:1000:total_interactions 1 EXEC 3. 游戏排行榜批量更新def update_leaderboard(redis_conn, scores): pipe = redis_conn.pipeline(transaction=False) for player_id, score in scores.items(): pipe.zadd('global_leaderboard', {player_id: score}) pipe.execute() 六、高级技巧与未来演进Lua脚本替代方案:-- 原子性执行复杂逻辑 local current = redis.call('GET', KEYS[1]) if tonumber(current) >= tonumber(ARGV[1]) then return redis.call('DECRBY', KEYS[1], ARGV[1]) end return -1 Redis 7.0新特性:多命令Pipeline响应缓冲客户端缓存优化更精细的内存控制云原生实践:自动扩缩容应对流量峰值基于Prometheus的Pipeline监控Serverless架构下的批处理策略Redis的Pipeline和事务如同双刃剑,合理使用能带来性能的飞跃,滥用则可能导致灾难性后果。建议开发者在实际应用中:优先使用Pipeline优化批量操作仅在需要原子性时引入事务严格监控内存和网络指标针对业务特点进行性能测试通过精准把握这两大特性的适用边界,开发者完全可以构建出既高性能又可靠的Redis应用架构。
-
Redis日志分析:原理、工具与实践指南一、Redis日志概述Redis作为高性能的键值存储系统,其日志系统是监控、调试和性能分析的重要工具。Redis主要生成以下几种日志:服务器日志:记录服务器运行状态、警告和错误信息慢查询日志:记录执行时间超过阈值的命令AOF持久化日志:记录所有写操作命令监控命令输出:通过MONITOR命令获取的实时命令流二、Redis日志配置详解2.1 基础日志配置在redis.conf配置文件中,关键日志参数包括:# 日志级别:debug/verbose/notice/warning loglevel notice # 日志文件路径 logfile "/var/log/redis/redis-server.log" # 是否启用系统日志记录 syslog-enabled no # 系统日志标识 syslog-ident redis2.2 慢查询日志配置# 慢查询阈值(微秒) slowlog-log-slower-than 10000 # 慢查询日志最大长度 slowlog-max-len 128 三、Redis日志分析方法3.1 基础日志分析常见日志模式及含义:[PID] Timestamp # Warning message:警告信息[PID] Timestamp * Background saving started by pid:后台持久化开始[PID] Timestamp * DB loaded from disk:数据库加载完成3.2 慢查询日志分析使用SLOWLOG GET命令获取慢查询记录,分析字段包括:唯一标识符发生时间戳执行时间(微秒)命令及参数3.3 AOF日志分析AOF日志记录了所有写操作命令,可用于:数据恢复操作审计性能分析(通过分析命令频率)四、Redis日志分析工具4.1 内置工具redis-cli monitor:实时监控命令执行redis-cli --latency:检测延迟问题redis-cli --stat:获取关键统计信息4.2 第三方工具RedisInsight:Redis官方可视化工具Logstash:日志收集与分析ELK Stack:完整的日志分析解决方案Grafana+Prometheus:监控与可视化4.3 自定义脚本示例import subprocess import re def analyze_redis_log(logfile): error_pattern = re.compile(r'\[ERROR\]|ERR|failed') warning_pattern = re.compile(r'\[WARNING\]|WARN') with open(logfile, 'r') as f: for line in f: if error_pattern.search(line): print(f"Error detected: {line.strip()}") elif warning_pattern.search(line): print(f"Warning detected: {line.strip()}") analyze_redis_log('/var/log/redis/redis-server.log') 五、常见问题诊断5.1 内存相关问题日志模式:OOM command not allowed when used memory > 'maxmemory'解决方案:增加maxmemory配置优化数据淘汰策略检查内存泄漏5.2 持久化问题日志模式:Background save error或Failed opening .rdb for saving解决方案:检查磁盘空间验证文件权限调整持久化策略5.3 性能问题日志模式:慢查询日志中频繁出现的命令解决方案:优化数据结构使用管道(pipeline)考虑分片六、高级分析技巧6.1 日志时间序列分析使用工具如R或Python pandas分析日志时间分布:import pandas as pd logs = pd.read_csv( 'redis.log', sep='\t', parse_dates=['timestamp'], date_parser=lambda x: pd.to_datetime(x, format='%d %b %Y %H:%M:%S') ) hourly_errors = logs[logs['level'] == 'ERROR'].groupby(logs['timestamp'].dt.hour).size() 6.2 机器学习异常检测使用隔离森林或K-Means算法检测异常日志模式:from sklearn.ensemble import IsolationForest from sklearn.feature_extraction.text import TfidfVectorizer # 将日志文本转换为特征向量 vectorizer = TfidfVectorizer(max_features=100) X = vectorizer.fit_transform(log_messages) # 训练异常检测模型 clf = IsolationForest(contamination=0.01) clf.fit(X) 七、最佳实践建议日志分级:合理配置loglevel,生产环境建议使用notice日志轮转:使用logrotate工具防止日志文件过大敏感信息:避免记录敏感数据,必要时进行脱敏集中管理:在集群环境中使用集中式日志管理系统定期分析:建立定期日志审查机制八、总结Redis日志分析是维护Redis健康运行的重要手段。通过合理配置日志系统、使用适当的分析工具和方法,可以及时发现潜在问题、优化性能并提高系统可靠性。随着Redis应用场景的复杂化,日志分析也需要结合更多自动化工具和高级分析方法,以实现更高效的运维管理。
-
Redis事务概念Redis事务和MySQL的事务在概念上是类似的,都是把一系列操作绑定成一组,让这一组能够批量执行。但是,Redis事务和MySQL事务在特性上有所不同,Redis事务没有回滚机制,只能保证这些操作批量执行,不能做到“一个失败就恢复到初始状态”。Redis 事务本质上是在服务器上搞了⼀个 "事务队列". 每次客⼾端在事务中进⾏⼀个操作, 都会把命令先发给服务器, 放到 "事务队列" 中(但是并不会⽴即执⾏)⽽是会在真正收到 EXEC 命令之后, 才真正执⾏队列中的所有操作. 特性1.弱化的原子性:Redis事务中的所有命令都会序列化、按顺序地执行,执行过程中不会被其他客户端的命令请求打断。但是,Redis事务没有回滚机制。如果事务中的某个命令执行失败,其他命令仍然会继续执行,事务不会因为一个命令的失败而回滚到初始状态。2.不保证一致性:由于Redis事务没有回滚机制,且没有涉及“约束”,因此事务执行过程中如果某个修改操作出现失败,就可能引起不一致的情况。3.不需要隔离性:Redis是单线程处理请求的,因此不需要隔离级别,也不会并发执行事务。4.不需要持久性:Redis事务是保存在内存中的,是否开启持久化是redis-server自己的事情,和事务无关。常用命令MULTI功能:开启一个事务。执行成功返回OK。当开启事务后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中。当EXEC命令被调用时,所有队列中的命令才会被执行。EXEC功能:真正执行事务。每次添加一个操作,都会提示“QUEUED”,说明命令已经进入服务端的队列。当执行EXEC命令时,服务器才会真正执行这些命令。EXEC命令的回复是一个数组,数组中的每个元素都是执行事务中的命令所产生的回复。回复元素的先后顺序和命令发送的先后顺序一致。DISCARD功能:放弃当前事务。直接清空事务队列,之前的操作都不会真正执行。WATCH一定要在开启事务之前使用!!!功能:监控一个或多个键。当开启事务时,如果对WATCH的键进行修改(在EXEC命令执行之前),就会记录当前键的“版本号”。在真正提交事务时(执行EXEC命令时),如果发现当前服务器上的键的版本号已经超过了事务开始时的版本号,就会让事务执行失败。WATCH命令本质上是给EXEC加了个判定条件,属于“乐观锁”。UNWATCH功能:取消对键的监控。相当于WATCH的逆操作。使用演示没开启事务,一方修改,另一方能实时看到 开启事务,一方修改,另一方看不到,直到事务执行完毕 开启事务,一方修改,另一方针对同一Key修改,最终value为执行事务设置的value WATCH只能在开启事务前使用 使用WATCH,开启事务,在事务中修改Key之前,Key被修改,在事务中修改Key,当执行EXEC会提示(nil),Key的value依旧是另一方设置的value 使用场景Redis事务适用于需要把多个操作打包进行的情况。例如,在商品抢购场景中,如果使用Redis事务,可以避免多线程下的线程安全问题。通过Redis事务,可以确保一系列操作(如检查库存、扣减库存等)的原子性执行,从而避免数据不一致的问题。注意事项1.锁的释放:在使用WATCH命令进行乐观锁控制时,需要注意在事务执行完毕后及时释放锁(即取消对键的监控)。如果忘记释放锁或因为异常导致锁无法释放,则可能会导致死锁问题。2.事务的失败处理:由于Redis事务没有回滚机制,因此需要在设计业务逻辑时考虑到事务失败的处理方式。例如,可以通过检查命令的返回值来判断命令是否执行成功,并采取相应的处理措施。3.避免事务过大:如果事务过大(包含过多的命令),可能会导致Redis服务器的性能下降。因此,需要合理控制事务的大小,避免将过多的命令放入一个事务中执行。———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/wmh_1234567/article/details/142964936
-
ZADD添加或者更新指定的元素以及关联的分数到 zset 中,分数应该符合 double 类型,+inf/-inf 作为正负极限也是合法的。语法ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]ZADD 的相关选项:• XX:仅仅⽤于更新已经存在的元素,不会添加新元素。• NX:仅⽤于添加新元素,不会更新已经存在的元素。• CH:默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。• INCR:此时命令类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。时间复杂度:O(log(N))返回值:本次添加成功的元素个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 1 "uno"(integer) 1redis> ZADD myzset 2 "two" 3 "three"(integer) 2redis> ZRANGE myzset 0 -1 WITHSCORES1) "one"2) "1"3) "uno"4) "1"5) "two"6) "2"7) "three"8) "3"ZCARD获取⼀个 zset 的基数(cardinality),即 zset 中的元素个数。语法ZCARD key时间复杂度:O(1)返回值:zset 内的元素个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZCARD myzset(integer) 2ZCOUNT返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。语法ZCOUNT key min max时间复杂度:O(log(N))返回值:满⾜条件的元素列表个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZCOUNT myzset -inf +inf(integer) 3redis> ZCOUNT myzset (1 3(integer) 2ZRANGE返回指定区间⾥的元素,分数按照升序。带上 WITHSCORES 可以把分数也返回。语法ZRANGE key start stop [WITHSCORES]时间复杂度:O(log(N)+M)返回值:区间内的元素列表。举例redis> ZADD myzset 1 "one" 2 "two" 3 "three"(integer) 3redis> ZRANGE myzset 0 -11) "one"2) "two"3) "three"redis> ZRANGE myzset 2 31) "three"redis> ZRANGE myzset -2 -11) "two"2) "three"ZREVRANGE返回指定区间⾥的元素,分数按照降序。带上 WITHSCORES 可以把分数也返回。语法ZREVRANGE key start stop [WITHSCORES]时间复杂度:O(log(N)+M)返回值:区间内的元素列表。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZREVRANGE myzset 0 -11) "three"2) "two"3) "one"redis> ZREVRANGE myzset 2 31) "one"redis> ZREVRANGE myzset -2 -11) "two"2) "one"ZRANGEBYSCORE返回分数在 min 和 max 之间的元素,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。语法ZRANGEBYSCORE key min max [WITHSCORES]时间复杂度:O(log(N)+M)返回值:区间内的元素列表。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZRANGEBYSCORE myzset -inf +inf1) "one"2) "two"3) "three"redis> ZRANGEBYSCORE myzset 1 21) "one"2) "two"redis> ZRANGEBYSCORE myzset (1 21) "two"redis> ZRANGEBYSCORE myzset (1 (2(empty array)ZPOPMAX删除并返回分数最⾼的 count 个元素。语法ZPOPMAX key [count]时间复杂度:O(log(N) * M)返回值:分数和元素列表。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZPOPMAX myzset1) "three"2) "3"BZPOPMAXZPOPMAX 的阻塞版本。语法BZPOPMAX key [key ...] timeout时间复杂度:O(log(N))返回值:元素列表。举例redis> DEL zset1 zset2(integer) 0redis> ZADD zset1 0 a 1 b 2 c(integer) 3redis> BZPOPMAX zset1 zset2 01) "zset1"2) "c"3) "2"ZPOPMIN删除并返回分数最低的 count 个元素。语法ZPOPMIN key [count]时间复杂度:O(log(N) * M)返回值:分数和元素列表。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZPOPMIN myzset1) "one"2) "1"BZPOPMINZPOPMIN 的阻塞版本。语法BZPOPMIN key [key ...] timeout时间复杂度:O(log(N))返回值:元素列表。举例redis> DEL zset1 zset2(integer) 0redis> ZADD zset1 0 a 1 b 2 c(integer) 3redis> BZPOPMIN zset1 zset2 01) "zset1"2) "a"3) "0"ZRANK返回指定元素的排名,升序。语法ZRANK key member时间复杂度:O(log(N))返回值:排名。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZRANK myzset "three"(integer) 2redis> ZRANK myzset "four"(nil)redis> ZRANK myzset "three" WITHSCORE1) (integer) 22) "3"redis> ZRANK myzset "four" WITHSCORE(nil)ZREVRANK返回指定元素的排名,降序。语法ZREVRANK key member时间复杂度:O(log(N))返回值:排名。redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZREVRANK myzset "one"(integer) 2redis> ZREVRANK myzset "four"(nil)redis> ZREVRANK myzset "three" WITHSCORE1) (integer) 02) "3"redis> ZREVRANK myzset "four" WITHSCORE(nil)ZSCORE返回指定元素的分数。语法ZSCORE key member时间复杂度:O(1)返回值:分数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZSCORE myzset "one""1"ZREM删除指定的元素。语法ZREM key member [member ...]时间复杂度:O(M*log(N))返回值:本次操作删除的元素个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZREM myzset "two"(integer) 1redis> ZRANGE myzset 0 -1 WITHSCORES1) "one"2) "1"3) "three"4) "3"ZREMRANGEBYRANK按照排序,升序删除指定范围的元素,左闭右闭。语法ZREMRANGEBYRANK key start stop时间复杂度:O(log(N)+M)返回值:本次操作删除的元素个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZREMRANGEBYRANK myzset 0 1(integer) 2redis> ZRANGE myzset 0 -1 WITHSCORES1) "three"2) "3"ZREMRANGEBYSCORE按照分数删除指定范围的元素,左闭右闭。语法ZREMRANGEBYSCORE key min max时间复杂度:O(log(N)+M)返回值:本次操作删除的元素个数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZADD myzset 3 "three"(integer) 1redis> ZREMRANGEBYSCORE myzset -inf (2(integer) 1redis> ZRANGE myzset 0 -1 WITHSCORES1) "two"2) "2"3) "three"4) "3"ZINCRBY为指定的元素的关联分数添加指定的分数值。语法ZINCRBY key increment member时间复杂度:O(log(N))返回值:增加后元素的分数。举例redis> ZADD myzset 1 "one"(integer) 1redis> ZADD myzset 2 "two"(integer) 1redis> ZINCRBY myzset 2 "one""3"redis> ZRANGE myzset 0 -1 WITHSCORES1) "two"2) "2"3) "one"4) "3"ZINTERSTORE求出给定有序集合中元素的交集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。语法ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]时间复杂度:O(N*K)+O(M*log(M)) N 是输⼊的有序集合中, 最⼩的有序集合的元素个数; K 是输⼊了⼏个有序集合; M 是最终结果的有序集合的元素个数.返回值:⽬标集合中的元素个数。举例redis> ZADD zset1 1 "one"(integer) 1redis> ZADD zset1 2 "two"(integer) 1redis> ZADD zset2 1 "one"(integer) 1redis> ZADD zset2 2 "two"(integer) 1redis> ZADD zset2 3 "three"(integer) 1redis> ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3(integer) 2redis> ZRANGE out 0 -1 WITHSCORES1) "one"2) "5"3) "two"4) "10"ZUNIONSTORE求出给定有序集合中元素的并集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。语法ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]时间复杂度:O(N)+O(M*log(M)) N 是输⼊的有序集合总的元素个数; M 是最终结果的有序集合的元素个数.返回值:⽬标集合中的元素个数。举例redis> ZADD zset1 1 "one"(integer) 1redis> ZADD zset1 2 "two"(integer) 1redis> ZADD zset2 1 "one"(integer) 1redis> ZADD zset2 2 "two"(integer) 1redis> ZADD zset2 3 "three"(integer) 1redis> ZUNIONSTORE out 2 zset1 zset2 WEIGHTS 2 3(integer) 3redis> ZRANGE out 0 -1 WITHSCORES1) "one"2) "5"3) "three"4) "9"5) "two"6) "10"内部编码有序集合类型的内部编码有两种:• ziplist(压缩列表):当有序集合的元素个数⼩于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都⼩于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会⽤ ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使⽤。• skiplist(跳表):当 ziplist 条件不满⾜时,有序集合会使⽤ skiplist 作为内部实现,因为此时ziplist 的操作效率会下降。1)当元素个数较少且每个元素较⼩时,内部编码为 ziplist:127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3(integer) 3127.0.0.1:6379> object encoding zsetkey"ziplist"2)当元素个数超过 128 个,内部编码 skiplist:127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 ... 省略 ... 82 e129(integer) 129127.0.0.1:6379> object encoding zsetkey"skiplist"3)当某个元素⼤于 64 字节时,内部编码 skiplist:127.0.0.1:6379> zadd zsetkey 50 "one string bigger than 64 bytes ... 省略 ..."(integer) 1127.0.0.1:6379> object encoding zsetkey"skiplist”应用场景1.排行榜Zset非常适合用于实现各种排行榜,如游戏内的玩家排名、社交平台的热门帖子排名等。元素可以是玩家的ID或帖子的ID,分数可以是玩家的积分或帖子的点赞数、评论数等。可以使用ZRANGE或ZREVRANGE命令来获取排名前列的元素,或使用ZRANK或ZREVRANK命令来获取特定元素的排名。2.延时队列Zset可以用于实现延时队列,其中元素代表任务,分数代表任务的执行时间戳。通过定期检查Zset中分数最小的元素(即最早应该执行的任务),可以实现任务的定时执行。当任务执行后,可以从Zset中删除该元素。———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/wmh_1234567/article/details/144493484
-
Redis集群是Redis的分布式解决方案,旨在通过多个节点共同工作来提高Redis的稳定性和效率。以下是对Redis集群的详细介绍:一、定义与目的Redis集群通过添加服务器的数量提供相同的服务,从而让服务器达到一个稳定、高效的状态。它主要解决单个Redis实例存在的不稳定性、读写能力有限以及存储容量受限等问题。二、特性可扩展性:Redis集群最多可扩展到1000个节点上,这极大地提高了Redis数据库的可扩展性。可用性:Redis集群继续运行有两个条件,即大多数主节点必须可达,无法达到的主节点必须有一个备份从节点。这一特性有助于提高Redis数据库的可用性。写入安全性:Redis集群尝试以写入安全的方式运行,它将尽量保留与集群中多数主节点连接的任何客户端的写入。数据分片:Redis集群通过在数据库中分片数据来工作。分片是一种数据库分区方案,将数据库中不同的行(在Redis中是键值对)分布到多个节点上,以便每个节点包含一部分数据。这意味着如果一个节点宕机,只有一部分数据将不可用,这将允许许多数据库请求正常进行。主/从架构:Redis集群使用主从复制,以便集群中的每个主节点都有一个备份从节点。如果其中一个主节点失败,相应的从节点可以被指定为新的主节点,对整个集群的影响很小。三、工作原理Redis集群通过哈希槽(Hash Slot)机制实现数据分片存储。每个节点负责一部分哈希槽,当客户端请求数据时,Redis会根据数据的键计算哈希值,并确定该数据所属的哈希槽,然后将请求转发到负责该哈希槽的节点。四、搭建与配置搭建Redis集群需要准备多台服务器或虚拟机,并在每台服务器上安装Redis。然后,为每个节点创建一个独立的配置目录和配置文件,设置集群相关的参数,如cluster-enabled、cluster-config-file、cluster-node-timeout等。最后,使用redis-cli工具创建集群,并将节点之间的关系绑定起来。五、高可用性保障Redis集群的高可用性主要由以下几个方面保障:自动故障转移:当主节点发生故障时,集群会自动提升对应的从节点为新的主节点,保证服务持续可用。数据分片:通过哈希槽机制,数据分散存储在多个节点上,避免单点瓶颈。去中心化架构:Redis集群中没有单点故障,每个节点相互通讯,共同维护集群状态。六、应用场景Redis集群适用于需要高并发、高可用性和大数据存储的分布式系统。例如,热点数据的缓存、限时任务、计数器、分布式锁、排行榜、社交网站的基本功能(如点赞、踩、关注/被关注、共同好友等)以及队列操作等场景都可以使用Redis集群来实现。综上所述,Redis集群是一种高效、可扩展且高可用的分布式数据库解决方案。它通过数据分片、主/从架构和自动故障转移等机制,提供了稳定、可靠的数据存储和服务。
-
当然,Redis 分布式锁是一种常用的解决分布式系统中资源同步访问的方法。以下是一篇关于 Redis 分布式锁的详细指南,包括原理、实现以及注意事项。Redis 分布式锁详解一、引言在分布式系统中,多个进程或线程可能会同时访问和修改共享资源,这会导致数据不一致的问题。为了解决这一问题,分布式锁应运而生。Redis 分布式锁因其高性能和易用性,成为了一种广泛使用的解决方案。二、Redis 分布式锁的原理Redis 分布式锁的实现通常依赖于 Redis 的单线程模型和原子操作。常见的实现方式包括使用 SETNX 命令、SET 命令的 NX 和 EX 选项,以及基于 Lua 脚本的原子操作。2.1 SETNX 命令SETNX 是 Redis 中的一个命令,全称是 “SET if Not eXists”。它用于设置一个键值对,当且仅当该键不存在时才会成功设置,并返回 1;如果键已经存在,则设置失败,返回 0。利用这一特性,我们可以实现一个简单的分布式锁。2.2 SET 命令的 NX 和 EX 选项Redis 2.6.12 版本及以后,SET 命令增加了 NX 和 EX 选项。NX 表示仅在键不存在时设置键,EX 表示设置键的过期时间。通过这两个选项,我们可以一次性完成锁的获取和过期时间的设置,从而简化了分布式锁的实现。2.3 Lua 脚本为了确保分布式锁的原子性,可以使用 Lua 脚本来实现复杂的操作。Lua 脚本在 Redis 中是以原子方式执行的,这保证了脚本中的多个命令在执行过程中不会被其他命令打断。三、Redis 分布式锁的实现以下是一个基于 Redis SET 命令的 NX 和 EX 选项实现的分布式锁示例:3.1 锁获取import redis import uuid import time # 连接到 Redis 服务器 client = redis.StrictRedis(host='localhost', port=6379, db=0) def acquire_lock(lock_name, acquire_timeout=10, lock_timeout=10): identifier = str(uuid.uuid4()) end = time.time() + acquire_timeout while time.time() < end: if client.set(lock_name, identifier, nx=True, px=lock_timeout * 1000): return identifier time.sleep(0.001) return False 在这个示例中,acquire_lock 函数尝试获取一个名为 lock_name 的锁。它生成一个唯一的标识符 identifier,并使用 SET 命令的 NX 和 PX 选项尝试设置锁。如果设置成功,则返回标识符;否则,循环等待直到超时。3.2 锁释放def release_lock(lock_name, identifier): pipe = client.pipeline(True) while True: try: pipe.watch(lock_name) if pipe.get(lock_name) == identifier: pipe.multi() pipe.delete(lock_name) pipe.execute() return True pipe.unwatch() break except redis.exceptions.WatchError: continue return False 在 release_lock 函数中,我们使用 Redis 的事务机制来确保锁的正确释放。通过 WATCH 命令监视锁键,如果锁键的值与我们的标识符匹配,则使用 MULTI 和 EXEC 命令删除锁键。如果在事务执行过程中锁键被其他进程修改,则会引发 WatchError 异常,此时我们重新尝试释放锁。四、注意事项锁过期时间:设置合理的锁过期时间非常重要。如果过期时间太短,可能会导致锁被意外释放;如果过期时间太长,则可能导致资源被长时间占用。续期机制:对于需要长时间持有的锁,可以考虑实现续期机制,即在锁即将过期时重新设置过期时间。这需要在业务逻辑中增加相应的处理。可重入性:上述示例中的锁实现是不可重入的。如果需要可重入锁,可以在锁值中记录获取锁的次数,并在释放锁时根据次数递减。锁释放失败:由于网络或其他原因,锁可能无法被正确释放。为了避免这种情况,可以使用额外的机制(如日志记录、监控等)来检测和清理未释放的锁。Redis 实例的高可用性:如果 Redis 实例发生故障,可能会导致分布式锁失效。因此,在生产环境中,通常需要使用 Redis 集群或主从复制来提高 Redis 的可用性。五、总结Redis 分布式锁是一种高效且易用的解决方案,适用于大多数分布式系统中的资源同步访问场景。通过合理设置锁过期时间、实现续期机制以及注意锁的释放和可重入性等问题,可以确保分布式锁的正确性和可靠性。希望这篇指南对你理解和实现 Redis 分布式锁有所帮助。如果你有任何问题或需要进一步的帮助,请随时提问。
-
用到了华为redis客户端,版本是jedisclient-3.6.3-h0.cbu.mrs.330.r9.jar创建客户端实例JedisCluster,本地和服务器上链接正常,使用docker创建镜像后,只有少数情况下正常,多数情况下都需要16秒才能创建,跟踪代码定位发现在JdisAuth.java中createSaslClient里调用Sasl.createSaslClient需要16秒,jdk换成和服务器正常使用的jdk一样也不行,怀疑可能是网络问题,各位有没有遇到相似问题的,麻烦提供一下指点,非常感谢
-
redis全量+增量迁移(已经在增量中),发现目标实例键数>源实例键数,这是什么情况呢
-
#实惠更实用,跑赢新开局 #华为云618 15+款云原生2.0产品助力应用现代化! Redis、Kafka、RockeMQ、研发工具等新客试用3.96元起 老客户也有专属优惠!下单抽FreeBuds耳机! 更多产品优惠戳:http://t.cn/A6a7JhLQ #华为云 #618促销季
-
#华为云开年采购季#15+云原生产品全场低至3折,新客1.98元起! -Redis低至6折,Kafka、RabbitMQ、RocketMQ等低至5.5折,3年5折! -数字资产链新客119元起,华为链新客19.8元起! -软件开发生产线CodeArts,新客试用1.98元起! -漏洞扫描、二进制成分分析、APP合规检测6.6折起! -Serverless应用引擎CAE,新客试用109元起! -ROMAConnect集成平台,打通新老应用,试用19.8元起! 下单抽FreeBuds无线耳机!更多产品优惠戳:http://t.cn/A6a7JhLQ 活动有效期至2023年3月31日,上云正当时!>点击这里,马上进入活动专场<
-
分布式缓存服务(Distributed Cache Service,简称DCS)是华为云提供的一款内存数据库服务,兼容了Redis和Memcached两种内存数据库引擎,为您提供即开即用、安全可靠、弹性扩容、便捷管理的在线分布式缓存能力,满足用户高并发及数据快速访问的业务诉求。即开即用DCS提供单机、主备、Proxy集群、Cluster集群、读写分离类型的缓存实例,拥有从128M到1024G的丰富内存规格。您可以通过控制台直接创建,无需单独准备服务器资源。其中Redis 4.0、Redis 5.0和Redis 6.0版本采用容器化部署,秒级完成创建。安全可靠借助华为云统一身份认证、虚拟私有云、云监控与云审计等安全管理服务,全方位保护实例数据的存储与访问。灵活的容灾策略,主备/集群实例从单AZ(可用区)内部署,到支持跨AZ部署。弹性伸缩DCS提供对实例内存规格的在线扩容与缩容服务,帮助您实现基于实际业务量的成本控制,达到按需使用的目标。便捷管理可视化Web管理界面,在线完成实例重启、参数修改、数据备份恢复等操作。DCS还提供基于RESTful的管理API,方便您进一步实现实例自动化管理。在线迁移提供可视化Web界面迁移功能,支持备份文件导入和在线迁移两种方式,您可以通过控制台直接创建迁移任务,提高迁移效率。 以下是我们整理的DCS相关资料:分布式缓存服务DCS产品官方文档最新动态_分布式缓存服务 DCS_华为云 (huaweicloud.com)分布式缓存服务DCS功能总览功能总览_分布式缓存服务 DCS_华为云 (huaweicloud.com)分布式缓存服务DCS快速入门快速入门_分布式缓存服务 DCS_华为云 (huaweicloud.com)分布式缓存服务DCS用户指南管理和使用分布式缓存服务_分布式缓存服务 DCS_用户指南_使用前必读_华为云 (huaweicloud.com)分布式缓存服务DCS API参考概述_分布式缓存服务 DCS_API参考_使用前必读_华为云 (huaweicloud.com)华为云分布式缓存服务Redis(DCS),从入门到实践应用,循序渐进一站式学习Redis全景实践课_在线课程_华为云开发者学堂_云计算培训-华为云 (huaweicloud.com)
-
#华为云12·12#全场DevOps与中间件服务3折起,新用户1.98元起,老用户续订7折起!-Redis、Kafka、RabbitMQ、RocketMQ等低至5.5折,3年5折!-数字资产链7折起,区块链新客试用19.8元起!-软件开发生产线CodeArts,新客试用1.98元起!-漏洞扫描、二进制成分分析、APP合规检测6.6折起!下单抽FreeBuds无线耳机!戳连接:http://t.cn/A6a7JhLQ活动有效期至2022年12月31日,上云正当时!>点击这里,马上进入活动专场<
-
828选华为云,实惠更实用!研发与中间件专场全场3折起! Redis、Kafka、数字资产链、软件开发平台,首购低至1.98元! 下单抽FreeBuds耳机,满额送P50手机,助力企业转型云原生2.0! 活动有效期至2022年9月16日,上云正当时!>点击这里,马上进入活动专场<
-
亲爱的开发者们,618年中钜惠来袭!参与试用,100%有礼!最高可得价值899元FreeBuds耳机,满额再送MateBook笔记本!>点击这里,马上进入活动专场<
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签