zoukankan      html  css  js  c++  java
  • Redis 常用技巧

    Redis 是什么、特点

    非关系型(NoSQL)内存键值数据库

    五种类型数据类型为:字符串、列表、散列表,集合、有序集合

    内存中数据持久化

    使用复制来扩展读性能:复制到多台服务器、提高读性能和可用性

    使用分区来扩展写性能【hash一致性算法】:当数据量大的时候,把数据分散存入多个数据库中,减少单节点的连接压力

    特点

    完全基于内存
    数据结构简单,对数据操作也简单
    使用多路 I/O 复用模型
    多路 I/O 复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作

    Redis 的五种基本类型

    数据类型

    可以存储的值

    操作

    STRING

    字符串、整数或者浮点数

    字符串操作

    对整数和浮点数执行自增、自减操作

    LIST

    链表,维护顺序

    两端压入、弹出元素;保持顺序

    读取单个或者多个元素

    删除、保留范围内元素

    SET

    无序集合

    添加、随机获取、移除单个元素

    检查一个元素是否存在于集合中

    计算交集、并集、差集

    HASH

    包含键值对的无序散列表

    添加、获取、移除单个键值对

    获取所有键值对

    检查某个键是否存在

    ZSET

    有序集合,增加了一个权重参数score,集合中的元素能按score进行有序排列

    添加、获取、删除元素个元素

    根据分值范围或者成员来获取元素

    计算一个键的排名

    Redis 适用场景

    缓存 将热点数据放到内存中
    消息队列 List 类型是双向链表,很适合用于消息队列
    计数器 快速、频繁读写操作;string的单线性自增减 ++ --
    共同好友关系 set 交集运算,很容易就可以知道用户的共同好友
    排名 zset有序集合
     

    键的过期时间 作用:清理缓存数据

    为键设置过期时间,过期,自动删除该键

    对于散列表这种容器,只能为整个键设置过期时间(整个散列表),而不能为键里面的单个元素设置过期时间。

    事务

    Redis最简单的事务实现方式是使用MULTI和EXEC命令将事务操作包围起来

    MULTI 和 EXEC 中的操作将会一次性发送给服务器,这种方式称为流水线,减少客户端与服务器之间的网络通信次数,提升性能

    redis事务三阶段:

    开启:以MULTI开始一个事务
    入队:将多个命令入队到事务队列中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
    执行:由EXEC命令触发事务
    redis事务三大特性:

    单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
    没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
    不保证事务原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
    官方认为,只有当被调用的Redis命令有语法错误时,这条命令才会执行失败
    保证生产环境的简单、快速
    通过WATCH命令实现CAS操作,实现乐观锁;(读锁和写锁属于悲观锁)

    Redis使用WATCH命令实现事务的“检查再设置”(CAS)行为。

    作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。在执行EXEC命令之前,如果Redis检测到至少有一个键被修改了,那么整个事务便会中止运行,然后EXEC命令会返回一个Null值,提醒用户事务运行失败

    持久化

    快照持久化

    将某个时间点的所有数据都存放到硬盘上

    可以将快照复制到其它服务器从而创建具有相同数据的服务器副本

    缺点:故障可能丢失最后一次创建快照之后的数据;如果数据量很大,保存快照的时间也会很长。

    AOF 持久化 将写命令添加到 AOF 文件(Append Only File)的末尾

    写命令添加到 AOF 文件时,有以下同步选项:

    选项

    同步频率

    always

    每个写命令都同步

    everysec

    每秒同步一次

    no

    让操作系统来决定何时同步

    always: 严重减低服务器的性能;
    everysec :比较合适,保证系统奔溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;
    no :不能给性能带来提升,且会增加奔溃时数据丢失量
     

    随着服务器写请求的增多,AOF 文件会越来越大;Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。

    对硬盘的文件进行写入时,写入的内容首先会被存储到缓冲区,操作系统决定何时写

    用户可以调用 file.flush() 方法请求尽快将缓冲区存储的数据同步到硬盘

    redis主从复制 分布式数据同步方式

    slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。

    一个从服务器只能有一个主服务器

    从服务器连接主服务器的过程

    主服务器创建快照文件,发送给从服务器。同时记录其间执行的写命令,发送完毕后,开始向从服务器发送写命令;
    从服务器丢弃所有旧数据,载入主服务器的快照文件,然后开始接受主服务器发来的写命令;
    主服务器每执行一次写命令,就向从服务器发送相同的写命令
    主从链 创建一个中间层来分担主服务器的复制工作

    随着负载不断上升,主服务器可能无法很快地更新所有从服务器
    重新连接和重新同步从服务器将导致系统超载
    中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器
     

    redis 主服务器 故障 处理

    当主服务器出现故障时,Redis 常用的做法是新开一台服务器作为主服务器,具体步骤如下:假设 A 为主服务器,B 为从服务器,当 A 出现故障时,让 B 生成一个快照文件,将快照文件发送给 C,并让 C 恢复快照文件的数据。最后,让 B 成为 C 的从服务器。

    分片 集群 读并发

    数据划分为多个部分,可以将数据存储到多台机器里,作用:负载均衡、线性级别的性能提升

    分片方式:

    客户端代码分片
    Redis Sharding,对Redis数据的key进行hash,相同的key到相同的节点上
    一致性哈希算法
    代理服务器分片 轮询round-bin
     

    数据淘汰策略 6 种

    可设置内存最大使用量,超出时淘汰, 淘汰策略。

    策略

    描述

    volatile-lru

    从已设置过期时间的数据集中挑选最近最少使用的数据淘汰

    volatile-ttl

    从已设置过期时间的数据集中挑选将要过期的数据淘汰

    volatile-random

    从已设置过期时间的数据集中任意选择数据淘汰

    allkeys-lru

    从所有数据集中挑选最近最少使用的数据淘汰;最常用的热点数据缓存策略

    allkeys-random

    从所有数据集中任意选择数据进行淘汰

    no-envicition

    禁止驱逐数据

    缓存热点数据,启用 allkeys-lru 淘汰策略,

    一个简单的论坛系统分析

    该论坛系统功能如下:

    可以发布文章;
    可以对文章进行点赞;
    在首页可以按文章的发布时间或者文章的点赞数进行排序显示;
    文章信息 HASH 来存储

    文章包括标题、作者、赞数等信息,在 Redis 中使用 HASH 来存储每种信息以及其对应的值的映射

    Redis 使用命名空间的方式来实现类似表的功能、命名空间可以扩展树的深度 set test1:test2:test3 123 类似json

    键名的前面部分存储空间名,后面部分存储空间 ID,整个组成Hash的健名

    使用【冒号 : 】分隔。例如下面的 HASH 的键名为 article:92617,其中 article 为命名空间,ID 为 92617。

    点赞功能

    建立文章的已投票用户集合,set交集操作检查是否已点过赞

    点赞 votes 字段进行加 1 操作

    设置一周的过期时间,过后就不能再点赞

    对文章进行排序 zset

    为建立一个文章发布时间的有序集合和一个文章点赞数的有序集合

    redis与数据库的同步 数据一致

    一、一致性要求高场景,实时同步方案,即查询redis,若查询不到再从DB查询,保存到redis;

    更新redis时,先更新数据库,再将redis内容设置为过期(建议不要去更新缓存内容,直接设置缓存过期),再用ZINCRBY增量修正redis数据

    二、并发程度高的,采用异步队列的方式,采用kafka等消息中间件处理消息生产和消费

    三、阿里的同步工具canal,实现方式是模拟mysql slave和master的同步机制,监控DB bitlog的日志更新来触发redis的更新,解放程序员双手,减少工作量

    四、利用mysql触发器的API进行编程,c/c++语言实现,学习成本高。

    redis新数据定时同步到数据库过程:

    定时任务定时同步redis与数据库的数据,
    数据库里存储着原始数据,通过数据库的数据和redis对比,得出需要更新的数据
    2.在更新过程中,redis的数据还在增长

    需先读redis的数据,记下时间;
    再查询指定时间段里的数据库的数据;
    再用ZINCRBY增量修正redis数据,而不是直接用ZADD覆盖redis数据
     

    热数据与Mysql的同步编码实现 数据库上锁

    热点数据(经常会被查询,但是不经常被修改或者删除的数据),首选是使用redis缓存

    用spring的AOP来构建redis缓存的自动生产和清除,过程如下:

    Select 数据库前查询redis,有的话使用redis数据,放弃select 数据库,没有的话,select 数据库,然后将数据插入redis
    update或者delete 数据库数据
    高并发的情况下:先对数据库加锁,再删除redis
    查询redis是否存在该数据,若存在则先对数据库加行锁,再删除redis,再update或者delete数据库中数据
    update或者delete redis,先更新数据库,再将redis内容设置为过期(建议不要去更新缓存内容,直接设置缓存过期)
     

    出错场景:update先删掉了redis中的该数据,这时另一个线程执行查询,发现redis中没有,瞬间执行了查询SQL,并且插入到redis

    使用案例

    1.计数器 string

    单线程,避免并发问题,保证不会出错,毫秒级性能

    命令:INCRBY incrby

    2.队列 list 简单消息队列、用户第几个访问、新闻列表排序

    由于redis把数据添加到队列是返回添加元素在队列的第几位,所以可以做判断用户是第几个访问这种业务

    新闻列表页面最新的新闻列表,redis的 LPUSH命令构建List

    3.在线状态、签到(大数据处理)

    几亿用户系统的签到,去重登录次数统计,用户是否在线状态

    setbit、getbit、bitcount命令

    原理是:

    redis内构建一个足够长的数组,每个数组元素只能是0和1两个值

    数组的下标index用来表示我们上面例子里面的用户id

    4.hash实现幂等性请求

    (hash实现幂等性请求)验证前端的重复请求,通过redis进行过滤:每次请求将request ip、参数、接口等hash作为key存储redis,设置多长时间有效期,然后下次请求过来的时候先在redis中检索有没有这个key,进而验证是不是一定时间内过来的重复提交
    5.秒杀系统(防止超卖),单线程特征,自增,无并发问题 string

    6.全局增量ID生成 生成全局唯一商品序列号、插入数据重复问题

    7.排行榜 zrevrank 查看前n名 ZRANGE 查看所有排名 O(log(N))

    谁得分高谁排名往上。命令:ZADD(有序集)

    给Alice投票 redis> zincrby vote_activity 1 Alice "1"

    给Bob投票 redis> zincrby vote_activity 1 Bob "1"

    给Alice投票 redis> zincrby vote_activity 1 Alice "2"

    查看Alice投票数 redis> zscore vote_activity Alice ----"2"

    获取Alice排名(从高到低,zero-based ) redis> zrevrank vote_activity Alice (integer) 0

    获取前10名(从高到低) redis> zrevrange vote_activity 0 9 1) "Alice" 2) "Bob"

    获取前10名及对应的分数(从高到低) redis> zrevrange vote_activity 0 9 withscores "Alice" "2" "Bob" "1"

    获取总参与选手数 redis> zcard vote_activity (integer) 2

    score相同,排序逻辑是按照key的字母序排序,同分数情况下按时间排序,key加上时间戳前缀

    通过ZRANK可以快速得到用户的排名

    通过ZRANGE可以快速得到TOP N的用户列表,它们的复杂度都是O(log(N)),

    STRING

    > set hello world OK > get hello "world" > del hello (integer) 1 > get hello (nil)

    LIST

    > rpush list-key item (integer) 1 > rpush list-key item2 (integer) 2 > rpush list-key item (integer) 3 > lrange list-key 0 -1 1) "item" 2) "item2" 3) "item" > lindex list-key 1 "item2" > lpop list-key "item" > lrange list-key 0 -1 1) "item2" 2) "item"

    SET

    > sadd set-key item (integer) 1 > sadd set-key item2 (integer) 1 > sadd set-key item3 (integer) 1 > sadd set-key item (integer) 0 > smembers set-key 1) "item" 2) "item2" 3) "item3" > sismember set-key item4 (integer) 0 > sismember set-key item (integer) 1 > srem set-key item2 (integer) 1 > srem set-key item2 (integer) 0 > smembers set-key 1) "item" 2) "item3"

    HASH

    > hset hash-key sub-key1 value1 (integer) 1 返回是否存在该键值 > hset hash-key sub-key2 value2 (integer) 1 > hset hash-key sub-key1 value1 (integer) 0 查询不到该键值 > hgetall hash-key //查询所有键值 1) "sub-key1" 2) "value1" 3) "sub-key2" 4) "value2" > hdel hash-key sub-key2 //删除键 (integer) 1 > hdel hash-key sub-key2 (integer) 0 > hget hash-key sub-key1 //根据键,查询值 "value1"

    ZSET Sorted Set

    SkipList + HashTable

    > zadd zset-key 728 member1 (integer) 1 > zadd zset-key 982 member0 (integer) 1 > zadd zset-key 982 member0 (integer) 0 > zrange zset-key 0 -1 withscores 1) "member1" 2) "728" 3) "member0" 4) "982" > zrangebyscore zset-key 0 800 withscores 1) "member1" 2) "728" > zrem zset-key member1 (integer) 1 > zrem zset-key member1 (integer) 0 > zrange zset-key 0 -1 withscores 1) "member0" 2) "982"

     
    ————————————————
    版权声明:本文为CSDN博主「zzpueye」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zzpueye/article/details/81451916

  • 相关阅读:
    CPSR_cxsf
    C的xml编程libxml2(转)
    showModalDialog 使用详解
    SecureCRT 6.7.4 安装
    Nokia Qt SDK 1.1的开发环境的搭建
    ARM寄存器介绍
    ucos在xp平台下开发环境搭建
    用JavaScript实现让浏览器停止载入页面
    makefile变量使用及其条件判断
    Makefile中指示符“include”、“include”和“sinclude”的区别
  • 原文地址:https://www.cnblogs.com/PerfectBeauty/p/11506621.html
Copyright © 2011-2022 走看看