索引的作用是让健值数据库根据Key找到对应Value的存储位置,进而进行操作。
实现
索引的类型有很多,常见的有哈希表、B+树、字典树等。为了实现从健到值的快速访问,Redis使用了一个全局哈希表来保存所有的健值对。
之所以采用哈希表作为索引,很大的一部分原因在于,其健值数据基本都是保存在内存中的,而内存的高性能随机访问特性可以很好地与哈希表O(1)的操作复杂度相匹配。
哈希表本身就是一个数组,数组中的每个元素都是一个哈希桶,每个哈希桶中都保存着健值对数据。
- 健:存储指向Key所在内存地址的指针
- 值:存储指向Value所在内存地址的指针
哈希冲突
既然使用来哈希表,难免会照成哈希冲突。所谓的哈希冲突是指两个Key的哈希值相同从而导致两个数据落到了同一个哈希桶中。
Redis通过链式哈希去解决哈希冲突。链式哈希是指同一个哈希桶中的多个元素用一个链表存储,链表中的数据用指针依次连接。
rehash
随着哈希表中的数据越来越多,哈希冲突也会随之增多,由于冲突链上的数据只能逐一查找,进而导致元素查找耗时长、效率低下。为了解决这个问题,Redis会对哈希表做rehash操作。
rehash操作是通过增加现有哈希桶数量,让逐渐增多的数据能在更多的哈希桶间分散保存,从而减少单个哈希桶中的元素个数。
Redis默认使用了两张全局哈希表,一开始有数据进来时默认使用哈希表1,此时并没有为哈希表2分配空间,随着数据逐步增多,Redis开始执行rehash操作:
由于Redis是单线程的,为了避免在拷贝数据时造成线程阻塞无法处理其它请求,Redis使用了渐进式的rehash:
以上,就是Redis索引的实现。