首页 > 数据库 >redis字符串的底层源码以及应用实例

redis字符串的底层源码以及应用实例

时间:2022-12-03 00:11:39浏览次数:45  
标签:实例 int redis value 源码 userInfo 字符串 id

内部编码

  • int 8个字节的长整型
  • embstr 小于等于39个字节的字符串
  • raw 大于39个字节的字符串

string底层使用的sds自定义的字符串,因为c语言中string默认为\0为结尾,而redis有可能会传输视频流或者其他的数据,有可能会出现nam\0orxxxx这种,但是如果使用c默认的字符串,只会读取到name就会截止。

  struct sdshdr {
        int len;    //存储的长度
        int free;  //剩余的空闲空间
        char buf[]; //数据存储的地方
    };

这种数据结构的好处是:
1.对于存储数据的准确性更高了,依靠len字段来标明准确数据的位置。【二进制安全的数据结构】
2.采用以空间换时间的方式,每次扩容的时候可以适当分配大一点的空间,记录剩余时间是否够下一次的修改或者追加。(减少对象的销毁与创建的步骤)【提供了内存预分配机制,避免了频繁的内存分配】
3.会在数据末尾依旧采用\0作为结尾【兼容C语言的函数库】

//redis 3.2 以前
struct sdshdr {
    int len;
    int free;
    char buf[];
};
//redis 3.2 后
//redis\deps\hiredis\sds.h文件
typedef char *sds;

//存在注释:sdshdr5 is never used, we just access the flags byte directly.However is here to document the layout of type 5 SDS strings. 
//意思大概是:sdshdr5从未使用过,我们只是直接访问标志字节。然而,这里是为了记录类型5 SDS字符串的布局
struct __attribute__ ((__packed__)) sdshdr5 {  // 对应的字符串长度小于 1<<5
    unsigned char flags; 
    char buf[];
};

//__attribute__ ((packed)) 的作用就是告诉编译器取消结构体在编译过程的优化对齐,按照实际占用字节数进行对齐

struct __attribute__ ((__packed__)) sdshdr8 { // 对应的字符串长度小于 1<<8
    uint8_t len;                              //目前字符串的长度
    uint8_t alloc;                            //分配的内存总长度
    unsigned char flags;                      //flag用3bit来标明类型,类型后续解释,其余5bit目前没有使用
    char buf[];                               //柔性数组,以'\0'结尾
};
struct __attribute__ ((__packed__)) sdshdr16 { // 对应的字符串长度小于 1<<16
    uint16_t len; 
    uint16_t alloc; 
    unsigned char flags; 
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 { // 对应的字符串长度小于 1<<32
    uint32_t len; 
    uint32_t alloc; 
    unsigned char flags; 
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 { // 对应的字符串长度小于 1<<64
    uint64_t len; 
    uint64_t alloc; 
    unsigned char flags; 
    char buf[];
};

#define SDS_TYPE_5  0
#define SDS_TYPE_8  1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

static inline char sdsReqType(size_t string_size) {
    if (string_size < 1<<5)
        return SDS_TYPE_5;
    if (string_size < 1<<8)
        return SDS_TYPE_8;
    if (string_size < 1<<16)
        return SDS_TYPE_16;
#if (LONG_MAX == LLONG_MAX)  
    if (string_size < 1ll<<32)
        return SDS_TYPE_32;
    return SDS_TYPE_64;
#else
    return SDS_TYPE_32;
#endif
}

String限制512mb从何而来

//位于t_string.c文件中
//为什么要限制,要知道512M已经是一个很大的值了(已经是一个bigkey了),在redis单线程操作中已经很容易阻塞线程
//故在追加命令appendCommand和设置命令setrangeCommand中都会进行校验
static int checkStringLength(client *c, long long size) {
    if (size > 512*1024*1024) {
        addReplyError(c,"string exceeds maximum allowed size (512MB)");
        return C_ERR;
    }
    return C_OK;
}

2.2.3典型的使用场景

  • 用户登录

比较典型的缓存使用场景,其中Redis作为缓存层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。

image-20221202235617526

UserInfo getUserInfo(Long id){
    
}
//首先先从redis里面获取用户信息
userRedisKey ="user:info"+id;
value = jedis.get(userRedisKey);
if(value!=null){
    userInfo = deserialize(value);
    return userInfo;
}
//如果没有在redis中找到用户信息,则从mysql数据库里查找
UserInfo getUserInfo(long id){
    userRedisKey = "user:info:" + id
    value = redis.get(userRedisKey);
    UserInfo userInfo;
    if (value != null) {
        userInfo = deserialize(value); 
    } else {
        userInfo = mysql.get(id);
        if (userInfo != null)
            redis.setex(userRedisKey, 3600, serialize(userInfo));
    }
    return userInfo;
}
  • 计数

许多应用都会使用Redis作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他数据源。例如笔者所在团队的视频播放数系统就是使用Redis作为视频播放数计数的基础组件,用户每播放一次视频,相应的视频播放数就会自增1:

long incrVideoCounter(long id) {
    key = "video:playCount:" + id;
    return redis.incr(key);
}
  • 共享session
  • 验证码限速 时间+次数

标签:实例,int,redis,value,源码,userInfo,字符串,id
From: https://www.cnblogs.com/wiseleer/p/16946038.html

相关文章

  • [Redis] (二) 配置
    Redis配置Redis的配置文件位于Redis安装目录下,文件名为redis.conf(Windows名为redis.windows.conf)。通过命令配置Redis可以通过CONFIG命令查看或设置配置项。......
  • [Redis] (一) 简介
    Redis是什么REmoteDIctionaryServer(Redis)是一个由SalvatoreSanfilippo写的key-value存储系统,是跨平台的非关系型数据库。Redis是一个开源的使用ANSIC语言......
  • C++学习------cmath头文件的源码学习08
    函数族定义---四舍五入与余数函数ceil---返回不小于x的最小整数doubleceil(doublex);代码示例:printf("ceilof2.3is%.1f\n",ceil(2.3));printf("ceilof3.8......
  • 13 刘欣晨 第五章实例+实战
    实验 一 项目名称:     使用字符串拼接输出一个关于程序员的笑话programmer_1='程序员甲:搞IT太辛苦了,我想换行....怎么办?'programmer_2='程序员乙:敲一下回车......
  • shiro源码第一天:登陆验证部分
    登陆验证部分:​​1.单点登陆系统中不同系统密码验证方式不一样​​1.单点登陆系统中不同系统密码验证方式不一样问题:当使用shiro作为鉴权框架时,首先用到的应该就是登陆认证......
  • EasyExcel 实践与源码梳理
    目录​​1.写在最前​​​​1.1EasyExcel版本​​​​1.2初探源码​​​​2.表头实体类MyUser​​​​3.最简单的导出Excel文件​​​​4.源码demo:​​​​4.1读Exc......
  • 基于redis的点赞功能
    初始代码@GetMapping("/likes/{id}")publicResultqueryBlogLikes(@PathVariable("id")Longid){//修改点赞数量blogService.update().setSql("liked=li......
  • 学习Spring源码问题总结
    记录一下学习源码遇到的问题:​​1.编译时报错:Failedtoapplyplugin[id'com.gradle.build-scan']​​​​2.报错Groovy:compilermismatchprojectlevelis:2.4Works......
  • 15.第三章第12节: 2021.11.20 Redis分布式锁 redisson分布式锁,乐观锁+版本号 watch do
                                                 ......
  • Redis cluster 扩容与缩容
    Redis群集TCP端口每个Redis集群节点都需要两个开放的TCP连接:一个用于服务客户端的RedisTCP端口,例如6379,以及第二个称为集群总线端口的端口。默认情况下,集群总线端口是通......