1.Redis7.0源码阅读:哈希表扩容、码多缩容以及rehash
2.Redis源码解析:一条Redis命令是码多如何执行的?
3.redisåmemcachedçåºå«
4.Redis和Memcached的区别
5.Redis底层数据结构解密?
Redis7.0源码阅读:哈希表扩容、缩容以及rehash
当哈希值相同发生冲突时,码多Redis 码多使用链表法解决,将冲突的码多键值对通过链表连接,但随着数据量增加,码多举报中心源码冲突加剧,码多查找效率降低。码多负载因子衡量冲突程度,码多负载因子越大,码多冲突越严重。码多为优化性能,码多Redis 码多需适时扩容,将新增键值对放入新哈希桶,码多减少冲突。码多
扩容发生在 setCommand 部分,其中 dictKeyIndex 获取键值对索引,判断是否需要扩容。_dictExpandIfNeeded 函数执行扩容逻辑,条件包括:不在 rehash 过程中,哈希表初始大小为0时需扩容,或负载因子大于1且允许扩容或负载因子超过阈值。
扩容大小依据当前键值对数量计算,harmonyos源码获取如哈希表长度为4,实际有9个键值对,扩容至(最小的2的n次幂大于9)。子进程存在时,dict_can_resize 为0,反之为1。fork 子进程用于写时复制,确保持久化操作的稳定性。
哈希表缩容由 tryResizeHashTables 判断负载因子是否小于0.1,条件满足则重新调整大小。此操作在数据库定时检查,且无子进程时执行。
rehash 是为解决链式哈希效率问题,通过增加哈希桶数量分散存储,减少冲突。dictRehash 函数完成这一任务,移动键值对至新哈希表,使用位运算优化哈希计算。渐进式 rehash 通过分步操作,减少响应时间,适应不同负载情况。定时任务检测服务器空闲时,排名指标源码进行大步挪动哈希桶。
在 rehash 过程中,数据查询首先在原始哈希表进行,若未找到,则在新哈希表中查找。rehash 完成后,哈希表结构调整,原始表指向新表,新表内容返回原始表,实现 rehash 结果的整合。
综上所述,Redis 通过哈希表的扩容、缩容以及 rehash 动态调整哈希桶大小,优化查找效率,确保数据存储与检索的高效性。这不仅提高了 Redis 的性能,也为复杂数据存储与管理提供了有力支持。
Redis源码解析:一条Redis命令是如何执行的?
作者:robinhzhang Redis,一个开源内存数据库,凭借其高效能和广泛应用,如缓存、消息队列和会话存储,打标机c 源码本文将带你探索其命令执行的底层流程。本文将以源码解析的形式,逐层深入Redis的核心结构和命令执行过程,旨在帮助开发者理解实现细节,提升编程技术和设计意识。源码结构概览
在学习Redis源代码之前,首先要了解其主要的组成部分:redisServer、redisClient、redisDb、redisObject以及aeEventLoop。这些结构体和事件模型构成了Redis的核心架构。redisServer:服务端运行的核心结构,包括监听socket、数据存储的redisDb列表和客户端连接信息。
redisClient:客户端连接状态的存储,包括命令处理缓冲区、回复数据列表和数据库句柄。
redisDb:键值对的数据存储,采用两个哈希表实现渐进式rehash。
redisObject:存储对象的通用表示,包含引用计数和LRU时间,用于内存管理。怡宝源码
aeEventLoop:事件循环,管理文件和时间事件的处理。
核心流程详解
Redis的执行流程从main函数开始,首先初始化配置和服务器组件,进入主循环处理事件。命令执行流程涉及redis启动、客户端连接、接收命令和返回结果四个步骤:启动阶段:创建socket服务器,注册可读事件,进入主循环。
连接阶段:客户端连接后,接收并处理命令,创建客户端实例。
命令阶段:客户端发送命令,服务端解析并调用对应的命令处理函数。
结果阶段:处理命令后,根据协议格式构建回复并写回客户端。
渐进式rehash与内存管理
Redis的内存管理采用引用计数法,通过对象的refcount字段控制内存分配和释放。rehash操作在Redis 2.x版本引入,通过逐步迁移键值对,降低对单线程性能的影响。当负载达到阈值,会进行扩容,这涉及新表的创建和键值对的迁移。总结
本文通过Redis源码分析,揭示了其命令执行的细节,包括启动流程、客户端连接、命令处理和结果返回,以及内存管理策略。这将有助于开发者深入理解Redis的工作原理,提升编程效率和设计决策能力。redisåmemcachedçåºå«
Redisçä½è Salvatore Sanfilippoæ¾ç»å¯¹è¿ä¸¤ç§åºäºå åçæ°æ®åå¨ç³»ç»è¿è¡è¿æ¯è¾ï¼1ãRedisæ¯ææå¡å¨ç«¯çæ°æ®æä½ï¼Redisç¸æ¯Memcachedæ¥è¯´ï¼æ¥ææ´å¤çæ°æ®ç»æå并æ¯ææ´ä¸°å¯çæ°æ®æä½ï¼é常å¨Memcachedéï¼ä½ éè¦å°æ°æ®æ¿å°å®¢æ·ç«¯æ¥è¿è¡ç±»ä¼¼çä¿®æ¹åsetåå»ãè¿å¤§å¤§å¢å äºç½ç»IOç次æ°åæ°æ®ä½ç§¯ãå¨Redisä¸ï¼è¿äºå¤æçæä½é常åä¸è¬çGET/SETä¸æ ·é«æãæ以ï¼å¦æéè¦ç¼åè½å¤æ¯ææ´å¤æçç»æåæä½ï¼é£ä¹Redisä¼æ¯ä¸éçéæ©ã
2ãå å使ç¨æç对æ¯ï¼ä½¿ç¨ç®åçkey-valueåå¨çè¯ï¼Memcachedçå åå©ç¨çæ´é«ï¼èå¦æRediséç¨hashç»ææ¥åkey-valueåå¨ï¼ç±äºå ¶ç»åå¼çå缩ï¼å ¶å åå©ç¨çä¼é«äºMemcachedã
3ãæ§è½å¯¹æ¯ï¼ç±äºRedisåªä½¿ç¨åæ ¸ï¼èMemcachedå¯ä»¥ä½¿ç¨å¤æ ¸ï¼æ以平åæ¯ä¸ä¸ªæ ¸ä¸Rediså¨åå¨å°æ°æ®æ¶æ¯Memcachedæ§è½æ´é«ãèå¨k以ä¸çæ°æ®ä¸ï¼Memcachedæ§è½è¦é«äºRedisï¼è½ç¶Redisæè¿ä¹å¨åå¨å¤§æ°æ®çæ§è½ä¸è¿è¡ä¼åï¼ä½æ¯æ¯èµ·Memcachedï¼è¿æ¯ç¨æéè²ã
å ·ä½ä¸ºä»ä¹ä¼åºç°ä¸é¢çç»è®ºï¼ä»¥ä¸ä¸ºæ¶éå°çèµæï¼
1ãæ°æ®ç±»åæ¯æä¸å
ä¸Memcachedä» æ¯æç®åçkey-valueç»æçæ°æ®è®°å½ä¸åï¼Redisæ¯æçæ°æ®ç±»åè¦ä¸°å¯å¾å¤ãæ为常ç¨çæ°æ®ç±»å主è¦ç±äºç§ï¼StringãHashãListãSetåSorted SetãRediså é¨ä½¿ç¨ä¸ä¸ªredisObject对象æ¥è¡¨ç¤ºææçkeyåvalueãredisObjectæ主è¦çä¿¡æ¯å¦å¾æ示ï¼
type代表ä¸ä¸ªvalueå¯¹è±¡å ·ä½æ¯ä½ç§æ°æ®ç±»åï¼encodingæ¯ä¸åæ°æ®ç±»åå¨rediså é¨çåå¨æ¹å¼ï¼æ¯å¦ï¼type=string代表valueåå¨çæ¯ä¸ä¸ªæ®éå符串ï¼é£ä¹å¯¹åºçencodingå¯ä»¥æ¯rawæè æ¯intï¼å¦ææ¯intå代表å®é rediså é¨æ¯ææ°å¼åç±»åå¨å表示è¿ä¸ªå符串çï¼å½ç¶åææ¯è¿ä¸ªå符串æ¬èº«å¯ä»¥ç¨æ°å¼è¡¨ç¤ºï¼æ¯å¦:ââ³ ââè¿æ ·çå符串ãåªææå¼äºRedisçèæå ååè½ï¼vmå段å段æä¼çæ£çåé å åï¼è¯¥åè½é»è®¤æ¯å ³éç¶æçã
1ï¼String
常ç¨å½ä»¤ï¼set/get/decr/incr/mgetçï¼
åºç¨åºæ¯ï¼Stringæ¯æ常ç¨çä¸ç§æ°æ®ç±»åï¼æ®éçkey/valueåå¨é½å¯ä»¥å½ä¸ºæ¤ç±»ï¼
å®ç°æ¹å¼ï¼Stringå¨rediså é¨åå¨é»è®¤å°±æ¯ä¸ä¸ªå符串ï¼è¢«redisObjectæå¼ç¨ï¼å½éå°incrãdecrçæä½æ¶ä¼è½¬ææ°å¼åè¿è¡è®¡ç®ï¼æ¤æ¶redisObjectçencodingå段为intã
2ï¼Hash
常ç¨å½ä»¤ï¼hget/hset/hgetallç
åºç¨åºæ¯ï¼æ们è¦åå¨ä¸ä¸ªç¨æ·ä¿¡æ¯å¯¹è±¡æ°æ®ï¼å ¶ä¸å æ¬ç¨æ·IDãç¨æ·å§åãå¹´é¾åçæ¥ï¼éè¿ç¨æ·IDæ们å¸æè·å该ç¨æ·çå§åæè å¹´é¾æè çæ¥ï¼
å®ç°æ¹å¼ï¼RedisçHashå®é æ¯å é¨åå¨çValue为ä¸ä¸ªHashMapï¼å¹¶æä¾äºç´æ¥ååè¿ä¸ªMapæåçæ¥å£ãå¦å¾æ示ï¼Keyæ¯ç¨æ·ID, valueæ¯ä¸ä¸ªMapãè¿ä¸ªMapçkeyæ¯æåçå±æ§åï¼valueæ¯å±æ§å¼ãè¿æ ·å¯¹æ°æ®çä¿®æ¹åååé½å¯ä»¥ç´æ¥éè¿å ¶å é¨MapçKey(Redisé称å é¨Mapçkey为field), ä¹å°±æ¯éè¿ key(ç¨æ·ID) + field(å±æ§æ ç¾) å°±å¯ä»¥æä½å¯¹åºå±æ§æ°æ®ãå½åHashMapçå®ç°æ两ç§æ¹å¼ï¼å½HashMapçæåæ¯è¾å°æ¶Redis为äºèçå åä¼éç¨ç±»ä¼¼ä¸ç»´æ°ç»çæ¹å¼æ¥ç´§ååå¨ï¼èä¸ä¼éç¨çæ£çHashMapç»æï¼è¿æ¶å¯¹åºçvalueçredisObjectçencoding为zipmapï¼å½æåæ°éå¢å¤§æ¶ä¼èªå¨è½¬æçæ£çHashMap,æ¤æ¶encoding为htã
3ï¼List
常ç¨å½ä»¤ï¼lpush/rpush/lpop/rpop/lrangeçï¼
åºç¨åºæ¯ï¼Redis listçåºç¨åºæ¯é常å¤ï¼ä¹æ¯Redisæéè¦çæ°æ®ç»æä¹ä¸ï¼æ¯å¦twitterçå ³æ³¨å表ï¼ç²ä¸å表çé½å¯ä»¥ç¨Redisçlistç»ææ¥å®ç°ï¼
å®ç°æ¹å¼ï¼Redis listçå®ç°ä¸ºä¸ä¸ªååé¾è¡¨ï¼å³å¯ä»¥æ¯æååæ¥æ¾åéåï¼æ´æ¹ä¾¿æä½ï¼ä¸è¿å¸¦æ¥äºé¨åé¢å¤çå åå¼éï¼Rediså é¨çå¾å¤å®ç°ï¼å æ¬åéç¼å²éåçä¹é½æ¯ç¨çè¿ä¸ªæ°æ®ç»æã
4ï¼Set
常ç¨å½ä»¤ï¼sadd/spop/smembers/sunionçï¼
åºç¨åºæ¯ï¼Redis set对å¤æä¾çåè½ä¸list类似æ¯ä¸ä¸ªå表çåè½ï¼ç¹æ®ä¹å¤å¨äºsetæ¯å¯ä»¥èªå¨æéçï¼å½ä½ éè¦åå¨ä¸ä¸ªå表æ°æ®ï¼åä¸å¸æåºç°éå¤æ°æ®æ¶ï¼setæ¯ä¸ä¸ªå¾å¥½çéæ©ï¼å¹¶ä¸setæä¾äºå¤ææ个æåæ¯å¦å¨ä¸ä¸ªsetéåå çéè¦æ¥å£ï¼è¿ä¸ªä¹æ¯listæä¸è½æä¾çï¼
å®ç°æ¹å¼ï¼set çå é¨å®ç°æ¯ä¸ä¸ª valueæ°¸è¿ä¸ºnullçHashMapï¼å®é å°±æ¯éè¿è®¡ç®hashçæ¹å¼æ¥å¿«éæéçï¼è¿ä¹æ¯setè½æä¾å¤æä¸ä¸ªæåæ¯å¦å¨éåå çåå ã
5ï¼Sorted Set
常ç¨å½ä»¤ï¼zadd/zrange/zrem/zcardçï¼
åºç¨åºæ¯ï¼Redis sorted setç使ç¨åºæ¯ä¸set类似ï¼åºå«æ¯setä¸æ¯èªå¨æåºçï¼èsorted setå¯ä»¥éè¿ç¨æ·é¢å¤æä¾ä¸ä¸ªä¼å 级(score)çåæ°æ¥ä¸ºæåæåºï¼å¹¶ä¸æ¯æå ¥æåºçï¼å³èªå¨æåºãå½ä½ éè¦ä¸ä¸ªæåºç并ä¸ä¸éå¤çéåå表ï¼é£ä¹å¯ä»¥éæ©sorted setæ°æ®ç»æï¼æ¯å¦twitter çpublic timelineå¯ä»¥ä»¥å表æ¶é´ä½ä¸ºscoreæ¥åå¨ï¼è¿æ ·è·åæ¶å°±æ¯èªå¨ææ¶é´æ好åºçã
å®ç°æ¹å¼ï¼Redis sorted setçå é¨ä½¿ç¨HashMapåè·³è·è¡¨(SkipList)æ¥ä¿è¯æ°æ®çåå¨åæåºï¼HashMapéæ¾çæ¯æåå°scoreçæ å°ï¼èè·³è·è¡¨éåæ¾çæ¯ææçæåï¼æåºä¾æ®æ¯HashMapéåçscore,使ç¨è·³è·è¡¨çç»æå¯ä»¥è·å¾æ¯è¾é«çæ¥æ¾æçï¼å¹¶ä¸å¨å®ç°ä¸æ¯è¾ç®åã
2ãå å管çæºå¶ä¸å
å¨Redisä¸ï¼å¹¶ä¸æ¯ææçæ°æ®é½ä¸ç´åå¨å¨å åä¸çãè¿æ¯åMemcachedç¸æ¯ä¸ä¸ªæ大çåºå«ãå½ç©çå åç¨å®æ¶ï¼Rediså¯ä»¥å°ä¸äºå¾ä¹ 没ç¨å°çvalue交æ¢å°ç£çãRedisåªä¼ç¼åææçkeyçä¿¡æ¯ï¼å¦æRedisåç°å åç使ç¨éè¶ è¿äºæä¸ä¸ªéå¼ï¼å°è§¦åswapçæä½ï¼Redisæ ¹æ®âswappability = age*log(size_in_memory)â计ç®åºåªäºkey对åºçvalueéè¦swapå°ç£çãç¶ååå°è¿äºkey对åºçvalueæä¹ åå°ç£çä¸ï¼åæ¶å¨å åä¸æ¸ é¤ãè¿ç§ç¹æ§ä½¿å¾Rediså¯ä»¥ä¿æè¶ è¿å ¶æºå¨æ¬èº«å å大å°çæ°æ®ãå½ç¶ï¼æºå¨æ¬èº«çå åå¿ é¡»è¦è½å¤ä¿æææçkeyï¼æ¯ç«è¿äºæ°æ®æ¯ä¸ä¼è¿è¡swapæä½çãåæ¶ç±äºRediså°å åä¸çæ°æ®swapå°ç£çä¸çæ¶åï¼æä¾æå¡ç主线ç¨åè¿è¡swapæä½çå线ç¨ä¼å ±äº«è¿é¨åå åï¼æ以å¦ææ´æ°éè¦swapçæ°æ®ï¼Rediså°é»å¡è¿ä¸ªæä½ï¼ç´å°å线ç¨å®æswapæä½åæå¯ä»¥è¿è¡ä¿®æ¹ãå½ä»Redisä¸è¯»åæ°æ®çæ¶åï¼å¦æ读åçkey对åºçvalueä¸å¨å åä¸ï¼é£ä¹Rediså°±éè¦ä»swapæ件ä¸å è½½ç¸åºæ°æ®ï¼ç¶ååè¿åç»è¯·æ±æ¹ã è¿éå°±åå¨ä¸ä¸ªI/O线ç¨æ± çé®é¢ãå¨é»è®¤çæ åµä¸ï¼Redisä¼åºç°é»å¡ï¼å³å®æææçswapæ件å è½½åæä¼ç¸åºãè¿ç§çç¥å¨å®¢æ·ç«¯çæ°éè¾å°ï¼è¿è¡æ¹éæä½çæ¶åæ¯è¾åéãä½æ¯å¦æå°Redisåºç¨å¨ä¸ä¸ªå¤§åçç½ç«åºç¨ç¨åºä¸ï¼è¿æ¾ç¶æ¯æ æ³æ»¡è¶³å¤§å¹¶åçæ åµçãæ以Redisè¿è¡æ们设置I/O线ç¨æ± ç大å°ï¼å¯¹éè¦ä»swapæ件ä¸å è½½ç¸åºæ°æ®ç读å请æ±è¿è¡å¹¶åæä½ï¼åå°é»å¡çæ¶é´ã
对äºåRedisåMemcachedè¿ç§åºäºå åçæ°æ®åºç³»ç»æ¥è¯´ï¼å å管ççæçé«ä½æ¯å½±åç³»ç»æ§è½çå ³é®å ç´ ãä¼ ç»Cè¯è¨ä¸çmalloc/freeå½æ°æ¯æ常ç¨çåé åéæ¾å åçæ¹æ³ï¼ä½æ¯è¿ç§æ¹æ³åå¨çå¾å¤§ç缺é·ï¼é¦å ï¼å¯¹äºå¼å人åæ¥è¯´ä¸å¹é çmallocåfree容æé æå åæ³é²ï¼å ¶æ¬¡é¢ç¹è°ç¨ä¼é æ大éå åç¢çæ æ³åæ¶éæ°å©ç¨ï¼éä½å åå©ç¨çï¼æåä½ä¸ºç³»ç»è°ç¨ï¼å ¶ç³»ç»å¼éè¿è¿å¤§äºä¸è¬å½æ°è°ç¨ãæ以ï¼ä¸ºäºæé«å åç管çæçï¼é«æçå å管çæ¹æ¡é½ä¸ä¼ç´æ¥ä½¿ç¨malloc/freeè°ç¨ãRedisåMemcachedå使ç¨äºèªèº«è®¾è®¡çå å管çæºå¶ï¼ä½æ¯å®ç°æ¹æ³åå¨å¾å¤§çå·®å¼ï¼ä¸é¢å°ä¼å¯¹ä¸¤è çå å管çæºå¶åå«è¿è¡ä»ç»ã
Memcachedé»è®¤ä½¿ç¨Slab Allocationæºå¶ç®¡çå åï¼å ¶ä¸»è¦ææ³æ¯æç §é¢å è§å®ç大å°ï¼å°åé çå ååå²æç¹å®é¿åº¦çå以åå¨ç¸åºé¿åº¦çkey-valueæ°æ®è®°å½ï¼ä»¥å®å ¨è§£å³å åç¢çé®é¢ãSlab Allocationæºå¶åªä¸ºåå¨å¤é¨æ°æ®è设计ï¼ä¹å°±æ¯è¯´ææçkey-valueæ°æ®é½åå¨å¨Slab Allocationç³»ç»éï¼èMemcachedçå ¶å®å å请æ±åéè¿æ®éçmalloc/freeæ¥ç³è¯·ï¼å 为è¿äºè¯·æ±çæ°éåé¢çå³å®äºå®ä»¬ä¸ä¼å¯¹æ´ä¸ªç³»ç»çæ§è½é æå½±åSlab Allocationçåçç¸å½ç®åã å¦å¾æ示ï¼å®é¦å ä»æä½ç³»ç»ç³è¯·ä¸å¤§åå åï¼å¹¶å°å ¶åå²æåç§å°ºå¯¸çåChunkï¼å¹¶æ尺寸ç¸åçååæç»Slab Classãå ¶ä¸ï¼Chunkå°±æ¯ç¨æ¥åå¨key-valueæ°æ®çæå°åä½ãæ¯ä¸ªSlab Classç大å°ï¼å¯ä»¥å¨Memcachedå¯å¨çæ¶åéè¿å¶å®Growth Factoræ¥æ§å¶ãåå®å¾ä¸Growth Factorçåå¼ä¸º1.ï¼å¦æ第ä¸ç»Chunkç大å°ä¸ºä¸ªåèï¼ç¬¬äºç»Chunkç大å°å°±ä¸ºä¸ªåèï¼ä¾æ¤ç±»æ¨ã
å½Memcachedæ¥æ¶å°å®¢æ·ç«¯åéè¿æ¥çæ°æ®æ¶é¦å ä¼æ ¹æ®æ¶å°æ°æ®ç大å°éæ©ä¸ä¸ªæåéçSlab Classï¼ç¶åéè¿æ¥è¯¢Memcachedä¿åçç该Slab Classå 空é²Chunkçå表就å¯ä»¥æ¾å°ä¸ä¸ªå¯ç¨äºåå¨æ°æ®çChunkãå½ä¸æ¡æ°æ®åºè¿ææè 丢å¼æ¶ï¼è¯¥è®°å½æå ç¨çChunkå°±å¯ä»¥åæ¶ï¼éæ°æ·»å å°ç©ºé²å表ä¸ãä»ä»¥ä¸è¿ç¨æ们å¯ä»¥çåºMemcachedçå å管çå¶æçé«ï¼èä¸ä¸ä¼é æå åç¢çï¼ä½æ¯å®æ大ç缺ç¹å°±æ¯ä¼å¯¼è´ç©ºé´æµªè´¹ãå 为æ¯ä¸ªChunké½åé äºç¹å®é¿åº¦çå å空é´ï¼æ以åé¿æ°æ®æ æ³å åå©ç¨è¿äºç©ºé´ãå¦å¾ æ示ï¼å°ä¸ªåèçæ°æ®ç¼åå°ä¸ªåèçChunkä¸ï¼å©ä½ç个åè就浪费æäºã
Redisçå å管ç主è¦éè¿æºç ä¸zmalloc.håzmalloc.c两个æ件æ¥å®ç°çãRedis为äºæ¹ä¾¿å åç管çï¼å¨åé ä¸åå åä¹åï¼ä¼å°è¿åå åç大å°åå ¥å ååç头é¨ãå¦å¾æ示ï¼real_ptræ¯redisè°ç¨mallocåè¿åçæéãrediså°å ååç大å°sizeåå ¥å¤´é¨ï¼sizeæå æ®çå å大å°æ¯å·²ç¥çï¼ä¸ºsize_tç±»åçé¿åº¦ï¼ç¶åè¿året_ptrãå½éè¦éæ¾å åçæ¶åï¼ret_ptrè¢«ä¼ ç»å å管çç¨åºãéè¿ret_ptrï¼ç¨åºå¯ä»¥å¾å®¹æçç®åºreal_ptrçå¼ï¼ç¶åå°real_pträ¼ ç»freeéæ¾å åã
Rediséè¿å®ä¹ä¸ä¸ªæ°ç»æ¥è®°å½ææçå ååé æ åµï¼è¿ä¸ªæ°ç»çé¿åº¦ä¸ºZMALLOC_MAX_ALLOC_STATãæ°ç»çæ¯ä¸ä¸ªå ç´ ä»£è¡¨å½åç¨åºæåé çå ååç个æ°ï¼ä¸å ååç大å°ä¸ºè¯¥å ç´ çä¸æ ãå¨æºç ä¸ï¼è¿ä¸ªæ°ç»ä¸ºzmalloc_allocationsãzmalloc_allocations[]代表已ç»åé çé¿åº¦ä¸ºbytesçå ååç个æ°ãzmalloc.cä¸æä¸ä¸ªéæåéused_memoryç¨æ¥è®°å½å½ååé çå åæ»å¤§å°ãæ以ï¼æ»çæ¥çï¼Rediséç¨çæ¯å è£ çmallc/freeï¼ç¸è¾äºMemcachedçå å管çæ¹æ³æ¥è¯´ï¼è¦ç®åå¾å¤ã
3ãæ°æ®æä¹ åæ¯æ
Redisè½ç¶æ¯åºäºå åçåå¨ç³»ç»ï¼ä½æ¯å®æ¬èº«æ¯æ¯æå åæ°æ®çæä¹ åçï¼èä¸æä¾ä¸¤ç§ä¸»è¦çæä¹ åçç¥ï¼RDBå¿«ç §åAOFæ¥å¿ãèmemcachedæ¯ä¸æ¯ææ°æ®æä¹ åæä½çã
1ï¼RDBå¿«ç §
Redisæ¯æå°å½åæ°æ®çå¿«ç §åæä¸ä¸ªæ°æ®æ件çæä¹ åæºå¶ï¼å³RDBå¿«ç §ãä½æ¯ä¸ä¸ªæç»åå ¥çæ°æ®åºå¦ä½çæå¿«ç §å¢ï¼Redisåå©äºforkå½ä»¤çcopy on writeæºå¶ãå¨çæå¿«ç §æ¶ï¼å°å½åè¿ç¨forkåºä¸ä¸ªåè¿ç¨ï¼ç¶åå¨åè¿ç¨ä¸å¾ªç¯ææçæ°æ®ï¼å°æ°æ®åæ为RDBæ件ãæ们å¯ä»¥éè¿Redisçsaveæ令æ¥é ç½®RDBå¿«ç §çæçæ¶æºï¼æ¯å¦é ç½®åéå°±çæå¿«ç §ï¼ä¹å¯ä»¥é ç½®æ次åå ¥å°±çæå¿«ç §ï¼ä¹å¯ä»¥å¤ä¸ªè§åä¸èµ·å®æ½ãè¿äºè§åçå®ä¹å°±å¨Redisçé ç½®æ件ä¸ï¼ä½ ä¹å¯ä»¥éè¿RedisçCONFIG SETå½ä»¤å¨Redisè¿è¡æ¶è®¾ç½®è§åï¼ä¸éè¦éå¯Redisã
RedisçRDBæ件ä¸ä¼åæï¼å ä¸ºå ¶åæä½æ¯å¨ä¸ä¸ªæ°è¿ç¨ä¸è¿è¡çï¼å½çæä¸ä¸ªæ°çRDBæ件æ¶ï¼Redisçæçåè¿ç¨ä¼å å°æ°æ®åå°ä¸ä¸ªä¸´æ¶æ件ä¸ï¼ç¶åéè¿ååæ§renameç³»ç»è°ç¨å°ä¸´æ¶æ件éå½å为RDBæ件ï¼è¿æ ·å¨ä»»ä½æ¶ååºç°æ éï¼RedisçRDBæ件é½æ»æ¯å¯ç¨çãåæ¶ï¼RedisçRDBæ件ä¹æ¯Redis主ä»åæ¥å é¨å®ç°ä¸çä¸ç¯ãRDBæä»çä¸è¶³ï¼å°±æ¯ä¸æ¦æ°æ®åºåºç°é®é¢ï¼é£ä¹æ们çRDBæ件ä¸ä¿åçæ°æ®å¹¶ä¸æ¯å ¨æ°çï¼ä»ä¸æ¬¡RDBæ件çæå°Redisåæºè¿æ®µæ¶é´çæ°æ®å ¨é¨ä¸¢æäºãå¨æäºä¸å¡ä¸ï¼è¿æ¯å¯ä»¥å¿åçã
2ï¼AOFæ¥å¿
AOFæ¥å¿çå ¨ç§°æ¯append only fileï¼å®æ¯ä¸ä¸ªè¿½å åå ¥çæ¥å¿æ件ãä¸ä¸è¬æ°æ®åºçbinlogä¸åçæ¯ï¼AOFæ件æ¯å¯è¯å«ç纯ææ¬ï¼å®çå 容就æ¯ä¸ä¸ªä¸ªçRedisæ åå½ä»¤ãåªæé£äºä¼å¯¼è´æ°æ®åçä¿®æ¹çå½ä»¤æä¼è¿½å å°AOFæ件ãæ¯ä¸æ¡ä¿®æ¹æ°æ®çå½ä»¤é½çæä¸æ¡æ¥å¿ï¼AOFæ件ä¼è¶æ¥è¶å¤§ï¼æ以Redisåæä¾äºä¸ä¸ªåè½ï¼å«åAOF rewriteãå ¶åè½å°±æ¯éæ°çæä¸ä»½AOFæ件ï¼æ°çAOFæ件ä¸ä¸æ¡è®°å½çæä½åªä¼æä¸æ¬¡ï¼èä¸åä¸ä»½èæ件é£æ ·ï¼å¯è½è®°å½äºå¯¹åä¸ä¸ªå¼çå¤æ¬¡æä½ãå ¶çæè¿ç¨åRDB类似ï¼ä¹æ¯forkä¸ä¸ªè¿ç¨ï¼ç´æ¥éåæ°æ®ï¼åå ¥æ°çAOF临æ¶æ件ãå¨åå ¥æ°æ件çè¿ç¨ä¸ï¼ææçåæä½æ¥å¿è¿æ¯ä¼åå°åæ¥èçAOFæ件ä¸ï¼åæ¶è¿ä¼è®°å½å¨å åç¼å²åºä¸ãå½éå®æä½å®æåï¼ä¼å°ææç¼å²åºä¸çæ¥å¿ä¸æ¬¡æ§åå ¥å°ä¸´æ¶æ件ä¸ãç¶åè°ç¨ååæ§çrenameå½ä»¤ç¨æ°çAOFæ件å代èçAOFæ件ã
AOFæ¯ä¸ä¸ªåæ件æä½ï¼å ¶ç®çæ¯å°æä½æ¥å¿åå°ç£çä¸ï¼æ以å®ä¹åæ ·ä¼éå°æ们ä¸é¢è¯´çåæä½çæµç¨ãå¨Redisä¸å¯¹AOFè°ç¨writeåå ¥åï¼éè¿appendfsyncé项æ¥æ§å¶è°ç¨fsyncå°å ¶åå°ç£çä¸çæ¶é´ï¼ä¸é¢appendfsyncçä¸ä¸ªè®¾ç½®é¡¹ï¼å®å ¨å¼ºåº¦éæ¸å强ã
appendfsync no å½è®¾ç½®appendfsync为noçæ¶åï¼Redisä¸ä¼ä¸»å¨è°ç¨fsyncå»å°AOFæ¥å¿å 容åæ¥å°ç£çï¼æ以è¿ä¸åå°±å®å ¨ä¾èµäºæä½ç³»ç»çè°è¯äºã对大å¤æ°Linuxæä½ç³»ç»ï¼æ¯æ¯ç§è¿è¡ä¸æ¬¡fsyncï¼å°ç¼å²åºä¸çæ°æ®åå°ç£çä¸ã
appendfsync everysec å½è®¾ç½®appendfsync为everysecçæ¶åï¼Redisä¼é»è®¤æ¯éä¸ç§è¿è¡ä¸æ¬¡fsyncè°ç¨ï¼å°ç¼å²åºä¸çæ°æ®åå°ç£çãä½æ¯å½è¿ä¸æ¬¡çfsyncè°ç¨æ¶é¿è¶ è¿1ç§æ¶ãRedisä¼éå延è¿fsyncççç¥ï¼åçä¸ç§éãä¹å°±æ¯å¨ä¸¤ç§ååè¿è¡fsyncï¼è¿ä¸æ¬¡çfsyncå°±ä¸ç®¡ä¼æ§è¡å¤é¿æ¶é´é½ä¼è¿è¡ãè¿æ¶åç±äºå¨fsyncæ¶æ件æ述符ä¼è¢«é»å¡ï¼æ以å½åçåæä½å°±ä¼é»å¡ãæ以ç»è®ºå°±æ¯ï¼å¨ç»å¤§å¤æ°æ åµä¸ï¼Redisä¼æ¯éä¸ç§è¿è¡ä¸æ¬¡fsyncãå¨æåçæ åµä¸ï¼ä¸¤ç§éä¼è¿è¡ä¸æ¬¡fsyncæä½ãè¿ä¸æä½å¨å¤§å¤æ°æ°æ®åºç³»ç»ä¸è¢«ç§°ä¸ºgroup commitï¼å°±æ¯ç»åå¤æ¬¡åæä½çæ°æ®ï¼ä¸æ¬¡æ§å°æ¥å¿åå°ç£çã
appednfsync always å½è®¾ç½®appendfsync为alwaysæ¶ï¼æ¯ä¸æ¬¡åæä½é½ä¼è°ç¨ä¸æ¬¡fsyncï¼è¿æ¶æ°æ®æ¯æå®å ¨çï¼å½ç¶ï¼ç±äºæ¯æ¬¡é½ä¼æ§è¡fsyncï¼æä»¥å ¶æ§è½ä¹ä¼åå°å½±åã
对äºä¸è¬æ§çä¸å¡éæ±ï¼å»ºè®®ä½¿ç¨RDBçæ¹å¼è¿è¡æä¹ åï¼åå æ¯RDBçå¼é并ç¸æ¯AOFæ¥å¿è¦ä½å¾å¤ï¼å¯¹äºé£äºæ æ³å¿æ°æ®ä¸¢å¤±çåºç¨ï¼å»ºè®®ä½¿ç¨AOFæ¥å¿ã
4ãé群管ççä¸å
Memcachedæ¯å ¨å åçæ°æ®ç¼å²ç³»ç»ï¼Redisè½ç¶æ¯ææ°æ®çæä¹ åï¼ä½æ¯å ¨å åæ¯ç«ææ¯å ¶é«æ§è½çæ¬è´¨ãä½ä¸ºåºäºå åçåå¨ç³»ç»æ¥è¯´ï¼æºå¨ç©çå åç大å°å°±æ¯ç³»ç»è½å¤å®¹çº³çæ大æ°æ®éãå¦æéè¦å¤ççæ°æ®éè¶ è¿äºåå°æºå¨çç©çå å大å°ï¼å°±éè¦æ建åå¸å¼é群æ¥æ©å±åå¨è½åã
Memcachedæ¬èº«å¹¶ä¸æ¯æåå¸å¼ï¼å æ¤åªè½å¨å®¢æ·ç«¯éè¿åä¸è´æ§åå¸è¿æ ·çåå¸å¼ç®æ³æ¥å®ç°Memcachedçåå¸å¼åå¨ãä¸å¾ç»åºäºMemcachedçåå¸å¼åå¨å®ç°æ¶æãå½å®¢æ·ç«¯åMemcachedé群åéæ°æ®ä¹åï¼é¦å ä¼éè¿å ç½®çåå¸å¼ç®æ³è®¡ç®åºè¯¥æ¡æ°æ®çç®æ èç¹ï¼ç¶åæ°æ®ä¼ç´æ¥åéå°è¯¥èç¹ä¸åå¨ãä½å®¢æ·ç«¯æ¥è¯¢æ°æ®æ¶ï¼åæ ·è¦è®¡ç®åºæ¥è¯¢æ°æ®æå¨çèç¹ï¼ç¶åç´æ¥å该èç¹åéæ¥è¯¢è¯·æ±ä»¥è·åæ°æ®ã
ç¸è¾äºMemcachedåªè½éç¨å®¢æ·ç«¯å®ç°åå¸å¼åå¨ï¼Redisæ´ååäºå¨æå¡å¨ç«¯æ建åå¸å¼åå¨ãææ°çæ¬çRediså·²ç»æ¯æäºåå¸å¼åå¨åè½ãRedis Clusteræ¯ä¸ä¸ªå®ç°äºåå¸å¼ä¸å 许åç¹æ éçRedisé«çº§çæ¬ï¼å®æ²¡æä¸å¿èç¹ï¼å ·æ线æ§å¯ä¼¸ç¼©çåè½ãä¸å¾ç»åºRedis Clusterçåå¸å¼åå¨æ¶æï¼å ¶ä¸èç¹ä¸èç¹ä¹é´éè¿äºè¿å¶åè®®è¿è¡éä¿¡ï¼èç¹ä¸å®¢æ·ç«¯ä¹é´éè¿asciiåè®®è¿è¡éä¿¡ãå¨æ°æ®çæ¾ç½®çç¥ä¸ï¼Redis Clusterå°æ´ä¸ªkeyçæ°å¼ååæ个åå¸æ§½ï¼æ¯ä¸ªèç¹ä¸å¯ä»¥åå¨ä¸ä¸ªæå¤ä¸ªåå¸æ§½ï¼ä¹å°±æ¯è¯´å½åRedis Clusteræ¯æçæ大èç¹æ°å°±æ¯ãRedis Cluster使ç¨çåå¸å¼ç®æ³ä¹å¾ç®åï¼crc( key ) % HASH_SLOTS_NUMBERã
为äºä¿è¯åç¹æ éä¸çæ°æ®å¯ç¨æ§ï¼Redis Clusterå¼å ¥äºMasterèç¹åSlaveèç¹ãå¨Redis Clusterä¸ï¼æ¯ä¸ªMasterèç¹é½ä¼æ对åºç两个ç¨äºåä½çSlaveèç¹ãè¿æ ·å¨æ´ä¸ªé群ä¸ï¼ä»»æ两个èç¹çå®æºé½ä¸ä¼å¯¼è´æ°æ®çä¸å¯ç¨ãå½Masterèç¹éåºåï¼é群ä¼èªå¨éæ©ä¸ä¸ªSlaveèç¹æ为æ°çMasterèç¹ã
Redis和Memcached的区别
Redis和Memcached是两种基于内存的高性能数据存储系统,它们在多个方面具有不同特点。以下将从网络IO模型、数据支持类型、内存管理机制、数据存储及持久化、数据一致性问题以及集群管理等角度,详细比较两者的主要区别。
网络IO模型方面,Memcached采用多线程模型进行非阻塞IO复用,通过libevent封装的事件库实现。虽然这种模型可以充分利用多核资源,但也引入了cache coherency和锁问题,比如在执行stats命令时需要对全局变量加锁,影响性能。相比之下,Redis使用单线程IO复用模型,利用封装的AeEvent事件处理框架,优化了IO调度,对单存操作有速度优势,但当涉及计算操作时,单线程模型可能会限制整体吞吐量。
数据支持类型上,Memcached仅支持简单的key-value形式存储,而Redis在提供key-value支持的同时,还具备更丰富数据结构,如list、set、zset和hash等,这使得Redis在处理复杂数据逻辑时更灵活。
在内存管理机制上,Memcached采用Slab Allocation机制管理内存,将内存分割成特定长度的块以存储相应长度的key-value数据记录,有效地解决了内存碎片问题。Redis则采用源码封装的内存管理机制,通过记录分配情况的数组和内存头部存储大小信息,实现内存块管理,相对简单高效。两者在内存使用效率上有不同侧重点,Memcached在不造成内存碎片的同时可能带来空间浪费,而Redis的内存管理虽简单但可能产生内存碎片。
数据存储及持久化方面,Memcached不支持数据持久化,所有数据均保存在内存中。Redis则支持持久化操作,通过快照(snapshotting)或只追加文件(AOF)两种方法将数据存储到硬盘,提供了数据恢复的可能。
数据一致性问题上,Memcached通过cas命令保证多并发访问同一数据时的一致性,而Redis未提供cas命令,但可通过事务功能实现命令原子性,避免被其他操作打断。
集群管理方面,Memcached依赖客户端通过分布式算法实现集群存储,客户端查询数据同样需计算目标节点。Redis则倾向于在服务器端构建分布式存储,最新版本的Redis支持分布式存储功能,采用Redis Cluster实现线性可伸缩的分布式架构,节点间通过二进制协议通信,支持自动故障转移,保证数据可用性。
综上所述,Redis相较于Memcached在数据结构、持久化能力、集群管理等方面有更多优势,但两者根据具体应用场景和需求选择,各有其适用场景。
Redis底层数据结构解密?
一:摘要概述
很多 redis 的使用者都可以清晰明白的道出Redis中常用的对象如string、list、hash、set、zset,一些场景比较丰富的使用者可能会说布隆过滤器、geo、Hash等。但是对于这些对象底层实现的数据结构却是知之甚少,将会详细阐述redis中的底层数据结构。为了弥补大家的创伤,今天分享Redis底层数据结构内容。
二:SDS
string作为redis中常用对象之一,普遍用于用户信息缓存等场景。当string对象中encoding编码为embstr或raw时都是采用sds作为其底层实现
2.1 SDS结构
源码文件位于redis安装目录src下的sds.h,sds声明了五种头部类型,分别为sdshdr5、sdshdr8、sdshdr、sdshdr、sdshdr。根据字符串长度创建不同头部的sds实例
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len;
uint8_t alloc;
unsigned char flags;
char buf[];
};
属性名称作用含义
len字符串长度
alloc预分配空间大小
flags低三位用于表示sds类型,可以查看sds.h文件-行定义
buf[]存储字符串用数组
2.2 SDS与C字符串区别
区别描述
长度计算 c中的字符串长度计算需要数组遍历,但是redis中的sds自身维护了len属性。所以O(1)时间复杂度即可
缓冲区溢出c中字符串更改如果未提前做好内存分配则会内存溢出,但是sds则会根据alloc与len计算预留内存是否足够分配重新申请内存
动态扩展 缓冲区溢出已经阐述这个概念,sds的内存空间会在字符串内容变更时自动扩展计算。策略为当字符换小于1M时*2翻倍,大于1M时每次扩容1M
惰性释放 与空间预分配相似操作的还有内存惰性释放,即字符串删除某些内容后所占用的内存空间并不会立即释放,后续字符串变更扩展就无需再申请内存
二:ZipList
ziplist可以说把redis对于内存的极致操作体现的淋漓尽致,链表除了节点值之外还需要维护前后节点两个指针,并且还会造成内存碎片。压缩列表紧凑的内存布局,所有节点都维护在整块内存中处理
2.1 ZipList结构
属性名称作用含义
zlbytes列表健占用内存的总字节数,在对列表健内存重分配或者是计算zlend的时候使用
zltail 指向压缩列表起始地址的指针
zllen 压缩列表的节点数量
entry压缩列表保存的节点数据
zlend压缩列表的尾节点
2.2 Entry节点结构
属性名称作用含义
previous_entry_length 字节为单位记录上一个节点的长度,如果上一个字节长度小于占用1字节。大于占用5字节,第一个字节设置为OxFE(十进制),后面四个字节储存长度
encoding 记录content记录的数据类型以及长度。长度一、二、五字节,值的最高位为、、表示类型为字节数组,长度使用除去最高位的其它位记录。开头表示储存整数,除去最高位其他位置表示content数据长度
content 记录压缩列表记录的数据