Redis系列-基础篇

作为搞了几年的技术小草,想写点东西,总结点东西,表示自己有点东西

在这里插入图片描述

Redis是什么?

Redis 是完全开源免费的,是一个高性能的key-value类型的内存数据库。
整个数据库加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。
因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过10万次读写操作,是已知性能最快的Key-Value DB。

Redis的优势(为什么要用Redis?)

  1. 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s。
  2. 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及Ordered Sets 数据类型操作。
  3. 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
    事务中任意命令执行失败,其余命令依然被执行。也就是说 Redis 事务不保证原子性,也不支持回滚;事务中的多条命令被一次性发送给服务器,服务器在执行命令期间,不会去执行其他客户端的命令请求
  4. 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

小总结:Redis适用于数据高并发及海量数据的读写、也可以配合关系型数据库做高频次访问的数据缓存等等

核心特性(Redis为什么这么快?)

  1. 基于内存实现,读写速度快
  2. 高效的底层数据结构
  3. 单线程,避免线程上下文切换,使用IO多路复用
  4. 简单的自定义网络通信协议
  5. 虚拟内存(VM)

1) 基于内存实现,读写速度快

在内存中读取数据,本质上是电信号的传递。

这肯定比机械运动传递信号要快得多,以MySQL为例,MySQL的数据和索引都是持久化保存在磁盘上的,因此当我们使用SQL语句执行一条查询命令时,如果目标数据库的索引还没被加载到内存中,那么首先要先把索引加载到内存,再通过若干寻址定位和磁盘I/O,把数据对应的磁盘块加载到内存中,最后再读取数据。

2) 采用高效底层数据结构

包括简单动态字符串(SDS),双向列表(Linkedlist),压缩列表(ziplist),哈希表(hashtable),跳表(skiplist)和整数数组(intset)。
在这里插入图片描述

RedisObject是Redis对象的类型,内部编码,内存回收,共享对象等功能都需要RedisObject的支持。
type 字段 占4bit 目前有5中类型, REDIS_STRING, REDIS_LIST, REDIS_HASH, REDIS_SET, REDIS_ZSET。 当执行type命令时,便是通过读取redisObject对象的type字段获取对象类型。

typedef struct redisObject{
    unsigned type: 4; /*type 字段 占4bit 目前有5中类型, REDIS_STRING, REDIS_LIST, REDIS_HASH, REDIS_SET, REDIS_ZSET */
    unsigned encoding: 4;/*占4bit (表示对象的内部编码),对于redis支持的每种类型,都有至少两种内部编码。通过object encoding命令,可以查看对象采用的编码方式*/
    unsigned lru: REDIS_LRU_BITS; /*lru time*/
    int refcount; /*记录对象的引用计数,协助内存回收,引用计数可以通过 object refcount命令查看*/
    void *ptr; /*指针指向具体的数据 如 set hello world ptr指向包含字符串world的SDS*/
} robj;

3) 单线程操作,使用IO多路复用

单线程模型:避免了上下文切换

Redis是单线程的,其实是指Redis的网络IO和键值对读写是由一个线程来完成的。但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,实际是由额外的线程执行的。

Redis的单线程模型,避免了CPU不必要的上下文切换和竞争锁的消耗。也正因为是单线程,如果某个命令执行过长(如hgetall命令),会造成阻塞。Redis是面向快速执行场景的内存数据库,所以要慎用如lrange和smembers、hgetall等命令。

I/O 多路复用

概念:多个网络链接复用同一个线程。

原理:IO多路复用其实就是一种同步IO模型,它实现了一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;而没有文件句柄就绪时,就会阻塞应用程序,交出cpu。

I/O 多路复用技术可以让单个线程高效的处理多个连接请求,而Redis使用用epoll作为I/O多路复用技术的实现。并且Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间

在这里插入图片描述

4) 简单的自定义网络通信协议

凡是网络通信,皆需要双方遵守一致的协议才能互联。Redis协议在如下几点之间做出了折衷

  1. 实现简单
  2. 被计算机快速解析
  3. 有一定的可读性

Redis在TCP端口6379上监听到来的连接,客户端连接到来时,Redis服务器为此创建一个TCP连接。在客户端与服务器端之间传输的每个Redis命令或者数据都以\r\n结尾。

Redis接收由不同参数组成的命令。一旦收到命令,将会立刻被处理,并响应给客户端。

统一请求协议如下(在Redis 2.0中,成为与Redis服务器通讯的标准方式)

  • 单行响应,响应的第一个字节将是 +
set java hello
+OK
  • 错误信息,响应的第一个字节是 -
keys*
-ERR unknown command `keys*`, with args beginning with:
  • 整型数字,响应的第一个字节是 :
  • 批量响应,响应得第一个字节是 $
  • 多个批量响应,响应的第一个字节是 *

5) 虚拟内存机制 VM

什么是虚拟内存机制?

虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中。

Redis为什么需要搞一个VM?

  1. 避免因为内存不足而造成访问速度下降
    腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。

  2. 相对OS系统VM减少IO操作
    redis将交换到磁盘的对象压缩,保存到磁盘的对象可以去除指针和对象元数据信息,一般压缩后的对象比在内存中的对象小10倍,这样redis的VM比操作系统的VM少很多IO操作。

  3. 相对OS系统更利于页面交换
    OS是基于page(4K)来做的,它的粒度对于Redis来说太大。而redis的大多数对象都远小于4k,所以一个OS页面上可能有多个redis对象。另外redis的集合对象类型如list,set可能存在与多个OS页面上。最终可能造成只有10%的key被经常访问,但是所有OS页面都会被OS认为是活跃的,这样只有内存真正耗尽时OS才会交换页面。

什么时候用到虚拟内存机制?

  1. 因为没有过多考虑数据存储模式,或者数据值太大,使得我们没有足够的内存将所有的数据都存放在内存中。
  2. Redis无法将键交换至磁盘中,内存问题是因太多值很小的键引起,虚拟内存机制没有用。
  3. 大部分内存开销都用于大容量的值存储时(例如很大的字符串,列表,集合或者很多元素的哈希)。

常用结构

String

使用概念:String 类型是 Redis 中最常使用的类型,内部的实现是通过 SDS(Simple Dynamic String )来存储的。SDS 类似于 Java 中的 ArrayList,可以通过预分配冗余空间的方式来减少内存的频繁分配。

应用场景:缓存、计数器、分布式锁、共享用户Session等。

List

使用概念:就是个有序列表。

应用场景:链表、队列、微博关注人时间轴列表等。

Hash

使用概念:这个是类似 Map 的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在 Redis 里,然后每次读写缓存的时候,可以就操作 Hash 里的某个字段。

应用场景:用户信息、Hash 表等。

Set

使用概念:无序集合,会自动去重。

应用场景:去重、赞、踩、共同好友等。

Zset(Sorted Set)

使用概念:排序的 Set,去重但可以排序,写进去的时候给一个分数,自动根据分数排序

应用场景:访问量排行榜、点击量排行榜等。

高阶用法

Bitmap

位图是支持按 bit 位来存储信息,可以用来实现 布隆过滤器(BloomFilter)。

HyperLogLog

供不精确的去重计数功能,比较适合用来做大规模数据的去重统计,例如统计 UV;

Geospatial

可以用来保存地理位置,并作位置距离计算或者根据半径计算位置等。可以试着Redis来实现附近的人或者计算最优地图路径。

pub/sub

功能是订阅发布功能,可以用作简单的消息队列。

Pipeline

可以批量执行一组指令,一次性返回全部结果,可以减少频繁的请求应答。

Lua

Redis 支持提交 Lua 脚本来执行一系列的功能,说白了就是利用脚本的原子性。

事务

Redis 提供的不是严格的事务,Redis 只保证串行执行命令,并且能保证全部执行,但是执行命令失败时并不会回滚,而是会继续执行下去。

Redis6.0 特性

  1. 多线程IO
    Redis 6 引入多线程IO,但多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想因为多线程而变得复杂,需要去控制 key、lua、事务,LPUSH/LPOP 等等的并发问题。

  2. 客户端缓存
    客户端缓存在某些方面进行了重新设计,特别是放弃了缓存槽方法而只使用密钥名。

  3. ACL权限控制

    1. 支持对客户端的权限控制,实现对不同的key授予不同的操作权限。
    2. 有一个新的ACL日志命令,允许查看所有违反ACL的客户机、访问不应该访问的命令、访问不应该访问的密钥,或者验证尝试失败。这对于调试ACL问题非常有用。
  4. 支持SSL
    连接支持SSL,更加安全。

  5. RESP3协议
    RESP(Redis Serialization Protocol)是 Redis 服务端与客户端之间通信的协议。Redis 5 使用的是 RESP2,而 Redis 6 开始在兼容 RESP2 的基础上,开始支持 RESP3。更多RESP3协议细节点击这里

    推出RESP3的目的:一是因为希望能为客户端提供更多的语义化响应,以开发使用旧协议难以实现的功能;另一个原因是实现 Client-side-caching(客户端缓存)功能。

  6. PSYNC2 改进
    PSYNC2的复制协议现在已经改进了。Redis将能够更频繁地进行部分重新同步,因为现在可以调整协议中的最终ping,从而使副本和主服务器能够找到共同的偏移量。

  7. 改进 Redis 命令行的超时选项
    带有超时的Redis命令现在好得多:不仅BLPOP和其他命令以前接受秒,现在接受十进制数,而且实际分辨率得到了提高,以便永远不会比当前的“HZ”值差,而不管连接了多少客户端。

  8. 提升了RDB加载速度
    RDB文件现在可以更快地加载。根据文件的实际组成(较大或较小的值),您可以预期有20/30%的改进。当有许多客户机连接时,信息也变得更快了,这是一个长期的问题,现在终于消失了。

  9. Redis集群代理模块(Redis Cluster proxy)
    在 Redis 集群中,客户端会非常分散,现在为此引入了一个集群代理,可以为客户端抽象 Redis 集群,使其像正在与单个实例进行对话一样。同时在简单且客户端仅使用简单命令和功能时执行多路复用 。

  10. STRALGO 新命令

  11. 提供了众多的新模块(modules)API

参考加感谢

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值