redis学习笔记

redis(Remote Dictionary Server)

简介

C语言开发的开源高性能键值对(key-value)数据库(性能高的主要原因)。

特征:

  1. 数据间没有必然的关联关系
  2. 内部采用单线程机制进行工作
  3. 高性能。50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s。
  4. 多数据类型支持
    • 字符串类型:string
    • 列表类型:list
    • 散列类型:hash
    • 集合类型:set
    • 有序集合类型:sorted_set
  5. 持久化支持。可以进行数据灾难恢复(比如断电)。

应用:

  1. 为热点数据加速查询(主要场景),如热点商品、热点新闻、热点资讯、推广类等高访问量信息等。
  2. 任务队列,如秒杀、抢购、购票排队等(redis作为缓存);运营平台监控到的突发高频访问数据:突发时政要闻,被吃瓜群众围观(redis作为缓存);高频复杂的统计数据:在线人数、投票(redis作为缓存)。
  3. 即时信息查询,如各位排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等。
  4. 时效性信息控制,如验证码控制、投票控制等。
  5. 分布式数据共享,如分布式集群架构中的session分离
  6. 消息队列
  7. 分布式锁
  8. 附加功能(系统功能优化或升级):单服务器升级集群、session管理、token管理

下载

Linux版(适用于企业级开发):

  • redis高级开始使用
  • 4.0版本挺好

Windows版本(适合学习):

在这里插入图片描述

下载后解压即可

  • 说明:

    • redis-server.exe是服务器,先双击启动

    • redis-cli.exe是用于操作的客户端,后双击启动(装逼:D:;cd Environments;cd r+按下Tab键提醒redis-x64-3.2;redis-cli;启动客户端成功)

      ps:dir对应Linuxls命令

    • redis-check-aof.exe用于持久化用的

    • redis-benchmark.exe是用于性能测试的

  • 端口号:6379(默认)

命令行操作

  • 增加(修改)

    set key value

    如:set name lalala

  • 查询

    get key

    如果不存在,返回空(nil),如

    get name

  • 清除屏幕信息命令

    clear(windows)

    不同操作系统不一样

  • 查看帮助信息

    help 命令名称

    查看命令使用方式

在这里插入图片描述

help @组名

获取组中所有命令信息名称

在这里插入图片描述

在这里插入图片描述

ps:此命令可直接输入也可help+空格,然后用Tab键进行选择。其中get keyset key value命令就属于@string组中。

  • 退出

    quit

    exit

    esc键

数据类型(常用)

  • string

    字符串,如果字符串以整数的形式展示,可以作为数字操作使用。

    数据库中热点数据key的命名约定:表名:主键名:主键的值:字段名,如:order:id:372637247:name

    • 基本操作

      增(修改):set key value;多个数据:mset key1 value1 key2 value2 ...

      获取:get key;多个数据:get key1 key2 ...

      删除:del key,(integer)1代表运行结果成功,(integer)0代表运行结果失败,适用于string的所有操作

      获取数据字符串长度:strlen key

      追加信息到原来的信息后部(如果原始信息存在就追加,否则就新建):append key value

      ps:(integer)+数字指运行结果是否成功,还是表示运行结果值(1个2个3个),具体要看给出的指令;数据的最大存储量:512MB;

    • 扩展操作

      需求:大型企业应用中,使用多张表存储同类型数据,但是对应的主键id必须保证统一性,不能重复(主要问题在这)。Oracle数据库具有sequence设定,可以解决此问题,但mysql数据库并不具有类似的机制,求解决办法。

      解决方法:

      1)设置数据增加指定范围的值

      incr key //如果是数字字符串,使得加1
      incrby key increment //如果是数字字符串,使得增加指定值(整数)
      incrbyfloat key increment //如果是数字字符串,使得增加指定小数
      

      2)设置数据减少指定范围的值

      decr key //如果是数字字符串,使得减1
      decrby key increment //如果是数字字符串,使得减少指定值(整数)
      

      ps:按数字进行操作的数据,如果原始数据不能转换成数字,或超出redis数字上限(java的long类型的最大值),将报错。

      用此方法,redis可以用于控制数据库表主键id,为数据库表主键提供生成策略,保障数据库表的主键唯一性,适用于所有数据库,且支持数据库集群。

      redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无序考虑并发带来的数据影响。

      需求:投票,每四个小时只能投一票(不能一直不间断投啊)

      解决方案:

      设置数据的生命周期:

      setex key seconds value
      psetex key milliseconds value //一个是秒,一个是毫秒
      

      需求:主页高频访问信息显示控制,例如新浪微博大V(应该是用户吧)主页显示粉丝数与微博数量

      解决方案:

      1)在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可,如:

      set user:id:372637247:fans 122383
      set user:id:372637247:blogs 666
      

      2)在redis中以json存储大V用户信息,定时刷新(也可hash类型),如:

      set user:id:372637247 {id:372637247,blogs:666,fans:122383}
      
  • hash(存储的数据有点像是对象的格式)

    数据少时,用的数组存储,多就类似于HashMap的方式

    • 基本操作

      增加(修改)数据

      hset key field value;多个数据:hmset key field1 value1 field2 value2...

      获取数据

      hget key field;多个数据:hmget key field1 field2...

      hgetall key(获取全部字段,如果字段过多,遍历会使得效率很低,有可能成为数据访问瓶颈)

      删除数据

      hdel key field1 field2...

      获取哈希表中字段(field)的数量

      hlen key

      获取哈希表中是否存在指定的字段

      hexists key field

    • 扩展操作

      获取哈希表中所有字段名(field)或字段值

      hkeys key

      hvals key

      设置指定字段的数字增加指定值(上面已经提过类似的)

      hincrby key field increment

      hincrbyfloat key field increment

      ps:hash类型下的value只能存储字符串;每个hash可以存储2^32-1个键值对

      需求:电商网站购物车设计与实现(仅分析购物车的redis存储模型:添加、浏览、更改数量、删除、清空)

      解决方案:

      第一步(存储,还没有起到加速作用):以客户id作为key,为每一位客户创建一个hash类型存储对应的购物车信息;将商品编号作为field,购买数量作为value进行存储;添加商品:追加全新的field与field;浏览:遍历hash;更改数量:redis的增减命令或直接设置value值;删除商品:删除field;清空:删除key

      第二步:购物车每条商品记录保存成两条field;field1用于保存购买数量:命名:商品id:nums,保存数据:数字;field2用于保存购物车中显示的信息,包含文字描述、图片地址、所属商家信息等:命名:商品id:info,保存数据:json。示例如下:

      hmset 003 g01:nums 100 g01:info {...}
      

      第三步:将field2做成一个独立的公共hash,这样会导致公共的商品信息频繁更改,这样解决:hsetnx key field value(如果key的field有值,就什么都不做,没值就添加),如:hsetnx 003 g01:nums 400(其值还是100),所以公共信息就不会频繁更改了。

      需求:抢购移动、联通、电信的30、50、100元的手机充值卡,每一种抢购上限为1000张

      解决方案:

      商家(移动等)id作为key,参与抢购的充值卡id作为field、相应的数量作为value,抢购时使用降值(hincrby+负数,因为另一种降值,hash不提供)方式控制充值卡数量。示例:

      hmset p01 c30 1000 c50 1000 c100 1000
      hincrby p01 c50 -1
      

      ps:string存储对象(json)与hash存储对象:前者强调整体,以读为主;后者更新比较灵活

  • list

    保存多个数据,底层使用双向链表存储

    • 基本操作

      增加(修改)数据

      lpush key value1 value2...(从左边进)

      rpush key value1 value2...(从右边进)

      获取数据

      lrange key start stop(开始和结束位置;lrange key 0 -1:可以查看全部内容,因为-1代表倒数第一个元素)

      lindex key index

      llen key

      获取并移除数据

      lpop key(从左边出)

      rpop key(从右边出)

      ps:list中保存的数据都是string类型的,最多2^32-1个元素。

      list可以对数据进行分页操作,通常第1页的信息来自list(提高效率),第2页及后面的信息通过数据库的形式加载(妙啊)。

    • 扩展操作

      规定时间内获取并移除数据

      blpop key1 key2... timeout(从左边出,在timeout的时间内一直等着,直到时间结束)

      brpop key1 key2... timeout(从右边)

      需求:朋友圈点赞,要求按照点赞顺序显示点赞好友信息,如果取消点赞,移除对应好友信息。

      解决方案:增加用rpush就好,移除用lrem key count value(从左边remove,即删除),如:rpush list1 a b c d e;lrem list1 1 d(count代表移除多少个,因为有可能有重复元素,value代表移除谁)。

      需求:微博中个人用户的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面。

      解决方案:用list

  • set

    与hash存储结构完全相同,仅存储hash中的field,不存储值(nil),不允许重复。

    • 基本操作

      增加数据

      sadd key member1 member2...

      获取全部数据

      smembers key

      删除数据

      srem key member1 member2...

      获取集合大小

      scard key

      判断集合中是否包含指定数据

      sismember key member

    • 扩展操作

      集合的交、并、差集

      sinter key1 key2...
      sunion key1 key2...
      sdiff key1 key2...
      

      求出两个集合的交、并、差集后存储到指定集合中

      sinterstore destination key1 key2...
      sunionstore destination key1 key2...
      sdiffstore destination key1 key2...
      

      将数据从原来的集合移到另一个集合中

      smove soure destination member

      需求:app首次使用时会设置3项兴趣,后期为了增加用户的活跃度,必须让用户对其他类别的信息逐渐产生兴趣,增加客户留存度

      解决方案:1)系统先分析出客户没有关注的各个分类的最热点信息条目并组织成set集合。2)随机挑选出其中部分信息。3)配合用户关注分类中的热点信息组织成展示的信息集合。

      随机获取集合中指定数量的数据

      srandmember key count

      随机获取集合中的某个数据并将该数据移除集合

      spop key [count]

      ps:set应用于同类信息的关联搜索,一度关联搜索,二度关联搜索:显示共同关注(一度);显示共同好友(一度);从用户A出发,获取到好友用户B的好友信息列表(一度);从用户A出发,获取到好友用户B的购物清单列表(二度)。

      可以用于屏蔽爬虫用户(黑名单),对于安全性更高的应用访问,可以设定可访问的用户群体(白名单)。

  • sorted_set

    有序(根据自身特征)的set(没错,就是上方的set),在set的基础上添加可排序字段。

    • 基本操作

      增加数据

      zadd key score1 member1 score2 member2...

      获取全部数据

      zrange key start stop [withscores] //zrange scores 0 -1(升序,不显示排序字段)
      //zrange scores 0 -1 withscores(升序,显示排序字段)
      zrevrange key start stop [withscores]//反序,后面的同上
      

      删除数据

      zrem key member1 member2...

      按条件获取数据

      zrangebyscore key min max [withscores][limit]//查询min、max范围之内的数据,limit限制数据条数,如zrangebyscore length 50 99 limit 0 3 withscores,查询范围之内的3条数据,是的,没错,前3条数据。
      zrevrangebyscore key max min [withscores]//反序
      

      ps:limit后面跟的是offset和count:作用于查询结果,表示开始位置和数据总数

      按条件删除数据

      zremrangebyrank key start stop//删除两个索引内的数据,包含边界,两边都包含
      zremrangebyscore key min max//删除范围之内的数据
      

      获取集合大小

      zcard key
      zcount key min max//范围之内的数据总数
      

      集合交、并操作(并存储)

      zinterstore destination numkeys key1 key2...//numkeys指的是要操作的集合个数,若numkeys为3,后面的key就要有3个,求交之后相同数据的排序字段的值会加在一块
      zunionsstore destination numkeys key1 key2...
      
    • 扩展操作

      需求:各类资源网站TOP10

      解决方案:sorted_set排序即可

      获取数据对应的索引(排名)

      zrank key member//由小到大的索引
      zerevrank key member//由大到小的索引
      

      score值获取与修改

      zscore key member//获取对应的score值
      zincrby key increment member//增加指定值
      

      ps:score,即排序字段可以是整数也可以是小数(双精度double值,可能会丢失精度:0.5->2-1、0.125->2-3,但是0.3这样的数字无法精准描述,俺之前看到的资料说,这是会有四舍五入的),有范围。

      需求:视频VIP,当VIP体验到期之后如何有效管理此类信息

      解决方案:将处理时间记录为score值,利用排序功能区分处理的先后顺序;记录下一个要处理的时间,到期后处理对应任务,移除redis中的记录,并记录下一个要处理的时间;当新任务加入时,判定并更新当前下一个要处理的任务时间;为提升性能,通常又会按 1小时内、1天内、1周内分成若干个sorted_set。示例:

      zadd ts 1539849 uid:001
      zadd ts 1539945 uid:002
      zrange ts 0 -1 withscores//根据排序结果001用户先到期
      

      获取当前系统时间

      time

      需求:当任务或消息待处理,形成了任务或消息队列时,对于高优先级的任务要保障对其有限处理,如何实现权重管理

      解决方案:采用score记录权重即可。示例:

      zadd tasks 4 order:id:005
      zadd tasks 9 order:id:345//排序后先执行该任务,执行完后移除
      zrem tasks order:id:345
      

ps:数据类型指的是key-value的value部分的类型,key只能是字符串

通用命令

key通用命令
  • key是一个字符串

  • 基本操作

    • 删除指定key

      del key

    • 获取key是否存在

      exists key

    • 获取key的类型

      type key

  • 扩展操作

    • 为key设置有效期

      expire key seconds
      pexpire key milliseconds//此命令设置毫秒时间
      expireat key timestamp//使用时间戳,通常在Linux系统中使用时间戳
      pexpireat key milliseconds-timestamp
      
    • 获取key的有效时间(还剩多少时间)

      ttl key//还剩多少秒,超过设定的时间,返回-2,永久的数据返回-1
      pttl key//配套毫秒
      
    • 切换key从时效性转换为永久性

      persist key

    • 查询key

      keys pattern

      keys *//查看所有的key
      key yyh*//查询所有以yyh开头的
      key *yyh//查询所有以yyh结尾的
      key ??yyh//查询长度为5,以yyh结尾的
      key yyh?//查询长度为4,以yyh开头的
      key y[yz]h//查询以y开头,以h结尾,中间包含一个字母:y或z的
      

      规则:*匹配任意数量的任意符号 ?匹配一个任意符号 []匹配一个指定符号

    • 给key改名

      rename key newkey//如果newkey已经存在,那么原来的key的value将覆盖newkey的value(string类型的)
      renamenx key newkey//解决上面会覆盖的问题,如果newkey已经存在,更改将会失败
      
    • 对所有key排序(用于排序list、set、sorted_set里面的元素)

      sort key [desc]//list、set、sorted_set的key名称,不会更改原数据的位置
      
    • 其他key通用操作

      help @generic//看key的全指令(generic组)

数据库通用命令

redis为每个服务提供有16个数据库,编号从0到15;每个数据库之间的数据相互独立。

  • 切换数据库

    select index//index是0~15,默认操作的是0号

  • 数据移动

    move key db//移动key到几号数据库,如果目标库有该key,则移动失败

  • 数据清除

    dbsize//当前库有多少个key
    flushdb//清除当前数据库的key
    flushall//清除所有数据库的key
    
  • 其他操作

    quit//退出
    ping//测试服务器是否连通,连通返回PONG,没有连通则不会有反应,如果是ping abc,则控制台会打印"abc"
    echo message//相当于system.out.println("message")
    

jedis

简介

java操作redis的工具,java还有其他的连接redis的方法:spring data redis(这个好)、lettuce。

jedis对应的方法名与redis里面的指令完全相同。

demo
  • 依赖

    		<dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.9.0</version>
            </dependency>
    
  • 代码

    	@Test
        public void helloJedis(){
            //连接redis
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            //操作redis
            jedis.set("message","helloJedis");
            String message = jedis.get("message");
            System.out.println(message);
            //关闭连接
            jedis.close();
        }
    
Jedis工具类
public class JedisUtils {
    private static JedisPool jp = null;
    private static String host;
    private static int port;
    private static int maxTotal;
    private static int maxIdle;
    static {
        ResourceBundle rb = ResourceBundle.getBundle("redis");//redis配置文件名
        host = rb.getString("redis.host");
        port = Integer.parseInt(rb.getString("redis.port"));
        maxTotal = Integer.parseInt(rb.getString("redis.maxTotal"));
        maxIdle = Integer.parseInt(rb.getString("redis.maxIdle"));
        //JedisPool类是jedis提供的连接池,构造方法的参数有:GenericObjectPoolConfig poolConfig,String host,int port
        //poolConfig:连接池配置对象,host:redis地址,port:redis端口
        JedisPoolConfig jpc = new JedisPoolConfig();
        jpc.setMaxTotal(maxTotal);//按照连接池思想,设置连接池最大连接数
        jpc.setMaxIdle(maxIdle);//设置活动连接数
        jp = new JedisPool(jpc,host,port);
    }

    public static Jedis getJedis(){
        return jp.getResource();
    }
}
redis.host = 127.0.0.1
redis.port = 6379
#按照连接池思想,设置连接池最大连接数
redis.maxTotal = 30
#设置活动连接数
redis.maxIdle = 10

高级

Linux下安装redis
  • 下载

    wget http://download.redis.io/releases/redis-4.0.0.tar.gz

  • 解压(在/usr/local/src目录下)

    tar -xvf redis-4.0.0.tar.gz

  • 安装

    cd redis-4.0.0

    make install

  • 报错

    开始报127错误,解决如下:

    yum install cpp
    yum install binutils
    yum install glibc
    yum install glibc-kernheaders
    yum install glibc-common
    yum install glibc-devel
    yum install gcc
    yum install make
    

    然后报c里面的错:

    In file included from adlist.c:34:0: zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录
    

    解决办法:https://blog.csdn.net/Hello_word_2/article/details/82981505?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control

  • 启动

    /usr/local/src/redis-4.0.0/src目录下执行:

    redis-server

    redis-cli

  • 指定端口启动

    redis-server --port 6380

    redis-cli -p 6380或者redis-cli -h 127.0.0.1 -p 6380

    –port和-p应该是一样的

  • 指定配置文件启动

    cat redis.conf | grep -v "#" | grep -v "^$"//第二部分是查看的内容去掉注释,第三部分是去掉注释之后会有空白,将空白也去掉,然后进行查看
    cat redis.conf | grep -v "#" | grep -v "^$" > redis-6379.conf//将输出的内容新生成一个文件
    

    配置项:

    daemonize no:为no时,控制台会打印日志信息,改成yes之后以守护线程启动,就会在后台启动

    logfile "":后台启动时的日志文件名(不含位置)

    dir ./:对应日志文件生成的位置

    修改配置文件如下:

    port 6379
    daemonize yes
    logfile "6379.log"
    dir /usr/local/src/redis-4.0.0/data
    

    启动:

    redis-server redis-6379.conf
    ps -ef | grep redis//查看启动进程,要启动多个只需要多复制几个配置文件,修改里面的端口和日志文件名就行了,如下:
    
    redis-server conf/redis-6380.conf  //在redis-4.0.0下专门建一个文件夹保存配置文件
    
持久化(用于灾难性恢复)

将内存中的数据与硬盘之间做了一个关联(看来redis确实适合用来做缓存)。

  • 将当前数据状态(快照)进行保存,存储数据结果,关注点在数据。redis叫RDB
  • 把这个数据的操作过程记录下来(比如ctrl+z),就是日志形式,关注点在于数据的操作过程。redis叫AOF

RDB的指令及配置

命令:save

手动执行一次保存操作,生成的数据保存在之前设定的data目录中,是dump.rdb文件。当kill掉redis的进程之后,再次启动时redis保存的数据还在(没有执行save,再次启动就没有数据了)

配置:dbfilename dump.rdb

设置保存的文件名,默认值为dump.rdb,通常设置为dump-端口号.rdb

配置:dir

不仅对应日志文件生成的位置,也对应.rdb文件的路径,通常设置的目录名称为data

配置:rdbcompression yes

设置save时保存的文件是否压缩,默认为yes,采用LZF压缩,如果设置为no,可以节省cpu运行时间,但会使存储的文件变得巨大。

配置:rdbchecksum yes(不用看)

设置是否进行RDB文件格式校验(万一该文件损坏了,所以校验),该校验过程在写文件和读文件过程均进行,默认为yes,如果设置为no,可以节约读写过程约10%时间消耗,但是存在数据损坏的风险。

注意:因为redis是单线程(执行的时候像从栈里弹出去一个个的方法),save指令会阻塞当前redis服务器,直到当前RDB过程完成为止,如果save的时间过长,会影响效率,线上环境不建议使用save。解决办法如下:

命令bgsave

手动启动后台保存操作,但不是立即执行(原理是调用fork函数生成一个子进程)。因此对于RDB可以放弃save命令的使用。

配置:stop-writes-on-bgsave-error yes(了解)

bgsave的专用配置:如果后台存储过程中出现错误,是否停止保存,默认yes

配置:save second changes

满足限定时间范围内key的变化达到指定值即进行持久化,second:时间范围,changes:key的变化(包括增加、删除和更新)指定值,比如:save 300 10。(这样的配置方式执行的是bgsave)

方式save命令bgsave命令save配置(同bgsave命令)
读写同步异步
阻塞客户端指令
额外内存消耗
启动新进程

ps:RDB特殊启动形式:全量复制:请看主从复制;服务器运行过程中重启:debug reload;关闭服务器时指定保存数据:shutdown save。rdb的缺点:因为基于快照,所以数据量大;无法实时(时时刻刻)持久化;有子进程会牺牲性能;redis的众多版本中RDB的文件格式没有统一。

AOF的指令及配置

以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到数据恢复的目的。主要解决了实时持久化的问题,目前是主流方式。

AOF的三种策略:

always(每次):每次写入操作(即get操作不算)均同步到AOF文件中,数据0误差,性能较低,不建议使用

everysec(每秒):每秒将缓冲区的指令同步到AOF文件中,数据准确性较高,性能较高,默认配置,同时也建议使用,在系统突然宕机的情况下丢失1秒内的数据

no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控

配置:appendonly yes/no

是否开启AOF持久化,默认关闭

配置:appendfsync always/everysec/no

AOF策略

配置:appendfilename filename

AOF持久化文件名,默认appendonly.aof,建议改为appendonly-端口号.aof

配置:dir

同RDB

概念:AOF重写

  • 将对同一个数据的若干条命令执行结果转化为最终结果对应的命令进行记录,好处是:降低磁盘占用;提高持久化效率;提高数据恢复效率(即用时减少,因为命令少了嘛)

  • 重写规则:1.进程内已超时的数据不再写入文件;2.使用进程内数据直接生成AOF文件,只保留数据的最终写入命令(包括增删改,查当然不用管);

  • 重写方式:

    • 手动重写:

      命令:bgrewriteaof//原理和bgsave非常像(会有子进程)

    • 自动重写(激活的也是上面的命令)

      配置:auto-aof-rewrite-min-size size//自动重写触发的文件大小(aof_current_size>size),默认值不同版本不一样:32M、64M

      ps:对比参数为:aof_current_size//当前大小(info Persistence获取该信息,在客户端输入)

      配置:auto-aof-rewrite-percentage percentage//自动重写触发的百分比((aof_current_size-aof_base_size)/aof_base_size>=percentage)

      ps:对比参数:aof_base_size//基础大小(info Persistence获取该信息,在客户端输入)

对比

持久化方式RDBAOF
占用空间小(数据级,可以压缩)大(命令级,可以重写)
存储速度
恢复速度
安全性会丢失数据以策略决定(可以零误差)
资源消耗高/重量级低/轻量级
启动优先级

如何选择:

  1. 如果对数据非常敏感,就AOF
  2. 数据呈现阶段有效性,可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),就RDB
  3. 灾难恢复用RDB
  4. 可以同时开启两者,重启时,redis会优先使用AOF来恢复数据。

持久化应用场景

  1. 抢购,如限购类、限量发放优惠券、激活码等业务的数据存储设计
  2. 最新消息展示(临时的任务,存储量不大)
  3. 具有操作先后顺序的数据控制
  4. 白名单与黑名单设定的服务控制
  5. 按次结算的服务控制
redis的事务
  • 基本操作

    • 开启事务

      multi

      设定开启位置,后续所有命令均加入到事务中

    • 执行事务

      exec

      设定结束位置,同时执行事务,与multi成对出现

    • 取消事务

      discard

      终止当前事务的定义,在multi之后,exec之前

    • 注意:

      如果中途的命令存在语法错误,所有命令均不会执行,包括正确的命令;

      如果中途的命令语法正确,执行结果错误(例如对string类型的name进行lpush),那么能够正确执行的命令会执行,执行结果错误的命令视为无效

    • 回滚(这个有点扯)

      操作之前拷贝一份受影响的数据,然后利用拷贝的数据恢复所有被修改的项

  • 监视锁(像互斥锁)

    • 对key添加监视锁,在执行exec之前如果key发生了变化,终止事务执行

      watch key1 key2...

    • 取消对所有key的监视

      unwatch

      示例:

      127.0.0.1:6379> keys *
      1) "name"
      127.0.0.1:6379> set age 30
      OK
      127.0.0.1:6379> get name
      "lalala"
      127.0.0.1:6379> watch name
      OK
      127.0.0.1:6379> multi
      OK
      127.0.0.1:6379> set sex 1
      QUEUED
      127.0.0.1:6379> exec
      (nil)
      

      exec之前另开一个会话客户端,然后exec就会出现上面的结果(取消执行):

      127.0.0.1:6379> set name hahaha
      OK
      
  • 分布式锁(解决最后一件商品的超卖问题,即被多个用户购买。好像还是互斥锁。)

    setnx lock-key value

    利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功;设置成功的,拥有控制权,进行下一步业务操作,设置失败的,不具有控制权,排队等待;操作完毕之后通过del删掉即释放锁。

    示例:

    set num 10
    setnx lock-num 1
    incrby num -1
    del lock-num
    

    如果在过程中有人也要执行setnx lock-num 1,那么这个操作会返回(integer) 0,这就是锁[doge]。

    ps:expire lock-key second或者pexpire lock-key millisecond为锁设置时效性,如果该用户一直不释放锁,应该让系统(时效性)来释放。锁时间推荐:1.持有锁的最长操作时间xxx毫秒2.测试百万次最长执行时间对应命令的最大耗时和百万次网络延迟平均耗时3.最大耗时x120%+平均网络延迟x110%;如果业务最大耗时<<网络平均延迟(也可能反过来),通常为老哥数量级,取其中单个耗时较长(业务最大耗时或者网络平均延迟)即可。

删除策略

redis是一种内存级数据库,所有数据均放在内存中。

TTL

获取数据的状态:XX(具有时效性的数据)、-1(永久的数据)、-2(已经过期或被删除或未定义的数据)

时效性命令:setex、expire、expireat、pexpire、pexpireat

过期数据的删除策略(目标是在内存占用和cpu占用之间寻找一种平衡,顾此失彼可能会造成:redis性能下降、服务器宕机、内存泄漏):

  • 定时删除(拿时间换空间)

    创建一个定时器,当key过期时,由定时器立马执行对键的删除操作。优点:省内存,到时就删除,缺点:cpu压力大,占用cpu,影响redis服务器响应时间和命令吞吐量

  • 惰性删除(拿内存空间换cpu性能,空间换时间)

    数据到达过期时间,不做处理,等下次访问数据时删除。优点:节约cpu性能,缺点:内存压力增大,出现长期占用内存的数据

  • 定期删除(折中方案,随机抽查,重点删除)

    对每个数据库(0到15)轮询,每次执行250ms/server.hz时间,对某个数据库检测时,随机挑W个key检测,如果key过期,则删除key(若删除的key>Wx25%,对剩下的再挑W个,然后进行同样的操作,循环;若删除的key<=Wx25%,则检测下一个数据库)。

    特点:cpu占用有峰值;内存压力不大(长期占用内存的数据会被持续清理)

    ps:W=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值(在配置文件配置),参数current_db用于记录执行到了哪一个数据库。

逐出算法

如果内存不满足新加入数据的最低存储要求,redis会临时删除一些数据为当前命令清理存储空间(如果不成功,则反复执行,所有尝试完毕后,还是不能满足要求,将出现错误信息),清理的策略称为逐出算法。

  • 相关配置

    • 最大可使用内存

      maxmemory

      占用物理内存的比例,默认为0,表示不限制。

    • 每次选取待删除数据个数

      maxmemory-samples

      采用随机获取数据的方式作为待检测删除数据。

    • 删除策略

      maxmemory-policy

      对被挑选出来的数据进行删除的策略,选项如下:

      检测易失数据(可能会过期的数据:db[i].expires):

      volatile-lru//挑选最近最少使用(get)的数据淘汰,建议设置
      volatile-lfu//挑选最近使用次数最少的数据淘汰
      volatile-ttl//挑选将要过期的数据淘汰
      volatile-random//任意选择数据淘汰
      

      检测全库数据(所有数据db[i].dict):

      allkeys-lru//挑选最近最少使用(get)的数据淘汰
      allkeys-lfu//挑选最近使用次数最少的数据淘汰
      allkeys-random//任意选择数据淘汰
      

      放弃数据逐出

      no-enviction//放弃逐出数据(4.0版本默认),可以引发OOM错误
      

      示例:

      maxmemory-policy volatile-lru
      

      逐出策略配置的依据:

      info//这会输出监控信息,查询缓存hit(命中)和miss(丢失)的次数,根据需求调优redis配置
      
配置文件redis.conf
  • 服务器基础配置

    • 服务器以守护进程的方式运行

    • 绑定主机地址(绑定后只能通过这个ip访问)

      bind 127.0.0.1

    • 服务器端口号

      port 6379

    • 设置数据库数量

      databases 16//就是那个0到15,默认值就是16

    • 设置服务器以指定日志记录级别

      loglevel debug/verbose/notice/warning默认值是verbose

      ps:开发设置为verbose,生产环境(线上)设置为notice(简化日志输出,降低写日志IO的频度)

    • 日志文件名

      logfile 端口号.log

    • 设置同一时间最大客户端连接数,默认无限制。达到上限时,redis会关闭新的连接

      maxclients 0

    • 客户端闲置等待最大时长,超时直接关闭连接。关闭该功能:设置为0

      timeout 300//300秒

    • 导入并加载指定配置文件信息,用于快速创建公共配置较多的redis实例配置文件(多个redis服务器),便于维护

      include /path/server-端口号.conf

高级数据类型
Bitmaps(按位操作)
  • 基础操作

    • 获取指定key对应偏移量上的bit值

      getbit key offset

    • 设置指定key对应偏移量上的bit值,0或1

      setbit key offset value

      ps:每一位bit默认为0。

  • 扩展操作

    • 对指定key进行交、并、非、异或操作,并将结果保存到destKey中

      bitop op destKey key1 key2...//and:交;or:并;not:非;xor:异或

    • 统计指定key中1的数量

      bitcount key [start end]

HyperLogLog

基数(不重复的元素的个数),此数据类型用于统计基数

  • 基本操作

    • 添加数据

      pfadd key element

    • 统计基数

      pfcount key

    • 合并数据

      pfmerge destkey key1 key2...

    ps:此数据类型里面添加的数据无法读出,它只统计基数;此类型的核心是一个基数估算算法,最终数值存在一定误差,基数估计的结果是一个带有0.81%标准错误的近似值;消耗空间极小,每个此类型的key占用12K(上限值)的内存;合并操作后占的存储空间一定是12K。

GEO

点与点之间的关联操作,即地理位置计算

  • 基本操作

    • 添加坐标

      geoadd key longitude latitude member//经度和纬度,member是指坐标的名称

    • 获取坐标

      geopos key member

    • 计算坐标点距离

      geodist key member1 member2 [unit]//unit指单位,如:m表示米(默认值)

      示例:

      geoadd geos 1 1 a
      geoadd geos 2 2 b
      geodist geos a b km//km表示千米
      
    • 根据坐标求范围内的坐标

      georadius key longitude latitude radius m/km/ft/mi [withcoord] [withdist] [withhash] [count count]//后面的参数了解就行

    • 根据坐标名称求范围内坐标

      georadiusbymember key member radius m/km/ft/mi [withcoord] [withdist] [withhash] [count count]

    • 获取坐标hash值

      geohash key member

主从复制

高并发、高性能、高可用。

架构跟mongodb集群很像:master是主节点(提供数据,可读写),slave是从节点(接收数据,只能读),核心工作是master的数据同步到slave中。

这样可以大大提高redis服务器的并发量与数据吞吐量,当master出现问题时,由slave实现快速的故障恢复。

这里出现了持久化之外的数据备份方式:数据热备份。

基于主从复制,构建哨兵与集群,实现redis的高可用方案

建立master与slave之间的连接
  1. 设置master的地址和端口,保存master信息

    在slave客户端发送:slaveof masterip masterport,这样会保存master的ip和端口

    根据保存的信息创建连接master的socket

    其他方式:1)命令:redis-server -slaveof masterip masterport2)配置:slaveof masterip masterport

  2. 建立socket连接(从此步开始后面的可以忽略)

  3. 在slave客户端周期性发送ping,master响应pong

  4. 身份验证

    在master配置文件设置密码:requirepass password;其他方式:命令:config set requirepass passwordconfig get requirepass

    在slave客户端命令设置密码:auth password,master验证授权;其他方式:配置:masterauth password

    因此在启动客户端时要给出密码:redis-cli -a password

  5. 在slave客户端发送自己的端口给master:repconf listening-port 端口号,master会保存slave的端口号

此时slave有master的地址与端口,master有slave的端口,连接就好了

ps:断开主从,在从客户端发送:slaveof no one

数据同步(主–>从)
  1. 先执行全量同步

    从客户端发送:psync2

    master执行bgsave,生成RDB文件,通过socket发送给slave,slave接收之后便会先清空,然后恢复RDB文件数据

  2. 后执行部分同步

    master将新来的命令发给slave,slave执行重写(bgrewriteaof),同步部分数据。

ps:复制缓冲区大小设定不合理,可能导致数据溢出。如进行全量同步的时候周期太长,到部分同步的时候发现数据已经存在丢失的情况,必须进行第二次全量同步,使得slave进入死循环。解决方法:在master中执行repl-backlog-size 1mb(默认大小1mb)。

在同步时关闭对外服务:配置slave-serve-stale-data yes/no

slave的数量过多时,调整结构:由一主多从结构变为树状结构,中间节点既是master,也是slave,因此深度越深的slave数据同步的延迟越大。

命令传播(到这里主从复制流程就完全结束了)

当master中的数据被修改后,需要让主从同步到一致。

master将接收到的修改命令发送给slave,slave接收到命令后执行命令。

  • 断网

    • 网络闪断闪连

      忽略

    • 短时间网络中断

      部分同步

    • 长时间网络中断

      全量同步

心跳机制

进入命令传播阶段,master和slave间需要进行信息交换,使用心跳机制进行维护,实现双方保持在线。

  • master方的心跳

    • 命令:ping
    • 周期:由repl-ping-slave-period决定,默认10秒
    • 作用判断slave是否在线
    • 查询:info replication,获取slave最后一次连接时间间隔(lag为0或1视为正常)
  • slave方心跳

    • 命令:replconf ack {offset}
    • 周期:1秒
    • 作用:判断master是否在线,并汇报自己的复制偏移量,获取最新的数据变更命令。
  • 注意

    • 当slave多数掉线或者延迟过高时,master将拒绝所有信息同步操作(保障数据稳定)

      min-slave-to-write 2
      min-slave-max-lag 10
      

      当slave数量少于2个,或者slave的连接延迟时长大于等于10时,强制关闭master写功能,停止数据同步。slave数量和延迟都是由slave发送replconf ack命令做确认。

哨兵模式(仲裁、选举模式)

哨兵就是对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。哨兵也是一台redis服务器,只是不存储数据。(像仲裁节点,mongodb表示这个我熟)

配置哨兵
  • 配置1+2的主从结构(1个master,2个slave)

  • 配置三个哨兵(配置相同,端口不同)

    主要在于sentinel.conf

    port  26379 //2+6379
    dir /tmp //哨兵工作信息存储目录
    sentinel monitor mymaster 127.0.0.1 6379 2 //mymaster为自定义的主节点名,2(通常为哨兵的数量的一半加1,所以哨兵数量通常为单数,mongodb表示我熟)表示由两个哨兵认为mymaster挂了,它就挂了
    sentinel down-after-milliseconds mymaster 30000 //多长时间没响应,认定它挂了,30秒
    sentinel parallel-syncs mymaster 1 //此值越小服务器压力越小,速度越慢
    sentinel failover-timeout mymaster 180000 //在进行同步的时候,多长时间同步完成算有效,没完成就算超时,180秒
    
  • 启动哨兵(哨兵启动之后,配置文件会发生变化,与上方的配置不太一样)

    redis-sentinel sentinel-端口号.conf

  • 启动顺序

    启动时,先master,后slave,最后哨兵

cluster集群(不需要哨兵,自带主从切换,即master挂了的时候)

集群可以解决的问题:redis提供的OPS(读写效率,每秒的操作命令数)可以达到10万/秒,当前业务已经达到10万/秒;单机的内存容量256G,业务需求1T。

作用:分散单台服务器的访问压力,实现负载均衡;分散单台服务器的存储压力,实现可扩展性;降低单台服务器宕机带来的业务灾难。

架构

将多个主从结构(若干台计算机)连接在一起,对外提供更大的访问带宽和存储空间,使其对外呈现单机的服务效果。

搭建
  • 配置节点(3主3从)

    配置文件,从6501到6506,如:

    port 6501
    dir "/redis-4.0.0/data"
    dbfilename "dump-6501.rdb"
    cluster-enabled yes
    cluster-config-file "cluster-6501.conf"
    cluster-node-timeout 5000
    

    接着挨个启动,如:

    redis-server conf/redis-6501.conf
    

    创建集群

    redis-cli --cluster create ip1:port1 ip2:port2..ip6:port6 --cluster-replicas n
    

    ​ 一个master对应n个slave,由最后的参数n决定;匹配顺序为第一个master与前n个slave分为一组,以此类推。

    如:redis-cli --cluster create 127.0.0.1:6501 127.0.0.1:6502 127.0.0.1:6503 127.0.0.1:6504 127.0.0.1:6505 127.0.0.1:6506 --cluster-replicas 1

    当在6501(master)操作的时候可能会遇到:(error) MOVED 5798 127.0.0.1:6502类似错误,说这个槽在6502。原因是:分槽(slot)类似于hash位置的计算,所以有这样的状况。解决办法:在启动时这样:redis-cli -c -p 6501(cluster模式启动),操作的时候就会自动跳转到6502

cluster配置

  • 是否启用cluster集群模式,成为cluster节点

    cluster-enabled yes/no

  • cluster配置文件名,该文件自动生成

    cluster-config-file filename

  • 节点服务响应超时时间,用于判断该节点是否下线或切换为从节点

    cluster-node-timeout milliseconds

  • master连接的slave最小数量

    cluster-migration-barrier min_slave_number

cluster节点操作命令

  • 查看集群节点信息

    cluster nodes

  • 添加master到当前集群中,连接时可以指定任意现有节点地址与端口

    redis-cli --cluster add-node newip:port nowip:port

    添加之后分槽方式1(不创建新槽)

    redis-cli --cluster reshard newip:port --cluster-from master-id1,master-id2,master-idn --cluster-to newip-master-id --cluster-slots 槽数量

    指定得到的槽数量(正常情况下是:16384/算上新加之后的总的master数量)之后,这些槽将平均从指定的master们处获取。

    添加之后分槽方式2(从有槽的master中分配指定数量到另一个master中,常用于清空master的槽)

    redis-cli --cluster reshard newip:port --cluster-from master-id --cluster-to newip-master-id --cluster-slots 槽数量 --cluster-yes

  • 添加slave

    redis-cli --cluster add-node newip:port masterip:port --cluster-slave --cluster-master-id masterid

  • 删除节点,如果删除的节点是master,必须保证其中没有槽(slot)

    redis-cli --cluster del-node ip:port del-id

ps:masterid和del-id可以通过cluster nodes查看,第一列就是(最后一列是槽);nowip:port输入集群中的任一个即可。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值