读书笔记:redis开发与运维 基础篇

Redis 是一款高性能的内存数据库,以其速度快、功能丰富、简单稳定著称。其单线程模型保证了服务端处理的简单性,支持RDB和AOF两种持久化方式,以及主从复制和Sentinel高可用。Redis 数据结构包括字符串、哈希、列表、集合和有序集合,适用于多种应用场景。此外,Redis 提供发布订阅、慢查询日志、事务与Lua等功能,以应对各种需求。
摘要由CSDN通过智能技术生成

 redis特性
   1>速度快:redis所有数据都是存放在内存中,是redis速度快的主要原因,是有c编写,一般来说用c编写的程序距离操作系统近,执行速度更快,非阻塞I/O,使用epoll作为I/O多路复用的技术实现,不再网路I/O上浪费过多时间,使用单线程架构,预防了多线程可能产生竞争的问题,对于服务端开发来说,锁和线程切换通常是性能杀手(但是单线程有一个问题就是每个命令执行时间有要求,如果某个命令执行过程,会造成其他命令阻塞,所以redis是面向快速执行场景的数据库)
   2>功能丰富,除了五中数据结构,还提供许多额外功能,键过期功能实现缓存,提供发布订阅实现消息系统,支持lua脚本创造新的redis命令,提供了简单事务,提供了流水线功能,这样客户端可以将一批命令一次性传到redis,减少了网络开销
   3>简单稳定  redis使用单线程模型,使得服务端处理模型简单,客户端开发变得简单,redis不需要依赖操作系统的类库,(例如Memcache需要依赖libevent这样系统类库),redis自己实现了事件库里功能
   4>redis提供了两种持久化方式:RDB和AOF可以把内存的数据保存到硬盘中
   5>提供了主从复制
   6>提供了sentinel实现高可用,保证节点的故障发现和自动专一,提供了分布式实现cluster,提供了高可用、读写和容量的扩展性

  单线程架构:redis使用单线程和I/O多路复用模型实现高性能内存数据库
    redis单线程处理命令,一条命令从客户端达到服务端不会立刻执行,所有命令进入一个队列,然后逐个执行,不会产生并发问题
 API理解和使用:
  string:
   set/mset key value  mget/get key
   keys* 将所有键输出
   dbsize 返回键总数
   dbsize直接获取redis键总数变量,时间复杂度O1,keys遍历所有键,时间复杂度On

   exists key 判断键是否存在
   del key [key1,key2]删除
   expire key seconds 添加过期时间 ttl查询过期时间 -1没设置过期时间 -2不存在
   type key 键类型  object encoding key 返回内部编码
   incr/decr key 计数+/- incrby/decrby 自增/减指定数字
   如果没有mget要执行n次get

   n*get=n*网络时间+n*命令时间 优化为  n*get=1*网络时间+n次命令
    
   append / strlen /getset 设新返旧 / setrange key offeset value

   内部编码:int 8长整型/embstr <=39字符串/raw >39字符串
   应用场景:共享Session、验证一分钟不超过多少次登陆/限制一个IP不能一分钟之内访问多少次

  Hash:
   键值本身又是一个键值对结构
   hset key field value /hmset user:1 name1 value1 name2 value2 
   hget key field /hmget key filed1 filed2
   hdel key field
   hlen key 计算field个数
   hexists key field 判断field是否存在
   hkeys key 获取所有field /hvals key 获取全部value
   hgetall key 获取全部field-value 如果个数比较多,会阻塞redis,可以使用hscan,该命令会渐进式遍历哈希类型
   hstrlen key field 计算value的字符串长度

   内部编码:
   压缩列表(ziplist):当哈希类型元素个数小于配置hash-max-ziplist-entries(默认512个)。同时所有值都小于hash-max-ziplist-value(默认64字节),redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个原色的连续存储,在节省内存比hashtable更优秀
   哈希表(hashtable):无法满足ziplist条件会使用,因为此时ziplist的读写效率下降,而hashtable读写时间复杂度为O1,当field个数超过512也会变

   应用场景:
    可以把关系型数据表记录的用户信息,用户的属性为列,用户信息为用哈希类型存储
   

     区别:
       哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型每个键都可以有不同的field,而关系型数据库一旦添加新的列,所有列都要为其设置值。关系式数据库可以做复杂的关系查询,而redis去模拟复杂查询开发困难,维护成本高
     三种缓存用户信息的方法:string 和hash
    方案一:
      set user:1:name tome
      set user:1:age 23 
      优点:简单直观,每个属性都支持更新操作
      缺点:占用过多的键,内存占用量大,同时用户信息内存性比较差,一般不会再生产环境使用
    方案二:
      set user:1 serialize(userInfo)
     优点:提高内存使用率
     缺点:序列化和反序列化需要开销,每次更新需要进行反序列化,然后在序列化到redis
    方案三:
     每个用户属性使用一对field-value,只用一个键保存
      hmset user:1 name tome age 23 city bj
      有点:简单直观,如果合理使用可以减少内存的使用
      缺点:要控制ziplist和hashtable两种内部编码的转换,后者消耗更多内存

   list:
     lrange 0 -1 获取列表全部元素
     linsert key before|after b java 某个元素前、后插入元素
     llen key 
     lrem key count value   count>0从左到右删除指定value元素 count=0删全部

    内部编码:
     ziplist(压缩列表):如果元素的个数小于list-max-ziplist-entries(默认512),同时列表中每个元素的值都小于list-max-ziplist-value(默认64字节)。会选用ziplist作为列表的内部实现来减少内存的使用
     linkedlist(链表):当列表类型无法满足ziplist条件时候。

 使用场景:
  1.消息队列:redis的lpush+brpop组合可以实现阻塞队列,多个消费者客户端使用brpop命令阻塞式的抢列表尾部的元素,多个客户端保证消费的负载均衡和高可用性
 集合:
   一个集合最多存储2的32次方-1元素。redis除了集合内增删改查,同事支持多个集合取交集、并集、差集
   sadd key element (O1)
   srem key element
   scard key  计算元素个数
   sismember key elsement 判断元素是否在
   srandmember key [count] 随机从集合返回指定个数元素
   spop key 从集合随机弹出元素
   smembers key 获取所有元素

   smembers和range、hgetall都属于比较重的命令,如果元素过多存在阻塞redis的可能性,这个时候使用sscan来完成
   
集合间的操作:
    sinter key.... 求多个集合的交集
    suione key.... 求多个集合的并集
    sdiff  key.... 求多个集合的差集
    集合间运算在元素较多的情况下比较耗时,所以redis提供了三个命令(原命令+store)将集合间操作保存在set类型中,比如sinterstore sinter_  s z

   内部编码:
    intset(整数集合):当集合中元素都是证书个数小于set_max_intset_entries配置(默认512个),redis会选用intset作为集合的内部实现,从而减少内存的使用
    hashtable:当集合类型无法满足inset条件时,redis会使用hashtable作为集合的内部实现
   使用场景:
    比较典型的场景是标签。例如一个电子商务网站对不同标签的用户做不同类型的推荐,当给用户添加标签和给标签添加用户以及删除的时候,防止部分命令造成数据不一致,应该将两个命令放在同一个事务里

     sadd=tag 标签
     spop/srandmember=Random item 生成随机数  抽奖
     sadd+sinter = 社交需求
   
有序集合:
   有序集合中的元素可以排序,但是它和列表使用索引下标作为排序依据不同,它给每个元素设置一个分支score作为排序的依据,有序集合中的元素不能重复,但是score可以重复
 
 命令:
   zadd key score member  (On)
   zcard key  计算成员个数  (O1)
   zscore key member 计算成员分数
   zrank key member   从低到高 计算成员排名
   zrevrank key member 从高到低 计算成员排名
   zrem key member 删除成员
   zincrby key increment member 增加成员的分数
   zrange/zrevrange key start end  返回指定排名范围的成员 [withscores]返回成员的分数
   zrangebyscore/zrevrangebyscore key max min 返回指定分数内的成员  [withscores]返回成员的分数
   zcount key min max 
   zremrangebyscore key min max 删除指定分数范围的成员
 
 内部编码:
   ziplist:当有序集合的元素个数小于zset-max-ziplist-entries(128个),同时每个元素的值小于zset-max-ziplist-value配置(64字节),redis用ziplist来作为有序集合的内部实现,有效的减少内存
   skiplist(跳表):当ziplist不满足,因此此时的ziplist读写效率会下降
 使用场景:
   排行榜系统

   迁移键:
     migrate:将dump、restore、del进行组合,具有原子性,在源redis执行即可,数据传输在源redis和目标rdis上完成,目标redis完成restore自己发送ok给源redis,源redis会根据migrate选项是否决定删除
   遍历键:keys 和 scan
     keys:支持正则匹配的,但是考虑redis是单线程架构就不是特别完美,如果redis产生大量的键,执行keys会造成redis阻塞

     scan:有效的解决keys命令存在的问题,采用了渐进式遍历方式,每次scan时间复杂度为O1,但是要实现keys功能,需要执行多次scan
       redis存储键值对实际用hashtable的数据结构,每次执行scan,可以想象成只扫描一个字典中一部分键,直到将字典中的所有键遍历完毕
       scan cursor [match pattern][count number]遍历的数量默认是10

       cursor实际上是一个游标,每次遍历完会返回当前游标的值,直到游标值为0

  数据库管理:
    切换数据库 select dbIndex
     reids 默认配置是有16个数据库,之间的数据没有任何关联,但是已经逐渐弱化这个功能
     因为: redis是单线程,如果使用多个数据库,依然使用一个cpu,会受影响,会让调试和运维不同业务数据库变得苦难,加入有一个慢查询,依然会影响其他数据库,定位问题也困难
     建议部署多个redis,彼此用端口来区分。这样保证业务之间不收到影响,又合理使用了cpu资源
    2.flushab/flushall
     前者清除当前数据库,后者清除全部数据库,但是如果键值比较多,会存在阻塞redis可能性

  慢查询日志
     只能查询命令执行的时间,不代表客户端没有超时问题

   使用config set动态修改:
    config set  slowlog-log-slower-than   20000 超过了多少微秒
      config set    slowlog-max-len  1000 记录多少条  config rewrite 持久化到本地配置文件
     是一个先进先出的队列
     slowlog get [n]

     slowlog len 
     
     慢查询日志有四个属性组成: 慢查询日志id、发生时间戳、命令耗时、执行命令和参数
     注意:慢查询日志只能记录命令执行时间,并不包括排队和网络传输时间,可以定期执行slow get将慢查询日志持久化到mysql中
  
  redis基准性能测试 类似于ab: redis-benchmark -c 并发 -n请求总数 -t 请求方式 get/put --csv

  pipeline:(RTT往返时间)
    redis提供了批量操作 mget、mset等有效节约RTT,但是大部分命令不支持批量操作
    pipeline:能将一组redis命令进行组装,通过一次RTT传输给redis。
    
    pipeline和原生批量命令:
      1>原生批量命令是原子的,pipeline是非原子的
      2>原生的是一个命令对应多个key,pipeline支持多命令
      3>原生的是在redis服务端实现的,而pipeline需要服务端和客户端共同实现

 事务与Lua:
   事务开启 multi  提交exec 取消:discard
   但是redis不支持回滚功能,有些场景需要在事务之前确保事务中的key没有被其他客户端修改过,才能执行事务,负责不执行(类似乐观锁)。redis提供了watch来解决

客户端1、2

bitmaps:实现对位的操作
  bitmaps不是数据结构,是字符串,但是它可以怼字符串的位进行操作
  setbit key offset value
  getbit key offset
  bitcount key [start][end]
  运算:and交集 or 并集 not 非 xor 异或
  bitop op destkey key[key]  保存在destkey中
可以用到统计访问网站用户数量: and 几天都访问的,or 任意一天访问的,(月活跃)
Bitmaps分析:
  假设网站1亿用户,每天访问5千万对比

 但是如果网站访问用户很少,只有10万,很显然bitmap就不太合适了,因为大部分都是0


  setbit一个大的偏移量,由于申请大量内存会导致阻塞

HyperLogLog:利用极小内存空间完成独立总数的统计,数据集可以使IP、Email、ID等。
  pfadd 、 pfcount、 pfmerge
   在进行

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值