前言
作为同时具备高性能、高可靠和高可扩展性的典型键值数据库,Redis不仅功能强大,而且稳定,理所当然地成为了大型互联网公司的首选。
众多大厂在招聘的时候,不仅会要求面试者能简单地使用Redis,还要能深入地理解底层实现原理,并且具备解决常见问题的能力。可以说,熟练掌握Redis已经成为了技术人的一个必备技能。
但是,在学习和使用Redis的过程中,总不可避免地遇见一些棘手的问题,比如:
- Redis的key和数据结构应该怎么设计?有什么最佳实践?
- Redis集群如何均衡数据?又如何横向扩展?
- 怎么保证数据的一致性?热点数据的问题怎么解决?
- RDB持久化生成的数据快照,每次更新是全量更新还是增量更新?
- 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题怎么解决?
- 如何高效阅读Redis源代码?
我根据自己多年的从业经验,梳理了一套系统的Redis学习方法。将纷繁复杂的Redis知识和问题归纳在“两大维度,三大主线”这个框架之中,帮助读者建立起系统观和全局观,从而彻底搞懂底层实现原理。让我们来看看大体内容
class MyHashMap {
static const int P = 10019;
struct Node{
int key,val;
Node* next;
Node(int key = 0,int val = 0,Node*next = nullptr):key(key),val(val),next(next){}
};
Node* bucket[P] = {0};
public:
/** Initialize your data structure here. */
MyHashMap() {
}
/** value will always be non-negative. */
void put(int key, int value) {
int hashcode = key%P;
// 键存在,搜寻整条链
for(Node* p = bucket[hashcode];p!=nullptr;p=p->next){
if(p->key == key){
p->val = value;
return;
}
}
// 没有提前结束,说明没有这个键,链表的头插法
Node* newNode = new Node(key,value,bucket[hashcode]);
bucket[hashcode] = newNode;
}
/** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
int get(int key) {
int hashcode = key%P;
// 键存在,搜寻整条链
for(Node* p = bucket[hashcode];p!=nullptr;p=p->next){
if(p->key == key){
return p->val;
}
}
return -1;
}
/** Removes the mapping of the specified value key if this map contains a mapping for the key */
void remove(int key) {
int hashcode = key%P;
// 键存在,搜寻整条链
Node* pre = nullptr;
for(Node* p = bucket[hashcode];p!=nullptr;p=p->next){
if(p->key == key){
if(pre==nullptr){
bucket[hashcode] = p->next;
}else{
pre->next = p->next;
}
}
pre = p;
}
}
};