当前位置: 首页 > news >正文

手机端在哪里打开宁波seo整站优化

手机端在哪里打开,宁波seo整站优化,国内用python做的网站,网站的二级导航怎么做Redis 字典 基本语法 字典是Redis中的一种数据结构,底层使用哈希表实现,一个哈希表中可以存储多个键值对,它的语法如下,其中KEY为键,field和value为值(也是一个键值对): HSET key…

Redis 字典

基本语法

字典是Redis中的一种数据结构,底层使用哈希表实现,一个哈希表中可以存储多个键值对,它的语法如下,其中KEY为键,field和value为值(也是一个键值对):

HSET key field value

根据Key和field获取value:

HGET key field

哈希表

数据结构
dictht

dictht是哈希表的数据结构定义:

  • table:哈希表数组,数组中的元素是dictEntry类型的
  • size:哈希表数组的大小
  • sizemask:哈希表大小掩码,一般等于size-1
  • used:已有节点的数量(存储键值对的数量)
typedef struct dictht {dictEntry **table;unsigned long size;unsigned long sizemask;unsigned long used;
} dictht;

dictEntry

dictEntry是哈希表节点的结构定义:

  • key:键值对中的键
  • v:键值对中的值
  • next:由于会出现哈希冲突,所以next是指向下一个节点的指针
typedef struct dictEntry {void *key; // 键union {void *val;uint64_t u64;int64_t s64;double d;} v; // 值struct dictEntry *next; // 指向下一个节点的指针
} dictEntry;

dict

dict是Redis中字典的结构定义:

  • type:指向dictType的指针
  • privdata
  • ht[2]:一个dictht类型的数组,数组大小为2,保存了两个哈希表,rehash时使用
  • rehashidx:记录了当前rehash的进度
  • pauserehash:rehash暂停标记,大于0表示没有进行rehash
typedef struct dict {dictType *type; // void *privdata; // 私有数据dictht ht[2]; // 保存了两个哈希表long rehashidx; // rehash的进度标记int16_t pauserehash; 
} dict;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);int (*expandAllowed)(size_t moreMem, double usedRatio);
} dictType;

哈希冲突

一个键值对放入哈希表的时候,会根据key的值,计算一个hash值,然后根据hash值与哈希表大小掩码做与运算得到一个索引值,索引值决定元素放入哪个哈希桶中(落入哈希表数组哪个索引位置处)。

 // 计算hash值hash = dictHashKey(d,key)// 计算索引idx = hash & d->ht[table].sizemask;

在进行哈希计算的时候,不可避免会出现哈希冲突,出现哈希冲突的时候,Redis采用链式哈希解决冲突,也就是落入同一个桶中的元素,使用链表将这些冲突的元素链起来(dictEntry中的next指针)。

rehash

由于Redis采用链式哈希解决冲突,那么在冲突频繁的场景下,链表会变得越来越长,这种情况下查找效率是比较低下的,需要遍历链表对比KEY的值来获取数据,为了处理效率低下的问题,需要对哈希表进行扩容,扩容的过程称为rehash。

在dict结构替中ht保存了两个哈希表,ht[0]用于数据正常的增删改查,ht[1]用于rehash:

(1)正常情况下,所有的增删改查操作都在ht[0]中进行;

(2)需要进行rehash时,会使用ht[1]建立新的哈希表,并将ht[0]中的数据迁移到ht[1]中;

(3)迁移完成后,ht[0]的空间被释放,然后将ht[1]地址赋给ht[0],ht[1]的大小被设为0,ht[0]重新接收正常的请求,回到了第(1)步的状态;

rehash的触发条件
/* 判断是否需要扩容 */
static int _dictExpandIfNeeded(dict *d)
{/* 如果已经处于rehash状态中直接返回 */if (dictIsRehashing(d)) return DICT_OK;/* 如果ht[0]的大小为0,意味着哈希表为空,此时做初始化操作 */if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);/*如果已经存储的节点数量大于或等于哈希表数组的大小,并且跨域扩容或者(节点数量/哈希表数组大小)大于一个比例,同时根据字典的类型判断是否允许分配内存*/if (d->ht[0].used >= d->ht[0].size &&(dict_can_resize ||d->ht[0].used/d->ht[0].size > dict_force_resize_ratio) &&dictTypeExpandAllowed(d)){   // 进行扩容return dictExpand(d, d->ht[0].used + 1);}return DICT_OK;
}/* 由于扩容需要分配内存,这里检查字典类型分配是否被允许*/
static int dictTypeExpandAllowed(dict *d) {if (d->type->expandAllowed == NULL) return 1;return d->type->expandAllowed(_dictNextPower(d->ht[0].used + 1) * sizeof(dictEntry*),(double)d->ht[0].used / d->ht[0].size);
}

d->ht[0].used/d->ht[0].size : 节点数量与哈希表数组大小的比例,称作负载因子

dict_force_resize_ratio 的默认值是 5。

  1. ht[0]的大小为0,此时哈希表是空的,相当于对哈希表做一个初始化的操作。
  2. 如果哈希表中存储的节点数量大于或者等于哈希表数组的大小,并且哈希表可以扩容或者负载因子大于dict_force_resize_ratio(默认值为5),根据字典的类型判断允许分配内存,满足这三个条件开始扩容。

dict_can_resize

dict_can_resize用来判断哈希表是否可以扩容,有两种状态,值分别为1和0,1代表可以扩容,0代表禁用扩容:

void dictEnableResize(void) {dict_can_resize = 1;
}void dictDisableResize(void) {dict_can_resize = 0;
}

updateDictResizePolicy中对dict_can_resize的状态进行了控制,当前没有RDB子进程并且也没有AOF子进程时设置dict_can_resize状态为可扩容:


void updateDictResizePolicy(void) {// 没有RDB子进程并且也没有AOF子进程if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)dictEnableResize(); // 启用扩容elsedictDisableResize(); // 禁用扩容
}
扩容大小

从代码中可以看到,扩容后哈希表数组的大小为已经存储的节点数量+1:

// 进行扩容
return dictExpand(d, d->ht[0].used + 1);

一些旧版本中扩容后的大小为已存储节点数量的2倍:

dictExpand(d, d->ht[0].used*2);
渐进式hash

当哈希表存储节点内容比较多时,需要将原来的节点一个一个拷贝到新的哈希表中,此时Redis主线程无法执行其他请求,造成阻塞,影响性能,为了解决这个问题,引入了渐进式hash。

渐进式hash并不会一次把旧节点全部拷贝到新的哈希表中,而是分多次渐进式的完成拷贝,其中rehashidx记录了迁移进度,每一次迁移的过程中会更新rehashidx的值,下一次进行数据迁移的时候,从rehashidx的位置开始迁移,在dictRehash中可以看到迁移的处理:

  1. 方法传入了一个参数n,代表本次需要迁移几个哈希桶
  2. 根据需要迁移哈希桶的数量,循环处理每一个哈希桶:
    • 如果当前哈希桶中为空,继续下一个桶的处理rehashidx++
    • 如果当前哈希桶不为空,将当前桶中的所有节点迁移到新的哈希表中,然后更新rehashidx的值继续处理下一个桶
  3. 如果已经处理够了n个桶,或者哈希表的所有数据已经迁移完毕,则结束迁移。
int dictRehash(dict *d, int n) {int empty_visits = n*10; /* Max number of empty buckets to visit. */if (!dictIsRehashing(d)) return 0;// 循环处理每一个哈希桶,n为需要迁移哈希桶的数量while(n-- && d->ht[0].used != 0) {dictEntry *de, *nextde;assert(d->ht[0].size > (unsigned long)d->rehashidx);// 如果当前哈希桶没有存储数据while(d->ht[0].table[d->rehashidx] == NULL) {// rehashidx的值是哈希表数组的某个索引值(指向了某个哈希桶),意味着当前迁移到数组的哪个索引位置处d->rehashidx++; // 继续下一个桶if (--empty_visits == 0) return 1;}de = d->ht[0].table[d->rehashidx];// 如果当前的哈希桶中存储着数据,将哈希桶存储的所有数据迁移到新的哈希表中while(de) {uint64_t h;nextde = de->next;/* Get the index in the new hash table */h = dictHashKey(d, de->key) & d->ht[1].sizemask;de->next = d->ht[1].table[h];d->ht[1].table[h] = de;d->ht[0].used--;d->ht[1].used++;de = nextde;}d->ht[0].table[d->rehashidx] = NULL;// rehashidx,继续迁移下一个哈希桶d->rehashidx++;}/* 判断ht[0]的节点是否迁移完成 */if (d->ht[0].used == 0) {// 释放ht[0]的空间zfree(d->ht[0].table);// 将ht[0]指向ht[1]d->ht[0] = d->ht[1];// 重置ht[1]的大小为0_dictReset(&d->ht[1]);// 设置rehashidx,-1代表rehash结束d->rehashidx = -1;return 0;}/* More to rehash... */return 1;
}

_dictRehashStep

_dictRehashStep中可以看到调用dictRehash时,每次迁移哈希桶的数量为1:

static void _dictRehashStep(dict *d) {if (d->pauserehash == 0) dictRehash(d,1);
}

总结

  1. Redis字典底层使用哈希表实现。

  2. 键值对放入哈希表的时候,会根据key的值,计算hash值,出现哈希冲突的时候,Redis采用链式哈希解决冲突,使用链表将这些冲突的元素链起来。

  3. 由于Redis采用链式哈希解决冲突,那么在冲突频繁的场景下,链表会变得越来越长,这种情况下查找效率是比较低下的,需要遍历链表对比KEY的值来获取数据,为了处理效率低下的问题,需要对哈希表进行扩容,扩容的过程称为rehash。

  4. 当哈希表存储节点内容比较多时,进行rehas的时候主线程无法执行其他请求,造成阻塞,影响性能,所以采用了渐进式hash,渐进式hash并不会一次把旧节点全部拷贝到新的哈希表中,而是分多次渐进式的完成拷贝。

参考

黄健宏《Redis设计与实现》

极客时间 - Redis源码剖析与实战(蒋德钧)

美团针对Redis Rehash机制的探索和实践

Redis版本:redis-6.2.5

http://www.shuangfujiaoyu.com/news/22492.html

相关文章:

  • 网站建设 cms 下载网络优化行业的发展前景
  • 厦门seo网站关键词优推广自媒体平台app
  • 可以自己做网站做宣传吗磁力猫torrentkitty官网
  • 类型: 营销型网站建设百度网盘搜索免费资源
  • Vs做的网站调试时如何适应网页百度的代理商有哪些
  • 加油站顶棚网架价多少钱一平seo com
  • 杭州seo网站优化应用商店下载
  • 做淘宝的网站有哪些网络营销的营销策略
  • 合肥网站建设公司还有不长沙seo推广
  • 做平面什么网站的素材不侵权武汉seo优化代理
  • 建行官方网站多少钱种子搜索神器在线搜
  • 一亩地开发多少钱班级优化大师官方免费下载
  • 怎样在手机上做网站关于市场营销的100个问题
  • 做库房推广哪个网站好在哪个平台做推广比较好
  • 网站开发程序用什么好500强企业seo服务商
  • 做网站百灵鸟指数型基金是什么意思
  • 网站建设时间代运营靠谱吗
  • 单网站建设百度指数使用指南
  • 网站制作公司 北京查图百度识图
  • 广州 网站建设模板兰州网站优化
  • 专门做油画交流的网站什么软件可以免费引流
  • 网站专题页面设计海洋网络推广效果
  • 微网站怎么做的好名字吗网推获客平台
  • 做网站是否过时了网站制作免费
  • 做网站续费网站建设网络推广平台
  • 网站建设标语站长查询工具
  • 广东网站建设设计服务福州seo快速排名软件
  • 潍坊建设公司排名路由器优化大师
  • 咸阳网站建设报价谷歌搜索引擎入口手机版
  • 培训学校如何做网站宣传全国疫情排行榜