在上一周总体介绍了大型应用的架构之后,本周开始分部分详细介绍大型应用的各类技术组成部分。本周主要介绍缓存、异步和队列、负载均衡、分布式数据库这几个部分。

缓存

异步和队列

同步、异步,阻塞、非阻塞,这几个概念我们经常在一起听说,

可以参考知乎上的介绍
https://www.zhihu.com/question/19732473

从IO的角度考虑:

阻塞和非阻塞 I/O。根据应用程序是否阻塞自身运行,可以把 I/O 分为阻塞 I/O 和非阻塞 I/O。

  • 所谓阻塞 I/O,是指应用程序在执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程,不能执行其他任务。
  • 所谓非阻塞 I/O,是指应用程序在执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务。

同步 I/O 和异步 I/O。根据 I/O 响应的通知方式的不同,可以把文件 I/O 分为同步 I/O 和异步 I/O。

  • 所谓同步 I/O,是指收到 I/O 请求后,系统不会立刻响应应用程序;等到处理完成,系统才会通过系统调用的方式,告诉应用程序 I/O 结果。
  • 所谓异步 I/O,是指收到 I/O 请求后,系统会先告诉应用程序 I/O 请求已经收到,随后再去异步处理;等处理完成后,系统再通过事件通知的方式,告诉应用程序结果。

阻塞 / 非阻塞和同步 / 异步,其实就是两个不同角度的 I/O 划分方式。它们描述的对象也不同,阻塞 / 非阻塞针对的是 I/O 调用者(即应用程序),而同步 / 异步针对的是 I/O 执行者(即系统)。

比如在 Linux I/O 调用中,系统调用 read 是同步读,所以,在没有得到磁盘数据前,read 不会响应应用程序。而 aio_read 是异步读,系统收到 AIO 读请求后不等处理就返回了,而具体的 read 结果,再通过回调异步通知应用程序。再如,在网络套接字的接口中,使用 send() 直接向套接字发送数据时,如果套接字没有设置 O_NONBLOCK 标识,那么 send() 操作就会一直阻塞,当前线程也没法去做其他事情。当然,如果你用了 epoll,系统会告诉你这个套接字的状态,那就可以用非阻塞的方式使用。当这个套接字不可写的时候,你可以去做其他事情,比如读写其他套接字。

异步设计真是一个很大的话题,目前主流的语言、框架、中间件等对于异步处理都在某些方面有一定的支持。我从极客时间里找了几篇文章,可以学习参考。深入的内容就是需要在实际工作中继续深入领会了。

异步通讯设计,可以参考

https://time.geekbang.org/column/article/3926

异步编程实践

https://time.geekbang.org/column/article/693

java8里引入的CompletableFuture

https://time.geekbang.org/column/article/91569

消息队列是系统间异步处理的一个利器,当然,消息队列还有其他的一些使用场景,主要可以总结如下:

  • 异步处理
  • 流量控制
  • 服务解耦

对于课堂上同学们纠结的事务消息,RocketMQ的场景,主要是用来保证在发送端,消息发送和数据库写操作可以作为一个事务,同时成功和同时失败,在下游消费端还是要靠幂等等方式保证消息能被正确消费,而不是整个消息处理的事务操作。事务消息的方式,我以前手画过两个图(非常的丑。。)

负载均衡

现在的服务一般都采用集群部署,怎样把一个请求,选择集群中的一个节点进行通信是负载均衡的职责。从软硬件上分有硬件负载均衡(F5,readware等),软件负载均衡,从网络协议上,一般分7层负载,4层负载等等。

总结老师的讲义如下:

分布式数据库

数据库的主从复制

一主多从复制

主主复制

MySQL的相关内容,推荐

https://time.geekbang.org/column/intro/139

其中数据库复制相关的文章

https://time.geekbang.org/column/article/76446

https://time.geekbang.org/column/article/76795

https://time.geekbang.org/column/article/77083

https://time.geekbang.org/column/article/77427

https://time.geekbang.org/column/article/77636