第五周

每周写一个 ARTS:Algorithm 是一道算法题,Review 是读一篇英文文章,Technique/Tips 是分享一个小技术,Share 是分享一个观点。

Algorithm - 验证二叉排序树

题目链接:https://leetcode-cn.com/problems/validate-binary-search-tree/

代码仓库:https://github.com/fhx1998/LeetCode

利用二叉排序树中序遍历可以得到升序序列的特性

Review - Using pipelining to speedup Redis queries

Redis PipeLine:https://redis.io/topics/pipelining

总结一下文章的主要内容

Redis 是使用 client-server 架构模式的基于 TCP 协议的服务器。也被称做 Request/Response protocol.

所以说呢,客户端发送请求到服务端,需要从 Socket 中以阻塞(通常)的形式读取服务端的响应。换句话说就是客户端发送了一个命令请求,需要等待服务端响应了才能继续发送其他请求。就像这样:

  • Client: INCR X
  • Server: 1
  • Client: INCR X
  • Server: 2
  • Client: INCR X
  • Server: 3
  • Client: INCR X
  • Server: 4

Client 和 Server 之间通过网络链接。因此 client 和 server 之间发送和接收数据包一定会存在时间延迟。RTT(Round Trip Time)指的是 client 从发送请求到接收 server 响应的时间间隔(当然可能包括时间延迟的因素)。

比如 RTT 是 250 ms,那么不管 server 的处理能力有多强悍,那么在一秒钟内最多也只能处理 4 条请求(由于阻塞地读取响应结果)。

Redis Pipelining

通过使用 Pipelining 技术,client 在发送请求后,可以不必等待 server 响应回来就能继续发送其他请求(非阻塞),再一次性的读取来自 server 的 replies。就像这样:

  • Client: INCR X
  • Client: INCR X
  • Client: INCR X
  • Client: INCR X
  • Server: 1
  • Server: 2
  • Server: 3
  • Server: 4

需要注意的点在于:使用 pipelining 技术发送请求,server 需要维护一个请求到 server 的顺序队列,保证按顺序响应请求,而这需要额外的内存空间。故要合理的配置 pipelining 输送的请求数。

使用 Pipelining 技术不只是减少了网络之间的时延。还涉及到读取和写入的 socket I/O。则会使用到 read() 和 write() 的系统调用方法,调用这两个方法的代价是很高的,因为会使系统从用户态转到内核态。使用 Pipeling 技术就可以很好的减少 socket I/O 的次数,降低开销。

  • Graceful
  • bandwidth
  • Short latencies
  • Meeting peak demand
  • trigger
  • accomplished
  • in a row

Technology - Redis 单线程架构与多线程架构

Redis 作为内存数据库领域的佼佼者,提供高性能的服务。因其采用单线程架构,在常规认知中,这似乎与高性能这个词搭不上边。这也是本文接下来要讨论的问题,为何在 Redis 4.0 开始,Redis 的架构设计将趋向于多线程化。

从 Redis 官网的 FAQ 部分的一个问答有相关的阐述,大体意思是 CPU 一般不会成为 Redis 和性能瓶颈,而通常是内存和网络会限制 Redis 的性能。在一个普通的 Linux 系统上,Redis 处理请求的速率可以达到 100 万个 request 每秒钟。官网还建议你可以在同一台机器上开多个 Redis 实例来最大化 CPU 的使用效率,或者分布式部署。

单线程模型

Redis 是基于 TCP,使用 Client/Server 模型提供服务的。一般来说一个 Redis Server 会有多个 Client 与之连接。Cient 发送请求到 Server,Server 响应请求,因为 Redis 是单线程架构,来自客户端的请求则在服务端串行执行。比如,Server 在收到来自 Client A 之前,与 Client A 建立 TCP 连接,通过绑定到一个 socket 进行通信。

Blocking I/O

如果是阻塞 I/O,在建立连接后,Server 等待来自 Client 的输入之前,会被阻塞,也就意味着无法处理其他请求(因为 Redis 是单线程的提供服务的)。为此,Redis 采用了 I/O 多路复用技术来解决这个问题。

I/O 多路复用技术

Redis 封装支持 I/O 多路复用的系统函数(select 函数等),同时监听多个文件描述符的可读写状态(这里指的就是各个客户端),等待数据报套接字变为可读,再进行 I/O。

需要注意的是:这里的 I/O 仍然是阻塞进行的。

这样单个 Redis 线程就可以高效的服务多个 Client 了。相比于创建多个线程,Redis 采用的方法也不错。

多线程架构的趋势

在写本文时,Redis 6.0 稳定版上线了,带来了多线程 I/O,默认不开启,可以在配置文件中配置开启:

  • io-threads-do-reads yes
  • io-threads 线程数

在 Redis 4.0 已经引入了多线程,但仅限于后台删除操作。

However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For future releases, the plan is to make Redis more and more threaded.

两种架构的优劣

单线程架构的可维护性更高。

多线程架构利用了 CPU 的特性,能够高效的并行处理。但是,一旦引入多线程,复杂的线程安全问题会让代码更加复杂。

Share - 无

你可能感兴趣的:(周学习任务,-,ARTS)