应用场景
1、缓存
2、数据共享
3、分布式锁
4、全局ID
5、计数器
6、限流
7、Top问题
8、消息队列
9、用户关注、推荐模型
10、排行榜
底层数据结构实现
string
list
hash
set
intset
zset
一般使用String类型。
缓存热点数据(weibo 热搜)、对象缓存、页面缓存,降低数据库压力
redis相对于引用是独立服务,可以在多个应用之间共享
例如:共享session
String类型sexnx,只有在不存在时才能添加成功。
public static boolean getLock(String key) {
Long flag = jedis.setnx(key,"1");
if (flag == 1) return true;
else return false;
}
给定一个全局发号器 ,一次给定一段号,每个服务器使用完再来申请。
incrby 通过步长设置来获取,利用Redis操作的原子性。
incr方法
例如:文章阅读量、微博的点赞量
一般通过访问的IP加其他信息作为key,访问一次加1,超过设定的阈值直接返回。
微博热搜按照访问量 (zset处理)。
list提供了两端操作的方法,rpush/lpush.rpop/rpush等操作。
通过操作可以实现队列,栈等结构。
sdiff set1 set2 获取差集 推荐(好友推荐、粉丝推荐、关注话题推荐)
sinter set1 set2 获取交集(共同好友、共同话题)
sunion set1 set2 获取并集(所有好友,所有话题)
新闻排行榜、微博热搜
/*保存字符串对象的结构*/
struct sdshdr {
int len; // buf 中已占用空间的长度
int free; // buf 中剩余可用空间的长度
char buf[]; // 数据空间
};
SDS 相比C 字符串的优势:
typedef struct listNode {
//前节点
struct listNode *prev;
//后节点
struct listNode *next;
//节点值
void *value;
} listNode;
typedef struct list {
//节点头
listNode *head;
//节点尾
listNode *tail;
//节点值复制
void (dup)(void ptr);
//节点值释放
void (free)(void ptr);
//节点值对比
int (match)(void *ptr, void *key);
//节点数量
unsigned long len; } list;
Redis 的链表实现的特性可以总结:
typedef struct dictht {
dictEntry **table;//哈希表数组
unsigned long size;//哈希表大小
unsigned long sizemask;//哈希表大小掩码,用于计算索引值
unsigned long used;//该哈希表已有节点的数量
}
哈希表节点的结构体如下:
typeof struct dictEntry{
void *key;//键
union{ //不同键对应的值的类型可能不同,使用union来处理这个问题
void *val;
uint64_tu64;
int64_ts64;
}
struct dictEntry *next;
}
当要将一个新的键值对添加到字典里面时,程序需要先根据键值对的键计算出哈希值和索引值,然后再根据索引值,将包含新键值对的哈希表节点放到哈希表数组的指定索引上面。其中解决哈希冲突的方法是链地址法。为了让哈希表的装载因子维持在一个合理的范围之内,需要对哈希表的大小进行扩展或者收缩,这叫做rehash。字典中总共有两个哈希表dictht结构体,ht[0]用来存储键值对,ht[1]用于rehash时暂存数据,平时它指向的哈希表为空,需要扩展或者收缩ht[0]的哈希表时才为它分配空间。比如扩展哈希表,就是为ht[1]分配一块大小为ht[0]两倍的空间,然后把ht[0]的数据通过rehash的方式全部迁移到ht[1],最后释放ht[0],使ht[1]成为ht[0],再为ht[1]分配一个空哈希表。收缩哈希表类似。
渐进式rehash:redis并不是专门找时间一次性地进行rehash,而是渐进地进行,rehash期间不影响外部对ht[0]的访问,要求修改字典时要把对应数据同步到ht[1]中,全部数据转移完成时,rehash结束。
typedef struct intset {
//类型
uint32_t encoding;
//长度
uint32_t length;
//数据
int8_t contents[];
} intset;
整数集的结构 类型为 intset_enc_int16 ,长度5(数组contents长度) ,contents 数组结构存储数据。只有当数据全是整数值,而且数量少于512个时,才使用intset,intset是一个由整数组成的有序集合,可以进行二分查找。
字典
经典例子:一个zset的key是"math",代表数学课的成绩,然后可以往这个key里插入很多数据。输入数据的时候,每次需要输入一个姓名和一个对应的成绩。那么这个姓名就是数据本身,成绩就是它的score。
typedef struct zskiplistNode {
//数据
sds ele;
//节点分值
double score;
//节点的后退指针
struct zskiplistNode *backward;
struct zskiplistLevel {
//节点的前进指针
struct zskiplistNode *forward;
//跨度
unsigned long span;
} level[];
} zskiplistNode;
typedef struct zskiplist {
//跳跃表的头结点和尾节点
struct zskiplistNode *header, *tail;
//跳跃表的长度
unsigned long length;
//跳跃表的层数
int level;
} zskiplist;
zset底层实现原理:
redis为什么使用跳表
redis使用跳表而不是红黑树的原因:
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_45981295/article/details/121458624
内容来源于网络,如有侵权,请联系作者删除!