从本文开始,将记录做者学习 MIT 6.824 分布式系统的学习笔记,若是有志同道合者,欢迎一块儿交流。数据库
RPC 全称为 Remote Procedure Call,他表示一种远程过程的调用,他可让用户在不知道底层网络协议的状况下,在本地的计算机就能够调用远端服务器的一些处理方法,而后服务器会把处理的结果返回到用户本地,就像这个方法写在用户本地空间中同样。缓存
RPC 的层级结构以下所示:服务器
如上图所示,RPC 的操做流程为:网络
RPC 具体实现的关键技术点以下多线程
RPC 的潜在失败状况有以下几种:并发
对此,为了必定要让客户端拿处处理结果,有如下几种解决方案:分布式
该方法的中心思想是:client 发送等待 server 回答,若是没收到,则继续发送。该方式可能形成的问题有:函数
问题一:可能客户端 -> 服务端的网络一直相同,服务器处理正常,可是在回复过程出现问题,从而形成客户端持续发送请求,使得客户端一直重复处理,浪费资源。学习
问题二:若是要处理的请求具备事务性,如操做数据库,那么使用这种方案就没法保证先后的一致性。考虑以下的状况,假设咱们要操做的对象是服务端的数据库,可能会出现以下的问题:编码
如上图所示,PUT 表示咱们要去修改一个 key 对应的值,而 GET 则让咱们获取这个 key 对应的值,所以当咱们延迟的请求到达服务器时,服务器已经处理其余的请求,形成咱们最后一次 GET 方法获取的结果可能与咱们的预期不一样。
因此 At least once 会形成资源浪费,服务端出现不一致的状况,不是一个很好的方法
其实,方案一的问题在于服务端没法判断客户端由于各类缘由收不到而重复发出的请求,所以咱们须要让服务器能够发现以前的重复请求,而且在不执行 handler 的状况下,返回以前缓存的结果。所以咱们的请求须要带上惟一的识别码,这个识别码能够经过 client ip + 时间戳 生成,也可使用 client ip + seq(序列号)。这样,服务端就能够知道这是否是一个已经处理过的请求,并经过缓存直接返回结果。
然而,这对服务端也提出了新的问题:
问题一: 何时能够删掉这些缓存?
毕竟服务端不可能永远保存这些缓存,这会形成容量不够的问题。答案其实也很简单,那就是客户端证实本身收到了回复的时候。对此,咱们 RPC 用户端协议能够带一些附加信息,好比:
对于客户端 RPC 请求,能够带上其近期已经收到回复的序列号,这样,服务端的在解码过程当中能够经过解析该字段,从而删除已经肯定收到回复的缓存
能够经过使用 sequence number 的方法,即客户端的该次请求是上一次请求的序列号 + 1。这样,客户端就能够在请求中带上一个序列号 n,表示 seq < n 的请求我都已经收到了。服务端便可删除全部序列号小于 n 的缓存。以下的示意图展现了这一种方法:
问题二:若是一个请求仍在处理,此时"心急的"客户端又发了一个相同的请求,该如何处理?
这个时候,服务端能够维护一个关于"处理中"的缓存,将正在处理的 request 记录在该缓存,若是有相同请求到来,则先去查询"处理中"的缓存,再去查找"已完成"的缓存,若是存在,则舍弃这条请求,返回已有结果或者等待原有的相同请求处理完成并返回。
本章是对 MIT 6.824 第二课 RPC 内容的总结,主要讲了 RPC 的结构,以及一些潜在错误的处理方法,为 lab1 中 mapreduce RPC 的实现打下基础。