• Redis线程 IO 模型和通信协议 Anthony


    鞭辟入里一一线程 IO 模型

    Redis 是个单线程程序 !

    非阻塞 IO

    当我们调用套接字的读写方法,默认它们是阻塞的,例如read方法传递进去一个参数n,最多读取n个字节返回,如果没有字节,线程就会卡在那里,直到有新的数据来或连接关闭,read方法才返回,才线才能继续处理。write方法一般来说不会阻塞,除非内核为套接字分配的写缓冲区已经满了, write 方法就会阻塞,直到缓存区中有空间空闲出来。

    ​ 非阻塞 IO 在套接字对象上提供了一个选项 Non_Blocking。读的字节取决于内核为套接字分配的读缓冲区内部的数据字节数,写的字节取决于内核为套接字分配的写缓冲区的空闲空间字节数。读方法和写方法都会通过返回值来告知程序实际读写了多少字节。

    事件轮询(多路复用)

    事件轮询 API 就是用来解决,当数据到来时,线程如何得到通知。事件轮询 API select 函数, 它是操作系统提供给用户程序的 API 输入是读写描述符列表 read_fds & write fds, 输出是与之对应的可读可写事件同时还提供了一个 timeout 参数,如果没有任何事 件到来,那么就最多等待 timeout 的值的时间,线程处于阻塞状态 一旦期间有任何事件到来,就可以立即返回。时间过了之后还是没有任何事件到来,也会立即返回。

    指令队列

    每个客户端套接字都关联一个指令队列,会通过队列来排队进行顺序处理。

    响应队列

    Redis 服务器通过响应队列来将指令的返回结果回复给客户端。如果队列为空,那么意味着连接暂时处于空闲状态,不需要去获取写事件,也就是可以将当前的客户端描述符从 write_fds 里面移出来。等到队列有数据了,再将描述符放进去,避免 select 系统调用立即返回写事件,当没什么数据可以写时,出现这种情况的线程会加大 CPU 消耗。

    定时任务

    Redis 的定时任务会记录在一个被称为“最小堆”的数据结构中。在这个堆中, 最快要执行的任务排在堆的最上方。在每个循环周期里, Redis 都会对最小堆里面已经到时间点的任务进行处理。处理完毕后,将最快要执行的任务还需要的时间记录下来,这个时间就是 select 系统调用的 timeout 参数。 Nginx 和 Node 的事件处理原理和 Redis 也是类似的。

    交头接耳一一通信协议

    Redis 使用了浪费流量的文本协议,依然可以取得极高的访问性能,将所有数据都放在内存中,用一个单线程对外提供服务,单个节点在跑满 一个 CPU 核心的情况下可以达到了 10 w/s 的超高 QPS。

    RESP

    RESP是Redis序列化协议(Redis Serialization Protocol),是一种直观的文本协议,优势在于实现过程简单,解析性能很好。

    Redis 协议将传输的结构数据有5种最小单元类型:(后面加\r\n)

    1. 单行字符串以“+”符号开头。 2. 多行字符串以“$”符号开头,后跟字符串长度 3. 整数值以“:”符号开头,后跟整数的字符串形式 4. 错误消息以“-”符号开头。 5. 数组以“*”号开头,后跟数组的长度。

    NULL 用多行字符串表示,不过长度要写成 -1 $-1\r\n

    空串用多行字符串表示,长度填0 $0\r\n\r\n

    客户端→服务器

    客户端向服务器发送的指令只有一种格式,多行字符串数组。

    eg: *3\r \n $3\r\nset\r\n$4\r\nname\r\n$3\r\n123\r\n

    服务器→客户端

    服务器向客户端回复的响应要支持多种数据结构,由上5种基本类型的组合。

    单行字符串响应 +OK

    错误响应 试图对个字符串进行自增,服务器抛出一个通用的错误。-ERR value is not an integer or out of range

    整数响应 (integer) 1 : 1

    多行字符串响应 "123" 使用双引号括起来的字符串就是多行字符串晌应

    $8
    codehole 
    

    数组响应
    嵌套

    127 . 0 . 0.1 : 6379> scan 0

    1 )“0”

    2 ) 1 ) ” info ”

    2 )”books”

    3 )”author”

    scan 命令用来扫描服务器包含的所有 key 列表,它是以游标的形式获取,一次只获取一部分。 scan 命令返回的是一个嵌套数组。数组的第一个值表示游标的值,如果这个值 为零,说明已经遍历完毕。如果不为零,使用这个值作为 scan 命令的参数进行下一 次遍历。数组的第二个值又是一个数组,这个数组就是 key 列表。

    *2
    $1
    0
    *3
    $4
    info 
    $5
    books
    $6
    author 
    
  • 相关阅读:
    jar强退出 JVM报错:Failed to write core dump. Core dumps have been disabled.
    配置 DHCP Snooping 和 IPSG
    OpenOffice
    RabbitMQ ADD
    YAPI 接口管理
    mysql:1153 Got a packet bigger than ‘max_allowed_packet’ bytes的解决方法
    修改端口的VLAN
    阿里云OSS设置跨域访问
    seata连接nacos 报错
    Linux登录超时问题
  • 原文地址:https://www.cnblogs.com/yugehard/p/14040019.html
Copyright © 2020-2023  润新知