老板们都应该学一学 Redis,它能管理上亿对象,你们呢?

女生学java怎么样?女孩子学java会不会很难? 不少男性开发者认为“女性水平比较低,也就做做测试”,这是男性领导者经常说的一句话,虽然此话含有其个人经验和行业经验,但我们并不完全认同。 女生学java怎么样 女生学java是一个很好的选择,因为女性比男性有着独特的优势,就这个行业而言: 一是女性在细心和耐力方面比男性表现得更为突出; 二是在技术管理方面女性更有优势。 现在的研发项目中很少是个人独立去做一件事情。多数是需要团队合作的。通常那些技术非常好的人,在对团队的管理及项目管理方面却是表现很一般。因为在管理中,沟通和协调是要素,这正是女性 阅读详情

我们知道一个大型的公司往往都具有复杂的组织结构,成百上千号员工,要做到大而不乱,就必须依靠合理的组织结构来优化内部的交流成本。Redis 内部也有组织结构,不同的是这个组织结构要维系上亿的对象,而不是几百几千。今天我来向大家呈现 Redis 如何来管理这上亿的对象而不会混乱的。

640?wx_fmt=jpeg
图片

Redis 的对象很多,但是对象的种类却是有限的,目前一共只有7种对象。

#define OBJ_STRING 0    /* String object. */
#define OBJ_LIST 1      /* List object. */
#define OBJ_SET 2       /* Set object. */
#define OBJ_ZSET 3      /* Sorted set object. */
#define OBJ_HASH 4      /* Hash object. */
#define OBJ_MODULE 5    /* Module object. */
#define OBJ_STREAM 6    /* Stream object. */

看到这里,肯定会要很多人要举手表示抗议!老钱啊,你这不对啊,HyperLogLog 哪里去了?Geo 哪里去了?

这个问题提的非常棒!其实这个问题是我在写这篇文章的时候自己向自己提出的,我在问这个问题的时候,我也不知道为什么,我只是隐约觉得上面这三种高级数据结构在Redis内部应该是混合使用了上面的基础数据结构,也就是说他们是复合数据结构。但是我需要求证,于是我阅读了一下源码证实了我的猜测。

HyperLogLog 和 Bitmap 一样,使用的是一个普通的动态字符串,而 Geo 使用的是 zset。还有一个奇妙的地方就是当你使用 pfadd 构造出来的计数器对象可以直接使用字符串命令将它的内部全部显示出来。

127.0.0.1:6379> pfadd codehole python java golang
(integer) 1
127.0.0.1:6379> get codehole
"HYLL\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80C\x03\x84MK\x80P\xb8\x80^\xf3"

同样你也可以使用 zset 相关的指令将 geo 的内容显示出来

127.0.0.1:6379> GEOADD city 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> zrange city 0 -1 withscores
1) "Palermo"
2) "3479099956230698"
3) "Catania"
4) "3479447370796909"

这个问题算是回答完了,接下来我再提出一个问题,平时我们听的「跳跃列表 skiplist」,「压缩列表 ziplist」、「快速列表 quicklist」跟对象类型什么关系?

为了回答这个问题,接下来要引入 Redis 的对象结构。Redis 所有的对象都有一个相同的「头结构」,头部结构中有一个指针指向各自不同的「体结构」。

typedef struct redisObject {
    unsigned type:4; // 对象类型
    unsigned encoding:4; // 对象编码
    unsigned lru:24; // LRU时间戳
    int refcount; // 引用计数
    void *ptr; // 指向体结构的指针
} robj;

我们注意到 type 字段只有 4bit,最多只能表示 16 个对象类型,这大概是为什么对象类型要省着用的原因,太浪费了以后就不好扩展了。

我们还注意到有一个 encoding 字段,它也是 4 个位,它代表的是对象的内部结构类型。Redis 为了节约内存,在集合对象比较小时,采用特殊结构进行存储。比如hash对象在内部 key 很少 (size<512) 并且 value 值较短 (len<64) 的时候采用 ziplist 进行存储,超过了这个数量就使用标准的 hashtable 存储。

Type是对外统一接口是形象,Encoding是对内具体实现是骨肉。

我们翻翻源码来看看 encoding 都有哪些

#define OBJ_ENCODING_RAW 0  // 可修改的长字符串
#define OBJ_ENCODING_INT 1 // 整型字符串
#define OBJ_ENCODING_HT 2 // hashtable
#define OBJ_ENCODING_ZIPMAP 3 // 压缩map,已经废弃不用,改用ziplist
#define OBJ_ENCODING_LINKEDLIST 4 // 双向链表,已废弃不用,改用quicklist
#define OBJ_ENCODING_ZIPLIST 5 // 压缩列表
#define OBJ_ENCODING_INTSET 6 // 整数集合,个数少全是整数的set
#define OBJ_ENCODING_SKIPLIST 7 // 跳跃列表,zset的标准内部结构
#define OBJ_ENCODING_EMBSTR 8 // 只读短字符串
#define OBJ_ENCODING_QUICKLIST 9 // 快速列表,存储list
#define OBJ_ENCODING_STREAM 10 // 流

看到这里我开始有点当心,encoding 只有 4bit,但是已经用掉了 11 个值,以后要是扩展改怎么办?这个问题这里就不好回答了,大家可以自己讨论。

Type和Encoding的对应关系如下

1. string  ==> raw|embstr|int
2. list ==> quicklist
3. hash ==> ziplist|hashtable
4. set ==> intset|hashtable
5. zset ==> ziplist|skiplist
6. stream => stream

接下来我们要开始深入内部结构了,将每一个结构都过一遍,限于篇幅,不能讲的太详细。

第一个我们要讲的是字典,因为它太重要了,Redis 对象树的主干就是字典结构,key 是对象的名称,value 是各种不同的对象,所有的对象都挂在一棵字典上。除了容纳所有对象的主干字典外,还有容纳所有带过期时间的对象的过期主干字典,它的 key 是对象的名称,value 是对象的过期时间戳。

typedef struct redisDb {
    dict *dict;
    dict *expires;
    ...
} redisDb;

字典的 value 呈现出了多态性,它可以是一个单纯的整数或者浮点数,也可以是一个对象,会有一个统一的对象头,也就是前面的 redisObject 结构体,会根据 type 字段和 encoding 字段来决定 ptr 字段指向的具体数据结构。我们来看一下字典的结构体代码定义

// dict
typedef struct dict {
    dictType *type; // 字典的接口实现,为字典带来多态性
    void *privdata; // 存储字典的附加信息
    dictht ht[2]; // 注意这里不是指向指针的数组,为什么?
    long rehashidx; // 渐进式rehash时记录当前rehash的位置
    unsigned long iterators;
} dict;

// dict hashtable
typedef struct dictht {
    dictEntry **table; // 指向第一维数组
    unsigned long size; // 数组的长度
    unsigned long sizemask; // 用于快速hash定位 sizemask = size - 1
    unsigned long used; // 数组中的元素个数
} dictht;

// 定义了字典功能的接口
typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

// key-value wrapper
typedef struct dictEntry {
    void *key;
    union {
        void *val; // sds|set|dict|zset|quicklist
        uint64_t u64; // 用于过期字典,val存储过期时间戳
        int64_t s64; // Don't watch me!
        double d; // 用于zset,存储score值
    } v;
    struct dictEntry *next;
} dictEntry;

字典结构的内部实现是两个 hashtable,为什么是两个 hashtable 呢,这个涉及到字典的渐进式扩容和所容,我们后再讲。通常情况下,我们只会使用到ht[0],一个单纯的 hashtable

640?wx_fmt=other
图片

我们看看 hashtable 的内部结构。hashtable 的结构和 Java 语言的 HashMap 初级版是一样的,为什么说初级版本呢,因为 Java8 对 HashMap 做了改造,在 hash 不均匀的时候做了复杂的优化处理,至于具体的优化方法,这里我就不做详细解释了,感兴趣可以搜索相关资料。

我们看下字典的内部结构,它是一个二维的

640?wx_fmt=other
图片

查找过程如下,为了方便阅读,我仔细去掉了额外的需要考虑「渐进式迁移」的部分代码

dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    uint64_t h, idx, table;

    if (d->ht[0].used == 0) return NULL; /* dict is empty */
    h = dictHashKey(d, key); // 计算hash值
    idx = h & d->ht[0].sizemask; // 定位数组位置
    he = d->ht[0].table[idx]; // 获取链表表头
    while(he) {
        if (key==he->key || dictCompareKeys(d, key, he->key))
            return he; // 找到了就返回
        he = he->next; // 找不到继续遍历
    }
    return NULL;
}

其中 dictHashKey 和 dictCompareKeys 会分别调用相应字典的多态函数

#define dictHashKey(d, key) (d)->type->hashFunction(key)
#define dictCompareKeys(d, key1, key2) \
    (((d)->type->keyCompare) ? \
        (d)->type->keyCompare((d)->privdata, key1, key2) : \
        (key1) == (key2))

需要注意到定位数组用的是按位操作,这是因为字典的第一维数组的长度都会 2^n 。对于 2^n 长度的数组来说,对数组长度的取模操作等价于按位操作

sizemask = size - 1;
idx = h & d->ht[0].sizemask ==> idx = h % d->ht[0].size

我们在使用 Java 的 HashMap 时会当心如果对象的 hashcode 不均匀,会导致链表长度差别较大,个别链表会特别长,对性能就会产生较大影响。所以 Java8 对 HashMap 的链表进行了适当的改造,如果链表的长度超过 8,就会转变成一颗红黑树,用于提升查找效率。

那为什么 Redis 不需要考虑这点呢?

这是因为 Java 的 HashMap 容纳的 key 对象是不可控的,它可以是任意对象,如果对象的 hashCode 方法返回的数值不均匀就会带来性能问题。

但是 Redis 的字典容纳的 key 都是 sds 动态字符串,它的 hashCode 是均匀的可控的,Redis的内置 hash(siphash) 算法可以保证字符串的 hash 值非常均匀。

接下来我们谈谈字典的扩容。

在 Java 的 HashMap 里面,扩容是申请一个新的数组,这个数组是旧数组的两倍大小,然后一次性将旧数组下面挂接的所有元素一次性全部迁移到新数组中。如果字典中元素特别多,扩容会比较消耗计算资源,也就是通常所说的「卡顿」。

Redis 内存里可以容纳的对象会上亿,这些对象是使用字典组织起来的。如果 Redis 字典的扩容策略和 Java 的 HashMap 一样,这样庞大的字典肯定也会遭遇「卡顿问题」。

Redis 为了解决这个问题,它使用了渐进式迁移策略。当字典需要扩容时,它会申请一个新的 hashtable 放在字典的 ht[1] 中,在迁移完成之前新旧两个 hashtable 将会共存,也就是 ht[1] 和 ht[0] 两个字段值同时存在。

int dictExpand(dict *d, unsigned long size)
{
    if (dictIsRehashing(d) || d->ht[0].used > size)
        return DICT_ERR;

    dictht n;
    unsigned long realsize = _dictNextPower(size);

    if (realsize == d->ht[0].size) return DICT_ERR;

    // 分配一个新的hashtable
    n.size = realsize;
    n.sizemask = realsize - 1;
    n.table = zcalloc(realsize*sizeof(dictEntry*));
    n.used = 0;

    // 如果是空字典的第一次扩容,那就挂到ht[0]上
    if (d->ht[0].table == NULL) {
        d->ht[0] = n;
        return DICT_OK;
    }

    // 挂在ht[1]上,准备进行渐进式迁移
    d->ht[1] = n;
    d->rehashidx = 0;
    return DICT_OK;
}

在后续该字典的每个指令中,Redis都会将旧 hashtable 的一部分键值对迁移到新的 hashtable 中。目前渐进式迁移每次迁移 10 个槽位,也就是最多 10 个链表,平均一个链表的长度大约是 1。看到这里我不禁要当心一个大型的字典需要渐进式迁移多少次才能完成。如果没有了后续的读写操作,是不是就永远无法迁移完成了呢?这个读者可以继续思考。

当 Redis 中积累了上亿个对象时,这颗对象树的主干是一个字典,这个字典是非常大的,它也需要扩容。如果这个渐进式扩容的时间比较漫长,Redis 的每个指令都需要进行渐进式迁移,势必会持续影响整体的性能,而且内存会长期处于一个比较高的冗余状态。

所以 Redis 对于这个主干字典采取了定期主动迁移法,每隔 1ms 都会执行渐进式迁移,每次迁移不超过 1ms,以免导致正常的指令卡顿。

// 渐进式rehash,最多持续时间ms
int dictRehashMilliseconds(dict *d, int ms) {
    long long start = timeInMilliseconds();
    int rehashes = 0;

    // 每次执行100步(每步10个槽位),停下来看看时间,如果超出时间就中断
    while(dictRehash(d,100)) {
        rehashes += 100;
        if (timeInMilliseconds()-start > ms) break;
    }
    return rehashes;
}

// 对指定db进行渐进式rehash
// 优先迁移所有对象的主干字典,再考虑过期对象字典
int incrementallyRehash(int dbid) {
    if (dictIsRehashing(server.db[dbid].dict)) {
        dictRehashMilliseconds(server.db[dbid].dict,1);
        return 1;
    }

    if (dictIsRehashing(server.db[dbid].expires)) {
        dictRehashMilliseconds(server.db[dbid].expires,1);
        return 1;
    }
    return 0;
}

同时如果 Redis 正在进行 bgsave 或者 bgaofrewrite 开启子进程来执行持久化操作时,需要遍历整颗对象树。为了避免父子进程过多的页面分离出来拉高整体内存占用,在这两条指令执行时,尽量不执行字典的扩容 dict_can_resize = false,除非字典已经特别拥挤,这个拥挤程度的阈值默认是 dict_force_resize_ratio = 5,也就是字典元素的个数相对第一维数组的长度的比例。

static int _dictExpandIfNeeded(dict *d)
{
    // 如果正在执行渐进式rehash,那就暂时不要扩容
    if (dictIsRehashing(d)) return DICT_OK;

    // 如果是空字典,那就进行第一次扩容
    if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);

    // 综合考虑字典的拥挤程度以及实例是否处于bgsave/bgaofrewrite
    // 来决定是否进行扩容
    if(dict_can_resize ||
         d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
    {
        return dictExpand(d, d->ht[0].used*2);
    }
    return DICT_OK;
}

有关字典的内容就讲到这里,下一篇我们继续看看字典里面容纳的 key 。字典的 key 放的都是字符串,所以下一篇我们要讲的内容是字符串的内部结构,敬请期待。

本文节选之掘金在线技术小册《Redis 深度历险》,对 Redis 感兴趣请点击「阅读原文」继续深入阅读《Redis 深度历险》

640?wx_fmt=jpeg

阅读更多深度技术文章,扫一扫上面的二维码关注微信公众号「码洞」

Redis万能指南:每一个应用场景背后,都藏着架构的智慧 有时候面试官没想为难你,但Redis这道题真能看出你到底是“用过”还是“会用”。今天,我来给你讲讲那次Redis救了我系统的故事。 阅读详情

相关推荐

Redis:06---数据库管理

一、服务器中的数据库Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个...

yolo模型训练找我,AI游戏合作找我 285

Redis精通系列——LFU算法详述(Least Frequently Used - 最不经常使用)

本文已收录于专栏 ❤️《Redis精通系列》❤️ 上千人点赞收藏,全套Redis学习资料,大厂必备技能! 目录 1、简介 2、实现方式 2.1 LRU实现方式 2.2 LFU实现方式 3、LFU使用 3.1 配置文件开启LFU淘汰算法 1、简介 LRU有一个明显的缺点,它无法正确的表示一个Key的热度,如果一个key从未被访问过,仅仅发生内存淘汰的前一会儿被用户访问了一下,在LRU算法中这会被认为是一个热key。 例如如下图,keyA与keyB同时被set到Redis中,在内存淘汰..

Java框架、并发编程、分布式、微服务、Redis、HarmonyOS、中间件等技术 5182

DOTween回调函数的隐藏技巧:优化你的Unity动画流程

本文深入探讨了DOTween回调函数在Unity动画开发中的高级应用技巧,帮助开发者优化动画流程。通过分析回调机制、链式应用模式和大规模动画系统管理,提升性能与可维护性,特别适合需要高效处理复杂动画场景的Unity开发者。

weixin_27945229的博客 319

渐进式rehash

redis的渐进式rehash

weixin_44474209的博客 1419

三维荧光光谱(EEM)散射干扰实战:从识别到精准切除的完整流程

本文详细解析三维荧光光谱(EEM)中散射干扰的识别与精准切除流程,涵盖瑞利散射和拉曼散射的实战处理技巧。通过drEEM工具箱的应用示例和高级场景解决方案,帮助研究者有效消除散射干扰,提升数据准确性,特别适用于环境样品和生物活体样本分析。

weixin_42554042的博客 330

Overleaf-Latex-Elsevier-图、表、参考文献标题及引用、伪代码写法(绝对详细直观且易懂)

overleaf爱思唯尔模板踩过的一些坑以及解决办法

2403_87584552的博客 5851

Redis篇--数据结构篇8--Redis数据结构架构篇(全局键空间,key存储结构,值存储结构,对象头)

字典(Dictionary):Redis使用字典来存储键值对。字典是一个键到值的映射结构,支持快速查找、插入和删除操作。- 哈希表(Hash Table):字典的底层实现是哈希表。每个哈希表由多个桶(bucket)组成,每个桶可以存储多个键值对。为了减少哈希冲突,Redis使用了拉链法(Separate Chaining),即当多个键的哈希值相同(发生冲突)时,它们会被存储在一个链表中。- 渐进式 rehash:为了应对哈希表扩展或收缩时的性能问题,Redis实现了渐进式rehash。

weisian的博客 3万+

电赛备赛笔记:用STM32驱动AD9959信号发生器模块,从接线到出波保姆级教程

本文详细介绍了如何使用STM32驱动AD9959信号发生器模块,从硬件接线到软件调试的全流程。AD9959作为高性能DDS芯片,适用于电子设计竞赛中的信号生成需求。文章包含硬件连接指南、寄存器配置解析、多通道控制技巧以及常见问题解决方案,帮助参赛者快速掌握AD9959的应用。

weixin_31858171的博客 368

【Redis原理】底层数据结构 && 五种数据类型

Redis底层数据结构 && 五种数据类型

Suk_god的博客 1254

Android Camera性能优化概述

做camera性能优化方面的工作有几年了,想写一篇文章简单介绍一下其中涉及到的具体技术,这篇文章会大概介绍一下涉及到的技术。

weixin_42136255的博客 4027

【博文汇总】I2C总线学习

将这一周学习I2C总线的文章汇总一下。 基础知识学习 触发器的建立时间和保持时间 如何学习总线技术 TTL电平和CMOS电平 深入理解 关于I2C和SPI总线协议 I2C总线深入浅出 I2C总线信号时序总结 对I2C总线协议的一些理解 对I2C总线的时钟同步和总线仲裁的深入理解 I2C总线学习终结,开始SPI总线的学习 深入理解IIC总线时序

ce123的技术博客 6216

【无标题】

redis数据结构:动态字符串SDS,IntSet整数集合,Dict 字典,ZipList压缩表,QuickList

weqeqwef的博客 376

基于STM32设计的水下水质检测装置(微信小程序)(205)

本项目设计了一款基于STM32微控制器为核心的水下水质检测设备,该设备具有高度集成化、智能化的特点,能够实时监测水深、温度、浊度及溶解性总固体(TDS)等关键水质参数,并通过4G网络将数据上传至腾讯云IOT物联网平台,实现远程监控和数据分析。同时,为了便于操作和移动观测,还配套开发了微信小程序,用户可通过微信小程序实时查看并控制设备的各项功能,如调整下潜深度等。

1253

[Redis#10] scan | db_0 | redis_cli | RESP | C++-redis启动教程

这篇博文探讨了 Redis的渐进式遍历、数据库管理技巧,以及如何在Ubuntu环境下使用C++操作Redis。内容覆盖了从基础命令如`scan`到高级主题如自定义RESP协议,并介绍相关工具安装步骤。

No Game No Life 1646

彻底讲透 SAP 中的 client-safe:从 CDS、AMDP 到 ABAP Cloud 的客户端隔离设计

SAP系统中的client-safe概念定义了技术边界:访问client-dependent数据的对象必须确保只看到单个client数据,而访问client-independent数据的对象则天然满足条件。这一原则直接影响CDS视图、AMDP等核心组件,并与ABAP Cloud开发模型紧密集成。在业务系统中,client isolation要求用户只能看到当前登录client的数据。SAP通过语言版本、对象规则和静态检查强制执行这一约束,特别是在ABAP Cloud开发中,AMDP方法和发布的API必须满足

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3270

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

redis数据结构之字符串

你以为Redis的字符串就是"Hello World"?今天咱们要掀开这位"字符串精分患者"的三重人格面具,准备好瓜子饮料,老司机带你飙车Redis字符串的魔幻底层世界!(温馨提示:阅读本文可能会引起颅内高潮,请系好安全带)

2401_89221867的博客 961

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

2024年Java最全女生学java怎么样?女孩子学java会不会很难?,用Elasticsearch搞定日均1亿订单查询

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!对于很多Java工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

2401_84585372的博客 999

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

看完老板哭着让我留下来!mysql删除数据库所有表

华为Java一面· 1H 闲聊偏多,问的技术性问题比较基础 ·简单说说面向对象的特征以及六大原则 ·谈谈final、finally、finalize的区别 ·Java中==、equals与hashCode的区别和联系 ·谈谈Java容器ArrayList、LinkedList、·HashMap、HashSet的理解,以及应用场景 ·谈谈线程的基本状态,其中的wait() sleep() yield()方法的区别。 华为Java二面 · 0.5H 问题深入一些,开始加难度

m0_57501529的博客 137

你连分布式+并发+Redis+JVM+Redis都讲不清楚,老板凭什么给你升职加薪呢?

关于程序员,除了做项目来提高自身的技术之外,还有一种提升自己的专业技能就是:多!看!书! 技术更新太快了,你在学校或者其他公司可能是个佼佼者,总是受人追捧,但是有可能一毕业或者你跳槽所学的技术就又更新了,如果你不继续保持学习,过个1~2年,你可能就被淘汰了。就像你还没有学习而别人可能已经早就会Mysql了 程序不可能一帆风顺,如果有这个时候,那么你可能在做梦,总会遇到各种各样的问题,难道你每次遇到问题都张口问“哪个大牛,来帮我看看这个程序什么问题吧,怎么老是提示错误呢?”...... 其他原因就不.

如果频繁就私信一下呢 501

Redis的基本数据类型以及作用

Redis(Remote Dictionary Server)是一个开源的、高性能的键值存储系统,常被用作数据库、缓存和消息中间件。除此以外Redis还包括LUA脚本,不同的持久化策略以及事务等等一般在我们实际的生产环境当中我们一般就是不会将Redis作为数据库而是会将它作为缓存来进行使用,那么我们都知道缓存就是放一些我们常用的信息然后能够就不需要直接访问数据库了,提高了整体的一个的性能二.Redis的优点对于缓存而言就是说一定是要高性能以及高并发。

2201_75397629的博客 1399

揭秘Redis性能优化:5大技巧让你面试加分!

Redis性能优化的关键在于内存使用、高并发处理和持久化配置。常见的性能瓶颈包括内存溢出、锁竞争和网络延迟。通过合理的数据结构选择、分片架构设计以及高效的序列化方案,可以显著提升系统吞吐量和响应速度。本文将深入探讨这些问题,并提供实际场景下的优化策略与解决方案,帮助企业最大化Redis的性能表现。

蓝鲸鱼计算机软件开发工作室 853

别再用 BGSAVE 敷衍了事!生产环境 Redis 备份恢复的血泪实战指南

本文分享了Redis备份恢复的实战经验与教训。作者通过真实事故案例指出RDB快照作为单一备份方式的不足,强调生产级备份需满足异地存储、可验证恢复和多时间点保留三个条件。文章详细介绍了四重保障策略:开启AOF日志、定时BGSAVE并上传对象存储、保留7天历史数据、定期恢复演练。针对灾难恢复场景,提供了从下载备份到数据迁移的完整流程,并总结了备份过程中的常见陷阱。最后强调备份是流程问题而非技术问题,建议建立自动化验证体系以确保数据安全。

qq_31815769的博客 398

java用户管理系统_老板面试了一个6年的Java,竟然什么都不会

老板面试了一个6年的Java,竟然什么都不会最近看了很多简历,很多候选人年限不小,但是做的都是一些非常传统的项目,想着也不能通过简历就直接否定一个人,何况现在大环境越来 越难,大家找工作也不容易,于是就打算见一见。在沟通中发现,由于年限不小,他们的定位基本都是高级及以上,毕竟,年限摆在那里,面个中级也不体面。面试时我打算聊点基础的,先打开一下话题,结果发现对于一些开发中很基本的问题,比如:Git的...

weixin_39603327的博客 153

Spring Boot会话管理:从Cookie到Redis分布式Session

HTTP协议本身是无状态的,Web应用需要通过会话状态管理来记住用户身份。Session作为服务端数据仓库,依赖Cookie在浏览器与服务器间传递会话标识;而Token则以签名凭证的方式实现无状态认证。在分布式部署场景下,单机内存Session无法跨实例共享,Redis分布式会话成为主流方案。理解Session、Cookie、Token的差异,掌握Spring Boot中的会话管理、拦截器、ThreadLocal及跨域配置,能够有效解决登录状态丢失、用户串号等工程难题。本文从基础概念到实践,逐步演示从单机S

weixin_34218890的博客 303
上一篇: 见缝插针 —— 深入 Redis HyperLogLog 内部数据结构分析
下一篇: RPC 服务器之【多进程描述符传递】高阶模型
codehole_
博客等级 码龄7年 34粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值