化妆品网站建设的论文,各大网站网络推广的收费,小说网站建站程序,购买网站空间目录 Redis为什么快#xff1f;渐进式ReHash全局哈希表渐进式ReHash 缓存时间戳 Redis为什么快#xff1f; 纯内存访问#xff1b; 单线程避免上下文切换#xff1b; 渐进式ReHash、缓存时间戳#xff1b;
前面两个都比较好理解#xff0c;下面我们主要来说下 渐进式… 目录 Redis为什么快渐进式ReHash全局哈希表渐进式ReHash 缓存时间戳 Redis为什么快 纯内存访问 单线程避免上下文切换 渐进式ReHash、缓存时间戳
前面两个都比较好理解下面我们主要来说下 渐进式ReHash 和 缓存时间戳。 渐进式ReHash
全局哈希表
为了实现从键到值的快速访问Redis使用了一个哈希表来保存所有的键值对。一个哈希表其实就是一个数组数组的每个元素称为一个哈希桶。所以我们常说一个哈希表是由多个哈希桶组成的每个哈希桶中保存了键值对数据。 哈希桶中的 entry 元素中保存了 key 和 value 指针分别指向了实际的键和值这样一来即使值是一个集合也可通过 *value 指针被查找到。因为这个哈希表保存了所有的键值对所以我也把它称为全局哈希表。
哈希表最大的好处很明显就是让我们可以用O(1)的时间复杂度来快速查找到键值对我们需要计算键值的哈希值就可以知道它所对应的哈希桶的位置然后就可以访问相应的 entry 元素。
但当你往 Redis 中写入大量数据后就可能发现操作有时候会突然变慢了这其实是因为你忽略了一个潜在的风险点那就是 哈希表的冲突问题 和 ReHash可能带来的操作阻塞。
当你往哈希表中写入更多数据时哈希冲突时不可避免的问题。这里的哈希冲突两个 key 的哈希值和哈希桶计算对应关系时正好落在同一个哈希桶中。
Redis解决哈希冲突的方式就是链式哈希链式哈希也很容易理解就是指同一个哈希桶中的多个元素用一个链表来保存它们之间依次用指针连接。
当然如果这个数组一直不变那么hash冲突会变很多这个时候检索效率会大打折扣所以Redis就需要把数组进行扩容一般是扩大到原来的两倍但是问题来了扩容后每个hash桶的数据会分散到不同的位置这里设计到元素的移动必定会阻塞IO所以这个ReHash过程会导致很多请求阻塞。 渐进式ReHash
为了避免这个问题Redis 采用了渐进式 ReHash。
首先Redis 默认使用了两个全局哈希表哈希表1 和 哈希表2。一开始当你刚插入数据时默认使用哈希表1此时的哈希表2并没有被分配空间。随着数据逐步增多Redis开始执行 ReHash。
给哈希表2分配更大的空间例如是当前哈希表1大小的两倍把哈希表1中的数据重新映射并拷贝到哈希表2中释放哈希表1的空间
在上面的第二步涉及大量的数据拷贝如果一次性把哈希表1中的数据都迁移完会造成Redis线程阻塞无法服务其他请求此时Redis就无法快速访问数据了。 在Redis开始执行 ReHashRedis仍然正常处理客户端请求但是要加入一个额外的处理 处理第一个请求时把哈希表1中的第一个索引位置上的所有 entries 拷贝到哈希表2中 处理第二个请求时把哈希表1中的第二个索引位置上的所有 entries 拷贝到哈希表2中 如此循环直到把所有的索引位置的数据都拷贝到哈希表2中。
这样就巧妙的把一次性大量拷贝的开销分摊到了多次处理请求的过程中避免了耗时操作保证了数据的快速访问。
所以这里基本上也可以确保根据 key 找 value 的操作在O(1) 左右。
不过这里要注意如果Redis中有海量的 key 值的话这个ReHash过程会很长很长虽然采用渐进式ReHash但在ReHash的过程中还是会导致请求有不小的卡顿并且像一些统计命令也会非常卡顿比如keys按照Redis的配置每个实例能存储的最大的key的数量为2的32次方即2.5亿但是尽量把key的数量控制在千万以下这样就可以避免ReHash导致的卡顿问题如果数量确实比较多建议采用分区hash存储。 缓存时间戳
我们平时使用系统时间戳时常常是不假思索的使用 System.currentTimeInMillis 或者 time.time() 来获取系统的毫秒时间戳。Redis不能这样因为每一次获取系统时间戳都是一次系统调用系统调用相对来说是比较费时间的作为单线程的Redis承受不起所以它需要对时间进行缓存由一个定时任务每毫秒更新一次时间缓存获取时间都是从缓存中直接拿。