redis详解

Redis是什么?

redis是目前最受欢迎的NoSQL(非关系型)数据库之一,redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库。

对比传统数据库?

  1. C/S通讯模型
  2. 单进程单线程模型
  3. 丰富的数据类型
  4. 操作具有原子性
  5. 持久化
  6. 高并发读写
  7. 支持lua脚本

应用场景?

  1. 缓存系统
  2. 计数器
  3. 消息队列
  4. 排行榜
  5. 社交网络
  6. 实时系统

支持的数据类型?

String、Hash、List、Set、Zset

Redis内存模型?

1. 内存统计

查看内存使用情况:info memory

2. 内存划分

数据

进程本身运行需要的内存

缓冲内存

内存碎片

3. 数据存储

涉及到内存分配器(如:jemalloc),简单动态字符串(SDS),5中对象类型以及内部编码,redisObject。

set hello world涉及到的数据类型:

  1. dictEntry: 里面存储了指向key和value的指针,next指向下一个dictEntry。
  2. Key: 就是对应的hello, 并不是直接以字符串存储,而是存储在SDS结构中。
  3. redisObject: value并不是以直接字符串的形式存储,也不是存储在SDS结构中,而是存储在redisObject中,
  4. jemalloc:无论上面哪个对象,都是需要内存分配器来分配内存进行存储,

 相关名词讲解:

        1. jemalloc

        2. redisObject

        3. SDS

5中数据类型内部编码

字符串         

        内部编码有3种:int   embstr   raw

        embstr:  <=39个字节的字符串(redis 3.2版本以后是44个字节)

                只分配一次内存空间,redisObject和sds是连续的内存,查询效率会快很多。缺点是字符串增加的时候,需要重新分配内存,导致整个redisObject和sds都需要重新分配内存,所以embstr的实现只允许读,如果对其进行修改,那么就会变成raw编码了。

        raw:大于44个字节

                可以分配两次内存空间

        问题:为什么在3.2版本以前是39字节?

                embstr是连续的内存区域, 由redisObject和sdsshdr组成。

struct RedisObject {
    int4 type; // 4bits,不同的redis对象会有不同的数据类型(string、list、hash等),type记录类                
                    型,会用到4bits。
    int4 encoding; // 4bits,存储编码形式,用4bits。
    int24 lru; // 24bits,用24bits记录对象的LRU信息
    int32 refcount; // 4bytes = 32bits,引用计数器,用到32bits
    void *ptr; // 8bytes,64-bit system,指针指向对象的具体内容,需要64bits
}

                计算完:128bits = 16bytes

struct sdshdr {
    unsigned int len;//4个字节
    unsigned int free;//4个字节
    char buf[];//假设buf里面是39个字节
};

if (ptr) {
        memcpy(sh->buf,ptr,len);
        sh->buf[len] = '\0';//一个字节

                计算完:48个字节

                综上:embstr = 16 + 48 = 64 (jemalloc来分配)

        问题:为什么分界值由39字节会变成44字节?

                https://my.oschina.net/sjyz/blog/3276075

列表 list

        用来存储多个有序的字符串,支持两端插入和弹出

        内部编码:压缩列表(ziplist)  双端链表(linkedlist)

哈希

        内部编码:压缩列表(ziplist)  哈希表(hashtable)

        hashtable:  由一个dict结构、2个dictht结构、一个dictEntry指针数组和多个dictEntry结构组成。

集合 set

        与列表的区别就是集合里面的元素是无序的,集合中的元素不能有重复

        内部编码:整数集合(intset)哈希表(hashtable)

有序集合

        内部编码:压缩列表(ziplist)或跳跃表(skiplist)


目前对于redis是什么、区别传统数据库、应用场景、数据类型、内存模型有了一定的了解。

接下来学习如何使用它。


Java客户端

        查了redis官方文档,排第一的就是Redisson,那就它了,搞它!!!!

Redisson

        引入依赖:

<!-- redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson       -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.8.2</version>
</dependency>

yml配置文件:

spring:
  redis:
    host: 127.0.0.1
    database: 0
    port: 6379
    timeout: 300ms

redisson配置类

@Configuration
public class RedissonConfig {

    @Autowired
    private RedisProperties redisProperties;

    @Bean
    public RedissonClient getRedissonClient() {
        Config config = new Config();
        String redisUrl = String.format("redis://%s:%s", redisProperties.getHost() + "", redisProperties.getPort() + "");
        config.useSingleServer().setAddress(redisUrl).setPassword(redisProperties.getPassword());
        config.useSingleServer().setDatabase(3);
        config.useSingleServer().setConnectionMinimumIdleSize(10);
        return Redisson.create(config);
    }
}

然后就可以在测试类中根据官网使用文档进行自测使用啦~~

6. 分布式对象 · redisson/redisson Wiki · GitHubRedisson - Redis Java client with features of In-Memory Data Grid. Over 50 Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Publish / Subscribe, Bloom filter, Spring Cache, Tomcat, Scheduler, JCache API, Hibernate, MyBatis, RPC, local cache ... - 6. 分布式对象 · redisson/redisson Wikihttps://github.com/redisson/redisson/wiki/6.-%E5%88%86%E5%B8%83%E5%BC%8F%E5%AF%B9%E8%B1%A1突然想了解布隆过滤器,我们来看下:

首先布隆过滤器是什么?

        判断一个元素是否存在于大数据量的集合中,(一定不存在、可能存在)因为布隆过滤器有一定的误差率

代码实现:

@Test
    void test5() {
        RBloomFilter<Object> phoneListFilter = redissonClient.getBloomFilter("phoneList");
        //初始化布隆过滤器:预计元素为100000000L,误差率为3%
        phoneListFilter.tryInit(100000000L, 0.03);
        //将号码10086插入到布隆过滤器中
        phoneListFilter.add("10086");
        System.out.println(phoneListFilter.contains("123456"));
        System.out.println(phoneListFilter.contains("10086"));
    }

优点:底层是二进制组成的数组,占用内存极少,并且查询和插入速度很快

缺点:有 一定的误判率、无法删除数据(因为存在hash冲突,会同时删掉其他数据)

对于以上缺点有什么解决方案呢?

        1. 首先如何解决误判率

                a: 增加二进制位数组的长度,hash后数据会更加的离散化,降低冲突率

                b: 增加hash次数,降低冲突概率

        2. 如何删除过滤器里面的数据

                a: 开发定时任务,每隔几个小时,自动创建一个新的布隆过滤器数组,替换老的,有点CopyOnWriteArrayList的味道

                b: 布隆过滤器增加一个等长的数组,存储计数器,主要解决冲突问题,每次删除时对应的计数器减一,如果结果为0,更新主数组的二进制值为0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值