美文网首页
Redis的基本知识

Redis的基本知识

作者: 掩流年 | 来源:发表于2020-01-05 19:40 被阅读0次

    Redis的基本原理

    Redis是单线程程序,它快的原因是因为它是在内存中运行的,它的多路复用技术保证了保证了并发客户端的连接。

    NIO

    NIO又被称为Non_Blocking IO。对于普通的IO而言,在一个socket对象进行网络传输的读写时候,当读操作读取的byte数还没有达到读取的要求就会被阻塞住,直到新的数据来到或者等连接关闭。对于写操作,内核为写缓冲分配的内存满了,就会发生阻塞。

    对于NIO而言,一次性能读多少就读多少,读完之后立即返回,写操作也是一样。但是这样如何保证数据读取和写入的完整性呢?这就用到了多路复用技术。

    多路复用

    其实从本质上而言就是,操作系统内核为程序分配了一个线程API叫做“select”,或者也linux中也有一种线程叫做“epoll”。它一只轮询着去看有没有新的时事件返回过来,有的话就赶紧通知redis的线程过来处理。
    对多个客户端而言,多路复用中维护了一个指令队列,把客户端放进去,按顺序进行处理。
    在轮询的同时,它们也会有timeout的一个属性,表示在一个事件等待的超时事件。这个时间的计算是动态的。是在定时任务中有个最小堆的数据结构。判断最先要执行的事件还需要多长时间,这个等待事件就是timeout时间。

    持久化

    Redis在持久化中,会使用操作系统的多进程COW(Copy On Write)来实现。

    • 快照方式

      快照持久化的方式是,Redis会调用glibc函数fork出一个子进程。所有的持久化工作完全由这个子进程完成,当子进程进行持久化的时候,仅仅是从内存中进行读操作,而客户端的写操作会复制出一份快照进行。这时候也就用到了操作系统的COW,进行页面分离,可以保证读写是分离的。

    • AOF方式

      它记录了所有客户端操作的命令,当恢复的时候只需要执行这些命令即可。

      AOF有两个特点,当Redis执行时间过长,会对AOF文件进行瘦身,会fork出一个子进程,然后遍历内存中的数据,然后形成新的AOF文件,同步到磁盘中,同时增量添加这段时间的添加指令。
      AOF文件从内存放到磁盘上可以使用,Linux 的 glibc 提供了 fsync(int fd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。

    Redis也可以使用混合持久化的方式,在实际运维中,持久化操作总是在从节点上进行的。但是Reids本来就不是强一致性的,所以无论采用什么方式,当机器突然宕机的时候总会丢失一些数据。

    Redis的数据结构

    String

    string是动态字符串,小于1M的时候每次扩容都是翻倍的,大于1M每次扩容都是加1M。可以认为它是一个ArrayList结构,有个常见的用途是我们可以使用fastjson把用户结构体序列化成字符串形式,然后做缓存。

    expire name 5 //可以用来设置过期时间5s

    setnx name 1 /会先检测有没有name这个key,有则输入失败,没有则添加成功

    list

    redis中的list相当于Java中的LinkedList,它是链表结构。当使用的键值对过多的情况下, 会产生较多的内存碎片。所以list中有一种列表叫做快速列表,就是在内存足够的时候分配一串连续的内存,叫做ziplist。

    hash

    更hashmap的结构基本是类似的,只是rehash的方式是不一致的,Redis为了高性能,不阻塞服务使用的是渐进式rehash策略。当hash移除了最后一个元素,就会删除原来旧的数据结构。

    set

    set集合相当于Java中的HashSet,可以用来存储中奖用户,它的内部键值都是无序且唯一的。

    • zset
      可以实现key唯一且排序。它的结构是使用跳跃列表来实现的。因为排序就意味着要插入,通常的插入点都是使用二分法来实现的,但是二分法只能使用在数组上,所以redis提供了一种数据结构叫做跳跃列表,就类似于一个索引,从高层到底层,去查找。

    Redis实现分布式锁

    redis实现分布式锁最简单的方式是

    setnx lock 1

    expire lock 5

    死锁问题

    但是因为这两步操作并非原子性的,所以在Redis2.8之后提供了一种方式:

    set lock:codehole true ex 5 nx

    超时问题

    给每个set操作的value值加一个随机数,当锁释放的时候先比较这个随机数是否一致,一致的话则进行del操作。

    位图

    位图的操作是setbit,getbit。可以指定一个string的ASCII码的位数。

    HyperLogLog

    使用pfadd和pfcount来提供不精确的统计方案,它可以用来统计日常的pv和uv。

    布隆过滤器

    在推荐算法中,过滤掉那些你看过的资讯。

    bf.add test movie1
    bf.exist test movie1
    (integer) 1
    bf.exist test movie2
    (integer) 0

    布隆过滤器的原理其实是一个大型的位数组和几个不一样的无偏hash函数。在每次添加key的时候, 利用hash函数算的位数组的索引,然后把这一位置为1。

    简单的限流

    限流的策略可以使用zset中的score数据结构,可以使用score的排序功能,划出一个时间窗口。简单的使用pipeline实现限流。

    漏斗限流

    可以使用开源插件redis-cell实现原子性操作

    SCAN

    1.通过游标分步进行的,不会阻塞线程
    2.提供limit参数,可以控制每次返回结果的最大条数。
    3.可以提供模式匹配功能
    4.返回的结果可能会有重复,需要客户端去重
    5.遍历的过程中,如果有数据的修改,改动过的数据有没有被遍历到是不知道的。
    6.单次返回的结果为空并不意味着遍历的结束,而是要看返回的游标值是否为零。

    相关文章

      网友评论

          本文标题:Redis的基本知识

          本文链接:https://www.haomeiwen.com/subject/xfecactx.html