当前位置: 首页 > news >正文

并发服务器:Redis案例研究分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

并发服务器:Redis案例研究分析并发服务器:Redis案例研究分析

1.事件处理库

Redis 最初发布于 2009 年,它最牛逼的一件事情大概就是它的速度 —— 它能够处理大量的并发客户端连接。需要特别指出的是,它是用一个单线程来完成的,而且还不对保存在内存中的数据使用任何复杂的锁或者同步机制。

Redis 之所以如此牛逼是因为,它在给定的系统上使用了其可用的最快的事件循环,并将它们封装成由它实现的事件循环库(在 Linux 上是 epoll,在 BSD 上是 kqueue,等等)。这个库的名字叫做 ae。ae 使得编写一个快速服务器变得很容易,只要在它内部没有阻塞即可,而 Redis 则保证 注1 了这一点。

在这里,我们的兴趣点主要是它对文件事件的支持 —— 当文件描述符(如网络套接字)有一些有趣的未决事情时将调用注册的回调函数。与 libuv 类似,ae 支持多路事件循环(参阅本系列的第三节和第四节)和不应该感到意外的 aeCreateFileEvent 信号:
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData);
它在 fd 上使用一个给定的事件循环,为新的文件事件注册一个回调(proc)函数。当使用的是 epoll 时,它将调用 epoll_ctl 在文件描述符上添加一个事件(可能是 EPOLLIN、EPOLLOUT、也或许两者都有,取决于 mask 参数)。ae 的 aeProcessEvents 功能是 “运行事件循环和发送回调函数”,它在底层调用了 epoll_wait。

2.处理客户端请求

我们通过跟踪 Redis 服务器代码来看一下,ae 如何为客户端事件注册回调函数的。initServer 启动时,通过注册一个回调函数来读取正在监听的套接字上的事件,通过使用回调函数 acceptTcpHandler 来调用 aeCreateFileEvent。当新的连接可用时,这个回调函数被调用。它调用 accept 注2 ,接下来是 acceptCommonHandler,它转而去调用 createClient 以初始化新客户端连接所需要的数据结构。

createClient 的工作是去监听来自客户端的入站数据。它将套接字设置为非阻塞模式(一个异步事件循环中的关键因素)并使用 aeCreateFileEvent 去注册另外一个文件事件回调函数以读取事件 —— readQueryFromClient。每当客户端发送数据,这个函数将被事件循环调用。

readQueryFromClient 就让我们期望的那样 —— 解析客户端命令和动作,并通过查询和/或操作数据来回复。因为客户端套接字是非阻塞的,所以这个函数必须能够处理 EAGAIN,以及部分数据;从客户端中读取的数据是累积在客户端专用的缓冲区中,而完整的查询可能被分割在回调函数的多个调用当中。

3.将数据发送回客户端

在前面的内容中,我说到了 readQueryFromClient 结束了发送给客户端的回复。这在逻辑上是正确的,因为 readQueryFromClient 准备要发送回复,但它不真正去做实质的发送 —— 因为这里并不能保证客户端套接字已经准备好写入/发送数据。我们必须为此使用事件循环机制。

Redis 是这样做的,它注册一个 beforeSleep 函数,每次事件循环即将进入休眠时,调用它去等待套接字变得可以读取/写入。beforeSleep 做的其中一件事情就是调用 handleClientsWithPendingWrites。它的作用是通过调用 writeToClient 去尝试立即发送所有可用的回复;如果一些套接字不可用时,那么当套接字可用时,它将注册一个事件循环去调用 sendReplyToClient。这可以被看作为一种优化 —— 如果套接字可用于立即发送数据(一般是 TCP 套接字),这时并不需要注册事件 ——直接发送数据。因为套接字是非阻塞的,它从不会去阻塞循环。

4.Redis中的多线程

在 Redis 的绝大多数历史中,它都是一个不折不扣的单线程的东西。一些人觉得这太不可思议了,有这种想法完全可以理解。Redis 本质上是受网络束缚的 —— 只要数据库大小合理,对于任何给定的客户端请求,其大部分延时都是浪费在网络等待上,而不是在 Redis 的数据结构上。

然而,现在事情已经不再那么简单了。Redis 现在有几个新功能都用到了线程:
1.“惰性” 内存释放。
2.在后台线程中使用 fsync 调用写一个 持久化日志。
3.运行需要执行一个长周期运行的操作的用户定义模块。

对于前两个特性,Redis 使用它自己的一个简单的 bio(它是 “Background I/O" 的首字母缩写)库。这个库是根据 Redis 的需要进行了硬编码,它不能用到其它的地方 —— 它运行预设数量的线程,每个 Redis 后台作业类型需要一个线程。

而对于第三个特性,Redis 模块 可以定义新的 Redis 命令,并且遵循与普通 Redis 命令相同的标准,包括不阻塞主线程。如果在模块中自定义的一个 Redis 命令,希望去执行一个长周期运行的操作,这将创建一个线程在后台去运行它。在 Redis 源码树中的 src/modules/helloblock.c 提供了这样的一个示例。

有了这些特性,Redis 使用线程将一个事件循环结合起来,在一般的案例中,Redis 具有了更快的速度和弹性,这有点类似于在本系统文章中 第四节 讨论的工作队列。

原文来自:https://www.linuxprobe.com/redis-case-study.html

转载于:https://my.oschina.net/ssdlinux/blog/1823418

相关文章:

  • POJ 3041 Asteroids (最小点覆盖集)
  • 不通过调用__Init__来创建实例
  • 算法学习--动手
  • 10-padding(内边距)
  • linux中grep和egrep的用法
  • hashlib模块学习:hmac
  • 开发基于以太坊智能合约的DApp
  • vue-cli脚手架一些插件安装elementui和axios
  • MD5加密解密
  • MS SQL 需要定期清理日志文件
  • Django-admin管理工具
  • Spring读书笔记-----部署我的第一个Spring项目
  • 减少死锁的几个常用方法
  • ylbtech-cnblogs(博客园)-数据库设计-7,News(新闻)
  • 用whistle和proxifier抓包调试任意客户端的网络请求
  • Android交互
  • Django 博客开发教程 8 - 博客文章详情页
  • E-HPC支持多队列管理和自动伸缩
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 开源SQL-on-Hadoop系统一览
  • 前言-如何学习区块链
  • 线上 python http server profile 实践
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​你们这样子,耽误我的工作进度怎么办?
  • #laravel 通过手动安装依赖PHPExcel#
  • #在 README.md 中生成项目目录结构
  • $.ajax()方法详解
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (附源码)计算机毕业设计大学生兼职系统
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (十)c52学习之旅-定时器实验
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (原)本想说脏话,奈何已放下
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Core 中的路径问题
  • .Net Memory Profiler的使用举例
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .net2005怎么读string形的xml,不是xml文件。
  • .Net7 环境安装配置
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • .NET业务框架的构建
  • .net中生成excel后调整宽度
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @RequestBody的使用
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(白虎组)
  • [ 隧道技术 ] 反弹shell的集中常见方式(二)bash反弹shell
  • [<事务专题>]
  • [Big Data - Kafka] kafka学习笔记:知识点整理
  • [Bzoj4722]由乃(线段树好题)(倍增处理模数小快速幂)
  • [C# 基础知识系列]专题十六:Linq介绍