【中间件快速入门】什么是Redis

打印 上一主题 下一主题

主题 1519|帖子 1519|积分 4557

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
现在后端开辟会用到各种中间件,一不留神项目可能在哪天就要用到一个我们之前可能听过但是从来没接触过的中间件,这个时间对于开辟职员来说,假如你不知道这个中间件的设计逻辑和使用方法,那在后面的开辟和维护工作中可能就会比较吃力,所以我想根据我的履历,把后端开辟中常用的中间件最简单的一层帮各人总结一下,包罗它是干什么的,优势是什么,如何使用这三大部分,让各人对一些常用的中间件有一些根本的了解,不至于在工作中的项目中用到了这个中间件但却对它没有一点了解。

   什么是redis

   
(来自维基百科)Redis(Remote Dictionary Server)是一个使用ANSI C编写的支持网络、基于内存、分布式、可选持久性的键值对存储数据库。根据月度排行网站DB-Engines.com的数据,Redis是最流行的键值对存储数据库。

   Redis为什么叫Redis

   
Redis的全称是REmote DIctionary Service,即远程字典服务

   Redis默认端口为什么是6379

   

   
6379实在对应手机9宫格键盘上的4个按键,来源是MERZ这个词:

   

   

  • Redis内部原理
   Redis一般用来干什么

   Redis最常见的用途就是用作缓存,当你的系统需要缓存的组件时,Redis根本上就是不二的选择。除了缓存以外,Redis有时还被用来实现分布式锁,比如OpenStack的tooz就是用redis实现的分布式锁。另外在分布式系统中,Redis可以用来共享会话信息。
   Redis的三种模式

   
Redis的三种模式主要包罗主从模式(Master-Slave Replication)、哨兵模式(Sentinel)和集群模式(Cluster)。

   主从模式

   
主从模式是一种数据备份和读写分离的模式。在这种模式下,有一个主节点(Master)负责处置处罚全部的写操作,一个或多个从节点(Slave)负责处置处罚读操作。从节点通过复制主节点的数据来保持与主节点的数据一致性。

   

  • 长处:     

    • 实现数据备份,进步数据安全性。
    • 读写分离,进步系统读取性能。

  • 缺点:     

    • 无法自动切换主从节点,主节点故障时需要手动切换。
    • 写操作仍然在主节点上进行,可能成为性能瓶颈。

   哨兵模式

   
哨兵模式是在主从模式的基础上,增加了故障转移和监控的功能。哨兵节点(Sentinel)负责监控主从节点的状态,并在主节点故障时自动将从节点提升为主节点。

   

  • 长处:     

    • 实现自动故障转移,进步系统可用性。
    • 监控主从节点的状态,实时发现和办理问题。

  • 缺点:     

    • 哨兵节点需要额外的资源和维护本钱。
    • 主从切换时可能会有短暂的服务中断。

   集群模式

   
集群模式是一种分布式办理方案,它将数据分散存储在多个节点上,每个节点负责一部分数据的读写。集群模式通过哈希槽技术实现数据的分片和管理。

   

  • 长处:     

    • 实现数据的水平扩展,进步系统存储容量和性能。
    • 自动进行故障转移和负载均衡。
    • 支持动态添加或删除节点,易于扩展和维护。

  • 缺点:     

    • 设置和维护相对复杂。
    • 不支持跨节点的事件和某些复杂操作。

   Redis持久化方式

   
Redis的持久机制有两种,第一种是快照,第二种是AOF日志。

   
快照是一次全量备份,AOF日志是连续的增量备份。快照是内存数据的二进制序列化情势,在存储上非常紧凑,而AOF日志记录的是内存数据修改的指令记录文本。AOF日志在长期的运行过程中会变得无比庞大,数据库重启时需要加载AOF日志进行指令重放,这个时间就会无比漫长,所以需要定期进行AOF重写,给AOF日志进行瘦身。

   快照

   
Redis使用操作系统的多进程COW(Copy on Write)机制来实现快照持久化。

   
Redis在持久化时会调用glibc的函数fork产生一个子进程,快照持久化完全交给子进程来处置处罚,父进程继续处置处罚客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以把父子进程想象成一个连体婴儿,它们在共享身材。这是Linux操作系统的机制,为了节约内存资源,所以尽可能让他们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。

   
子进程做数据持久化,不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须连续服务客户端请求,然后对内存数据结构进行不中断的修改。

   
这个时间就会使用操作系统的COW机制来尽心数据段页面的分离。数据段是由很多操作系统的页面(Page)组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这是子进程相应的页面是没有变化的,照旧进程产生时那一瞬间的数据。

   
随着父进程修改操作的连续进行,越来越多的共享页面被分离出来,内存就会连续增长,但是也不会超过原有数据内存的2倍大小。另外,Redis实例里冷数据占的比例往往是比较高的,所以很少会出现全部的页面都被分离的情况,被分离的往往只有其中一部分农业面。每个页面的大小只有4KB,一个Redis实例里面一般都会有成千上万个页面。

   
子进程因为数据没有变化,它能看到的内存里的数据在进程产生的一瞬间就凝固了,再也不会改变,这也是为什么Redis的持久化叫“快照”的原因。接下来子进程就可以非常安心地遍历数据,进行序列化写磁盘了。

   AOF

   
AOF日志存储的是Redis服务器的顺序指令序列,AOF日志只记录对内存进行修改的指令记录。

   
Redis会在吸收到客户端修改指令后,进行参数校验、逻辑处置处罚,假如没问题,就立刻将该指令文本存储到AOF日志中,也就是说,先实行指令才将日志存盘。这点差异于leveldb、hbase等存储引擎,它们都是先存储日志再做逻辑处置处罚。

   
Redis在长期运行的过程中,AOF的日志会越来越长。假如实例宕机重启,重放整个AOF日志会非常耗时,导致Redis长时间无法对外提供服务,所以需要对AOF日志瘦身。

   
Redis提供了bgrewriteaof指令用于对AOF日志进行瘦身,其原理就是开辟一个子进程对内存进行遍历,转换成一系列Redis的操作指令,序列化到一个新的AOF日志文件中。序列化完毕后再将操作期间发生的增量AOF日志追加到这个新的AOF日志文件中,追加完毕后就立刻替代旧的AOF日志文件了,瘦身工作就完成了。

   
Linux的glibc提供了fsync(int fd)函数可以将订定文件的内容逼迫从内核缓存刷到磁盘。只要Redis进程实时调用fsync函数就可以包管AOF日志不丢失。但是fsync是一个磁盘IO操作,它很慢!假如Redis实行一条指令就要fsync一次,那么Redis高新更能的地位就不保了。

   
所以在生产情况的服务器中,Redis通常是每隔1s左右实行一次fsync操作,这个1s的周期是可以设置的。这是在数据安全性和性能之间做的一个折中,在保持高新更能的同时,尽可能使数据少丢失。

   Redis扫除逾期key的方式

   
Redis会将每个设置了逾期时间的key放入一个独立的字典中,以后会定时遍历这个字典来删除到期的key。除了定时遍历之外,它还会使用惰性策略来删除逾期的key。所谓惰性策略就是在客户端访问这个key的时间,Redis对key的逾期时间进行检查,假如逾期了就立刻删除。假如说定时删除是会集处置处罚,那么惰性删除就是零散处置处罚。

   定期删除

   
Redis默认每秒进行10次逾期扫描,逾期扫描不会遍历逾期字典中全部的key,而是接纳了一种简单的贪婪策略,步调如下:

   

  • 从逾期字典中随机选出20个key
  • 删除这20个key中已经逾期的key
  • 假如逾期的key的比例超过1/4,那就重复步调1
   
同时,为了包管逾期扫描不会出现循环过度,导致线程卡死的现象,算法还增加了扫描时间的上限,默认不会超过25ms。

   惰性删除

   
在获取key时,先判断key是否逾期,假如逾期则删除。这种方式存在一个缺点:假如这个key不停未被使用,那么它不停在内存中,实在它已经逾期了,会浪费大量的空间。

   
这两种策略结合起来以后,定时删除策略发生了一些改变,不再是每次扫描全部的key了,而是随机抽取一部分key进行检查,如许就降低了对CPU资源的消耗。

   Redis string的设计

   
Redis的字符串叫“SDS”,也就是Simple Dynamic String。它的结构是一个带长度信息的字节数组。

  
  1. struct SDS<T> {
  2.     T capacity; // 数组容量
  3.     T len; // 数组长度
  4.     byte flags; // 特殊标志位,不用理睬它
  5.     byte[] content; // 数组内容
  6. }
复制代码
  
上面的SDS结构使用了泛型T。为什么不直接用int呢?因为当字符串比较短时,len和capacity可以使用byte和short来表示,Redis为了对内存做极致的优化,差异长度的字符串使用差异的结构体来表示。

   
Redis的字符串有两种存储方式,在长度特别短时,使用embstr情势存储,而当长度超过44字节时,使用raw情势存储。

   
为了解释这种现象,我们首先来了解一下Redis对象头结构,全部的Redis对象都有下面的这个头结构。

  
  1. struct RedisObject {
  2.     int4 type; // 4 bits
  3.     int4 encoding; // 4 bits
  4.     int24 lru; // 24 bits
  5.     int32 refcount; // 4 bytes
  6.     void *ptr; // 8 bytes, 64-bit system
  7. }
复制代码
  
差异的对象具有差异的类型type(4bit)。同一个类型的type会有差异的存储情势encoding(4bit)。为了记录对象的LRU信息,使用了24个bit来记录LRU信息。每个对象都有个引用计数,当引用计数为0时,对象就会被烧毁,内存被回收。ptr指针将指向对象内容(body)的具体存储位置。如许一个RedisObject对象头结构需要占据16字节的存储空间。

   
接着我们再看SDS结构体的大小,在字符串比较小时,SDS对象头结构的大小是capacity+3

   
,至少是3字节。意味着分配一个字符串的最小空间占用为19(即16+3)字节。

  
  1. struct SDS {
  2.     int8 capacity; // 1 byte
  3.     int8 len; // 1 byte
  4.     int8 flags; // 1 byte
  5.     byte[] content; // 内联数组,长度为capacity
  6. }
复制代码
  
embstr将RedisObject对象头结构和SDS对象连续存在一起,使用malloc方法一次分配,而raw存储情势不一样,它需要两次malloc方法,两个对象头在内存地址上一般是不连续的。

   

   

   
内存分配器jemalloc、tcmalloc平分配内存大小的单位都是2/4/8/16/32/64字节等,为了能容纳一个完整的embstr对象,jemalloc最少会分配32字节的空间,假如字符串再稍微长一点,那就是64本身的空间。假如字符串总体超出了64字节,Redis认为它是一个大字符串,不再适合使用embstr存储,而该使用raw情势。

   
当内存分配了64字节空间时,那这个字符串长度最大可以是多少呢?这个长度就是44字节。

   
为什么是44字节呢?64字节中,除了RedisObject的16字节和SDS的3字节,留给content的长度最多只有45(即64 - 19)字节了。字符串又是以NULL末了,所以embstr情势最大能容纳的字符串长度就是44字节。

   Redis如何使用

   Reids主要通过Redis Cli进行操作,毗连方式为
  
  1. redis-cli -h {host} -p {port}
复制代码
  然后就是在命令行内使用各种get和set命令去操作数据了,具体就不在这里展示了,可以等真正要用的时间去现搜索一下。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表