redis

作者: 16325 | 来源:发表于2020-03-25 17:34 被阅读0次

    String

    在Redis中String是可以修改的,称为动态字符串。说是字符串但它的内部结构更像是一个 ArrayList,内部维护着一个字节数组,并且在其内部预分配了一定的空间,以减少内存的频繁分配。

    • 当字符串的长度小于 1MB时,每次扩容都是加倍现有的空间。
    • 如果字符串长度超过 1MB时,每次扩容时只会扩展 1MB 的空间。
    • 字符串最大长度为 512MB


      image.png

      上图就是字符串的基本结构,其中 content 里面保存的是字符串内容,0x\0作为结束字符不会被计算len中。

    set   [key]  [value]   给指定key设置值(set 可覆盖老的值)
    
    get  [key]   获取指定key 的值
    
    del  [key]   删除指定key
    
    exists  [key]  判断是否存在指定key
    
    mset  [key1]  [value1]  [key2]  [value2] ...... 批量存键值对
    
    mget  [key1]  [key2] ......   批量取key
    
    expire [key]  [time]    给指定key 设置过期时间  单位秒
    
    setex    [key]  [time]  [value]  等价于 set + expire 命令组合
    
    setnx  [key]  [value]   如果key不存在则set 创建,否则返回0
    
    incr   [key]           如果value为整数 可用 incr命令每次自增1
    
    incrby  [key] [number]  使用incrby命令对整数值 进行增加 number
    

    list

    Redis中的list和Java中的LinkedList很像,底层都是一种链表结构, list的插入和删除操作非常快,时间复杂度为 0(1)
    当数据量较少的时候它的底层存储结构为一块连续内存,称之为ziplist(压缩列表),它将所有的元素紧挨着一起存储,分配的是一块连续的内存;当数据量较多的时候将会变成quicklist(快速链表)结构。

    rpush  [key] [value1] [value2] ......    链表右侧插入
    
    rpop    [key]  移除右侧列表头元素,并返回该元素
    
    lpop   [key]    移除左侧列表头元素,并返回该元素
    
    llen  [key]     返回该列表的元素个数
    
    lrem [key] [count] [value]  删除列表中与value相等的元素,count是删除的个数。 count>0 表示从左侧开始查找,删除count个元素,count<0 表示从右侧开始查找,删除count个相同元素,count=0 表示删除全部相同的元素
    
    (PS:   index 代表元素下标,index 可以为负数, index= 表示倒数第一个元素,同理 index=-2 表示倒数第二 个元素。)
    
    lindex [key] [index]  获取list指定下标的元素 (需要遍历,时间复杂度为O(n))
    
    lrange [key]  [start_index] [end_index]   获取list 区间内的所有元素 (时间复杂度为 O(n))
    
    ltrim  [key]  [start_index] [end_index]   保留区间内的元素,其他元素删除(时间复杂度为 O(n))
    

    hash

    Redis 中的 Hash和 Java的 HashMap 更加相似,都是数组+链表的结构,当发生 hash 碰撞时将会把元素追加到链表上,值得注意的是在 Redis 的 Hash 中 value 只能是字符串.

    hset  [key]  [field] [value]    新建字段信息
    
    hget  [key]  [field]    获取字段信息
    
    hdel [key] [field]  删除字段
    
    hlen  [key]   保存的字段个数
    
    hgetall  [key]  获取指定key 字典里的所有字段和值 (字段信息过多,会导致慢查询 慎用:亲身经历 曾经用过这个这个指令导致线上服务故障)
    
    hmset  [key]  [field1] [value1] [field2] [value2] ......   批量创建
    
    hincr  [key] [field]   对字段值自增
    
    hincrby [key] [field] [number] 对字段值增加number
    

    set

    Redis 中的 set和Java中的HashSet 有些类似,它内部的键值对是无序的、唯一 的。它的内部实现相当于一个特殊的字典,字典中所有的value都是一个值 NULL。当集合中最后一个元素被移除之后,数据结构被自动删除,内存被回收。

    sadd  [key]  [value]  向指定key的set中添加元素
    
    smembers [key]    获取指定key 集合中的所有元素
    
    sismember [key] [value]   判断集合中是否存在某个value
    
    scard [key]    获取集合的长度
    
    spop  [key]   弹出一个元素
    
    srem [key] [value]  删除指定元素
    

    zset

    zset也叫SortedSet一方面它是个 set ,保证了内部 value 的唯一性,另方面它可以给每个 value 赋予一个score,代表这个value的排序权重。它的内部实现用的是一种叫作“跳跃列表”的数据结构。

    zadd [key] [score] [value] 向指定key的集合中增加元素
    
    zrange [key] [start_index] [end_index] 获取下标范围内的元素列表,按score 排序输出
    
    zrevrange [key] [start_index] [end_index]  获取范围内的元素列表 ,按score排序 逆序输出
    
    zcard [key]  获取集合列表的元素个数
    
    zrank [key] [value]  获取元素再集合中的排名
    
    zrangebyscore [key] [score1] [score2]  输出score范围内的元素列表
    
    zrem [key] [value]  删除元素
    
    zscore [key] [value] 获取元素的score
    

    redis 性能优化

    • 缩短键值对的存储长度;
    • 使用 lazy free(延迟删除)特性;
    • 设置键值的过期时间;
    • 禁用长耗时的查询命令;
    • 使用 slowlog 优化耗时命令;
    • 使用 Pipeline 批量操作数据;
    • 避免大量数据同时失效;
    • 客户端使用优化;
    • 限制 Redis 内存大小;
    • 使用物理机而非虚拟机安装 Redis 服务;
    • 检查数据持久化策略;
    • 禁用 THP 特性;
    • 使用分布式架构来增加读写速度。

    缓存穿透

    • Redis 大部分的使用场景,都是根据 key ,先在 Redis 中查询,如果查询不到的话,再查询数据库。
    • 当有大量的请求,key 值根本不在 Redis 中,那么查询就会落到数据库上,这些请求就仿佛“穿透”过了 Redis 落在了数据库上,最后会导致数据库不堪重负直至崩溃。
    1. 将无效 key 保存到 Redis 中
    2. 布隆过滤器

    缓存雪崩

    通常我们在使用 Redis 的时候,都会为缓存设置过期时间,但是如果在某个时间点,有大量缓存失效,那么下一个时间点就会有大量请求访问到数据库,这种情况下,数据库可能因为访问量多大导致“崩溃”,这就是缓存雪崩。

    1. 不设置缓存过期时间
      最暴力的解决办法,缓存不设置自动过期时间,只要缓存不崩,数据库就不会崩。
    2. 设置随机过期时间
      另外一个办法,就是让缓存过期时间不那么一致,比如一批缓存数据24小时后过期,那么就在这个基础上,让每条缓存的过期时间前后随机 1-6000 秒(1-10分钟)。
    3. 使用互斥锁
      在缓存失效后,通过互斥锁或者队列,控制读数据库和写缓存的线程数量;不过这样会导致系统的吞吐量下降。
    4. 双缓存
      设置一级缓存和二级缓存,一级缓存过期时间短,二级缓存过期时间长或者不过期,一级缓存失效后访问二级缓存,同时刷新一级缓存。

    缓存击穿

    • 缓存击穿和缓存雪崩的区别在于:雪崩针对很多 key,而击穿只针对于某一个热点 key。
    • 设置缓存永不过期,这个方法虽然很暴力,但是确实能解决大部分的问题,当然,大部分场景也不太适用;
    • 设置随机过期时间,这个方案对于缓存击穿来说就不太适用了,因为击穿只针对一个热点 key,只要它一失效,大量的访问就会击垮数据库;
    • 其余的方案比如使用互斥锁、双缓存机制,也都可以解决缓存击穿的问题,让我们看看这些方案的具体实现。
      1.主动刷新缓存
      2.检查更新
      3.使用锁
      4.双缓存

    相关文章

      网友评论

          本文标题:redis

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