zoukankan      html  css  js  c++  java
  • Redis学习

                        官方网址: www.redis.cn
    • redis支持五大基本数据类型:
    String 
    List
    Set
    Hash
    Zset
    • 三种特殊数据类型:
    geo
    hyperloglog
    bitmap
    • Nosql特点:
    1.方便扩展;   2.大数据量高性能; 3.数据类型是多样的
    • 基本知识
    1. 测试redis是否连接通:
                           redis -cli -h -p 6379   //使用redis客户端进行连接 
                           ping   屏幕自动打印PONG则成功链接
                           keys *    //查看所有key名
                           ps -ef|grep redis   //查看redis的进程是否开启
    1. redis默认有16个数据库,可以用select切换数据库.    查看数据库大小: DBSIZE
    2. 清除当前数据库: flushdb 
    3. 清空所有库: flushall
    4. redis是单线程的.
                    redis是基于内存操作,cpu不影响它,影响它的是机器的内存和带宽,既然可以用单线程实现,就用单线程了.
    1. 速度: cpu > 内存 >  硬盘
    2. redis是单线程的,为什么还快?
                  答: 并不是所有的高性能服务器都是多线程的,并不是所有的多线程(cpu,上下文切换)都比单线程效率高.redis将所有的数据存放在内存中,多线程操作上下文切换会耗时,故对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个cpu上,对于内存情况下,这个方案是最佳的.
    1. 每秒读十亿万次,写8亿万次
    • 涉及命令:
         0. redis不区分大小写命令
         1.判断key是否存在           EXISTS name   ( 返回0代表没有)
          2.移动当前数据库的key名称     move name 1      其中name代表key的名字,可以为任意key名,1代表当前数据库
          3.设置key对应的value值   set name qinjiang       其中name是key名称,qinjiang是对应的value
          4.获取key对应的value值   get name                    其中name是key名称
          5.给key这是过期时间        EXPIRE name 10        其中name是key名称,10代表10s后过期,因为它的单位是秒
             查看当前key的剩余时间  ttl name                     其中name是key名称
          6.查看当前key对应的类型  type name                其中name是key名称
          7.查看所有的key                keys *
          8.当redis类型为String类型是,可使用append追加值,如果当前key不存在,相当于set的作用.     
                         eg: set key1 v1             APPEND key1 "hello"
          9.获取字符串的长度         STRLEN name
         10.相当于i++操作   set views 0(设置初始量为0)     ->  incr views    
         11.相当于自减1操作  set views 3    -> decr views
         12.自定义步长,比如加10操作   set views 0   ->  INCRBY views 10
         13.自定义步长,比如减10操作   set views 19  -> DECRBY views 10
         14.查看字符串范围,eg: 截取字符串[0,3]    set key1 "hello,kuangshen"     ->   GETRANGE key1 0 3     ===》 返回结果为: “hell"
         15. 查看字符串全部内容,主要原因在于-1,等同于get key1           GETRANGE key1 0 -1   
         16.替换指定位置的开始的字符串    set key2 abcdefg     ->    SETRANGE  key2 1 xx    ====> 返回结果为: axxdefg
         17.设置过期时间                                            setex  (set with expire)  
              设置key3的值为hello,30秒后过期             setex key3 30 "hello"    
         18.不存在再设置值,即不存在会创建一个key值,已经存在的话会创建失败(常用在分布式锁中)         
                        setnx (set if not exist)                    ===> 返回结果为1表示成功,为0表示失败
         19.批量设置和获取   mset(原子性操作,要么一起成功,要么一起失败)         mget
                  mset k1 v1 k2 v2 k3 v3
                  mget k1 k2
         20.设置对象,eg:设置user:1对象,值为json字符来保存一个对象.   set user:1 {name:zhangsan,age:3}
              其中key是一个巧妙设计: user:{id}:{filed}
         21.getset    先get然后在set           getset db redis       ==》返回结果为:如果不存在值,则返回nil,如果存在值,获取原来的值,并设置新的值
    • List列表类型详解
         1.在redis里,可以把list适配成栈,队列,阻塞队列
          2.所有的list命令都是用l开头的
          3.将一个或多个值插入到列表头部(左)              LPUSH list one
          4.按范围查找列表    LRANGE list 0 -1        ===>注意返回结果顺序是先进后出
          5.将一个或多个值插入列表尾部(右)       Rpush list two
          6.list移除值   
                        移除list的第一个元素        LPOP  xxx
                        移除list的最后一个元素     RPOP   xxx
         7.通过下表获取列表中的某一个值,索引下标从0开始    lindex list 0
         8.返回列表的长度      Llen 
         9.移除指定的值         lrem list 1 one     移除list集合中指定的1个值,这个值是one.属于精确匹配
         10. 截取   通过指定下标截取所要内容,但是会修改原集合. ltrim 
         11. rpoplpush    移除列表的最后一个元素,并将它移动到新的列表中 
                rpoplpush  mylist myotherlist       //移除mylist列表的最后一个元素,将它移动到myotherlist列表中
         12.将列表中指定下标(这个列表及下标必须存在,否则报错)的值替换为另外一个值,相当于更新操作. lset
                   lset list 0 item
         13.判断一个列表是否存在   EXISTS  list
         14.将某个具体的value插入到列表中某个单词的前面或后面 linsert
                       LINSERT list before || after  已存在元素   新加入元素
                     eg: linsert list before "world"  "other"
    • Set集合类型详解
        1.set集合中添加元素    sadd myset "hello"
        2.查看set中所有值       smembers myset
        3.判断某一个值是不是在set集合中  sismember myset hello         ===>返回结果中0表示不存在,1表示存在
        4.获取set集合中元素个数     scard myset
        5.移除set集合指定元素              srem myset hello
        6 随机抽选一个元素   srandmember myset   
        7.随机抽选出指定元素的个数 srandmember myset 2
        8.随机删除一些set集合中的元素   spop myset
        9.将一个指定的值移动到另一个set集合中     smove myset myset2 "hello"
        10.数字集合类,差集  sdiff              SDIFF key1 key2         以key1为准取差集
                                并集  sunion          SUNION key1 key2     取并集
                                交集  sinter           SINTER key1 key2    并集(比如共同好友)
    •     Hash哈希类型详解
         map集合,本质和String类型差不多,是一个简单的key-value,hash更适合存对象,而String更适合存字符串
         1.set一个具体的key-value    hset myhash field1 hello
         2.获取一个具体的key对应的value     hget myhash field1
         3.set多个key-value       hmset myhash field1 hello field2 world
         4.获取多个字段值         hmget myhash field1 field2
         5.获取全部数据             hgetall myhash 
         6.删除指定的key和value    hdel myhash field1
         7.获取hash内容长度          hlen myhash
         8.判断hash中指定字段key是否存在     hexists  myhash field1
         9.获取hash的所有key         hkeys myhash
        10.获取hash的所有value     hvals  myhash
        11.自增 incrby      自减   decrby
              hincrby  myhash field3 1     key为field3的属性值自增1
              hincrby  myhash field3 -1     key为field3的属性值自增-1,相当于自减1
              decrby  myhash field3 1      key为field3的属性值自减1
        12.如果不存在则可以设置新值,如果存在则创建失败              hsetnx  myhash field4 hello
        13.存对象     hset user:1 name qinjiang
        14.获取对象   hget user:1 name
    •    Zset(有序集合) 
       1.添加元素   zadd myset 1 one    1作为排序的标志
       2.获取所有元素   zrange  myset 0 -1
       3.显示全部内容,从小到大排序.          ZRANGEBYSCORE salary -inf +inf
       4.显示全部的用户并且附带成绩        ZRANGEBYSCORE salary -inf +inf withscores   
       5.显示工资小于2500员工升序排序    ZRANGEBYSCORE salary -inf 2500 withscores
       6.移除指定元素        zrem salary hello
       7.显示全部内容,从大到小排序.         ZREVRANGE salary 0 -1
       8.获取有序集合中元素个数  zcard salary
       9.获取指定区间的成员个数  zcount salary 500 2500
    • Geospatial地理位置详解
       1.官方文档网址:    https:www.redis.net.cn/order/3685.html    , geo命令底层的实现原理其实是Zset,可以使用Zset命令来操作geo
       2.添加地理位置:   geoadd
       3.获取指定城市的经度和纬度    geopos
       4.两个位置之间的距离     geodist                    geodist china:city beijing shanghai km              //km表示单位千米
       5.以某个经纬度为圆心周围内城市                   georadius       
                       georadius china:city 110 30 km withdist              //km是单位   withdist可加可不加,加了能显示二者经纬度直线距离
       6.以某个经纬度为圆心周围内城市的经度和纬度       
                      georadius  china:city 110 30 500 km withcoord      //500表示距离经度110纬度30的直线距离500km范围内,withcoord表示显示他人的经纬度
       7.以某个经纬度为圆心周围内城市的经度和纬度,获取指定数量 
                       georadius  china:city 110 30 500 km withdist withcoord count 3
       8.找出位于指定元素周围的其他元素            GEORADIUSBYMEMBER
                       georadiusbymember china:city beijing 1000 km
    [[   9.geohash  改命令返回11个字符串,将二维的经纬度转换为一维的字符串,如果两个字符串越接近,则距离越近.
    •    Hyperloglog基数统计
      1.创建一组元素    pfadd mykey a b c d  
       2.统计元素基数的数量    pfcount mykey 
       3.合并两组元素 mykey mykey2 => mykey3       PFMERGE mykey3 mykey mykey2      
    • redis基本的事务操作
      1.redis单条命令是保证原子性的,但是事务不保证原子性.
      2.redis事务的本质:一组命令的集合. 
      3.一个事务中的所有命令都会被序列化,在事务执行过程中会按照顺序执行.具有:一次性,顺序性,排他性.
      4.redis事务没有隔离级别的概念.所有的命令在事务中并没有直接被执行,只有发起执行命令的时候才会执行.
      5.redis的事务:     执行完exec之后,事务就没了,再次用需要重新开启事务multi
                #开启事务  (multi )
                #命令入队  (……)
                #执行事务  (exec)      
       6.放弃事务(一旦取消事务,事务中的队列都不会被执行):     discard
       7.悲观锁:很悲观,认为什么时候都会出问题,无论做什么都会加锁.
          乐观锁:很乐观,认为什么时候都不会出问题,所以不会上锁,更新数据的时候去判断一下,在此期间是否有人修改这个数据.
       8.测试多线程修改值时,使用watch加乐观锁.
                  如果发现事务执行失败,就先解锁(unwatch),再获取最新的值进行监视.
    • Jedis
       1.redis官方推荐的java连接工具
       2.步骤:       # 导入对应的依赖
                         #  连接数据库
                         #  操作命令
                         #  断开连接
    • SpringBoot集成Redis
    1. 在SpringBoot2.x之后,原来使用的jedis被替换为lettuce
    2. jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的情况,使用jedis pool连接池,更像BIO模式
    3. lettuce:采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据,更像NIO模式.
    4. @ConditionalOnMissingBean(name="xxx")    //可以自定义一个xxx,当xxx不存在时它下面的类才会生效
    5. redis对象都需要序列化    其中一种序列化方式: new ObjectMapper().writeValueAsString(xxx)
    • Redis配置文件详解
    1. redis是内存数据库,如果没有持久化,那么数据断电即失.
    2. redis默认没有密码,可以使用命令获取redis密码: config get requirepass 
                     config set requirepass "123456"     //设置redis密码为123456
                     auth 123456       //使用密码进行登录
    • 持久化之RDB(Redis DataBase)操作
    1. 在指定时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接读到内存里.
    2. redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,等持久化过程结束,再用这个临时文件替换上次持久化好的文件.整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效.RDB的缺点是最后一次持久化后的数据可能丢失.我们默认的就是RDB,一般情况下不需要修改这个配置.
    3. rdb保存的文件是  dump.rdb
    4. 触发机制:                 # save的规则满足的情况下,执行flushall命令的情况下,退出redis的情况下,都会触发rdb规则,产生rdb文件,备份自动生成一个dump.rdb文件
    5. 如何恢复rdb文件:   只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb 恢复其中的数据.
                                   查看rdb需要存放的位置:    config get dir
    • 持久化之AOF(Append Only File)操作
    1. AOF操作会将所有的命令都记录下来,恢复的时候就把这个文件全部再执行一遍.
    2. 以日志的形式来记录每一个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作.
    3. aof保存的是appendonly.aof文件
    4. 默认是不开启的,如果需要则需手动开启.我们只需要把appendonly改为yes就开启了aof.重启,redis就可以生效了.
    5. 如果aof文件有错误,这时候redis是启动不起来的,我们需要修复这个aof文件.使用工具命令: redis-check-aof --fix appendonly.aof即可恢复
    6. 优点:每次修改都同步,文件的完整性会更好;
    • Redis主从复制      
    1. 概念:
                  主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器.前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点.Master以写为主,Salve以读为主.
                  默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点.
                  主从复制的作用主要包括:
                          1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式.
                          2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余.
                          3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载; 尤其是在写少读多的场景下,通过大大提高Redis服务器的并发量.
                         4.高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实现的基础,因此说主从复制是Redis高可用的基础.
                  配置redis集群至少需要三台(哨兵,一主二从).
            2.单个Redis服务器内存容量有限,就算一台Redis服务器内从容量为256G,也不能将所有内容用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G. 
            3.环境配置.          >info replication    //查看当前库的信息
            4.一般配置主从复制环境,只需要配置从机即可.使用命令:   SLAVEOF host port     //host为主机域名,port为主机端口号 
            5.查看redis服务开启状况命令:     ps -ef|grep redis
            6.如果用命令行配置的主从环境,如果从机挂了,再次启动,会把自己当作主机,除非在配置文件里进行主从环境的配置才不会出现此种情况.
            7.复制原理:
                     Slave启动成功连接到master后会发送一个Sync同步命令.
                     Master接到命令,启动后台的存盘进程,收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,master将传送整个数据文件到salve,并完成一次完全同步.
                     全量复制: Salve服务在接收到数据库文件数据后,包含已有的全部数据,将其存盘并加载到内存中.
                     增量复制:Master继续将新的所有收集到的修改命令以此传给salve,完成同步.
                     Salve只有重新连接Master,一次完全同步(全量复制)将被自动执行!我们的数据一定可以在从机中看到.
            8.宕机手动配置:     如果主机断了连接,可以使用: slaveof no one命令让一个主机变成从机,其他的节点就可以手动连接到最新配置的这个主节点.如果主机此时恢复也没有用了.
    • 哨兵模式

         1.主从切换技术的方法是: 当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这需要人工干预,费时费力,还会造成一段时间内服务不可用.这是一种不推荐的方式,更多的时候,优先使用哨兵模式.Redis从2.0开始正式提供了Sentinel(哨兵)架构来解决这个问题.

         2.哨兵模式能够后台监控主机是否故障,如果故障则根据投票数自动将从库切换为主库.

         3.哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行.其原理是:  哨兵通过发送命令,等待Redis服务器响应,从而监控运行多个Redis实例.

         4.当主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线.当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作.切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线.

         5.配置哨兵的文件名: sentinel.conf. 在此文件中有如下命令可以进行哨兵配置:

                       # sentinel monitor 被监控的名称 host port 1

                         sentinel monitor myredis 127.0.0.1 6379 1

                        后面的数字1代表主机挂了,salve投票看让谁接替成为主机,票数最多者当选主机.

          6.哨兵模式,如果原来主机宕机后又恢复了,只能归并到新主机下,当作从机.

          7. 优点:

            哨兵集群,基于主从复制模式,所有的主从配置优点,它都有.

            主从可以切换,故障可以转移,系统的可用性就会更好.

            哨兵就是从主从模式的升级,手动到自动,更加健壮.

            缺点:

            Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦.

            实现哨兵模式的配置其实很麻烦,里面有很多选择.

    • Redis缓存穿透和雪崩(面试高频,工作常用)

         1.Redis缓存的使用,极大的提升了应用程序的性能和频率,特别是数据查询方面,但同时,它也带来了一些问题.其中,最要害的就是数据一致性问题.从严格意义上讲,此问题无解.如果对数据的一致性要求很高,那么就不能使用缓存.另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿.目前,业界也都有比较流行的解决方案.

         2.缓存穿透:(查不到)

             本概念是指: 用户想要查询一个数据,发现Redis内存数据库没有,也就是缓存没有命中, 于是向持久层数据库查询,发现也没有,于是本次查询失败.当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库,这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透.

             解决方案: 布隆过滤器.  布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力.

                           缓存空对象:  当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据就会从缓存中获取,保护了后端数据源.不过此种方法存在两个问题,1. 如果控制能够被缓存起来,这意味着缓存需要更多的空间存储更多的建,因为这当中可能会有很多空值的键;   2.即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响.

         3.缓存击穿:(量太大,缓存过期)

             本概念是指:缓存击穿是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库.

                             当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且写回缓存,会导致数据库瞬间压力过大.

             解决方案: 1.设置热点数据永不过期,所以不会出现热点key过期后产生的问题.(费空间 )

                           2.加互斥锁. 使用分布式锁保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可.这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大.

        4.缓存雪崩:

             本概念是指:在某一个时间段,缓存集中过期失效或者Redis宕机.

             产生原因: 所有的缓存都过期了.请求落在数据库上,对于数据库而言,就会产生周期性(比如双十一)的压力波峰,这时所有的请求都会达到存储层,存储层的调用量会爆增,造成存储层也挂掉的情况.

            加强解释:key集中过期不是非常致命,致命的缓存雪崩是缓存服务器某个节点宕机或断网,因为自然形成的缓存雪崩一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的,无非就是对数据库产生周期性的压力而已.而缓存服务节点的宕机,对于数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮.

            解决方案: 1.redis高可用

                              一台redis有可能挂掉,那就多设几台redis,这样一台挂掉之后其他的可以继续工作,其实就是搭建的集群.

                          2.限流降级

                              在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量.比如对某个key只允许一个线程查询数据和写缓存,其他线程等待.

                         3.数据预热

                              数据加热的含义是在正式部署之前,先把可能的数据访问一遍,这样部分可能大量访问的数据就会加载到缓存中.在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀.

    学习网址: https://www.bilibili.com/video/BV1S54y1R7SB?p=30&spm_id_from=pageDriver     

     
     
     
     
     
  • 相关阅读:
    linux设备驱动模型二【转】
    Linux设备驱动模型【转】
    内核学习方法,编译、调试等常见问题【转】
    第十四章 netlink机制--基于Linux3.10【转】
    手把手教你把Vim改装成一个IDE编程环境(图文)【转】
    Netlink通信机制【转】
    mac电脑的使用
    【转】不要使用SBJSON(json-framework)
    【转】IOS中Json解析的四种方法
    【转】iOS程序自动检测更新的实现 -- 思路不错
  • 原文地址:https://www.cnblogs.com/xiayanjiao/p/15404827.html
Copyright © 2011-2022 走看看