Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lec2:RPC与线程机制(Go语言实战) #3

Open
chaozh opened this issue Apr 11, 2017 · 5 comments
Open

Lec2:RPC与线程机制(Go语言实战) #3

chaozh opened this issue Apr 11, 2017 · 5 comments
Labels

Comments

@chaozh
Copy link
Owner

chaozh commented Apr 11, 2017

课前基础练习:Lab0 Go语言入门
观看视频:Lecture2Lecture5讲义
学习示例:

@chaozh chaozh changed the title Lec2:RPC与线程机制(Go语言入门) Lec2:RPC与线程机制(Go语言实战) Apr 11, 2017
@chaozh
Copy link
Owner Author

chaozh commented Apr 15, 2017

线程是操作系统级别的并发机制,可以充分利用CPU的多个运算核心,在分布式系统中IO并发都会涉及多线程操作,比如启动一个线程等待其他Server返回IO信息时主线程可以继续处理下一个请求。多线程间可以共享数据信息,但是每个线程都会有自己的程序计数器(PC)、寄存器、栈等,线程是操作系统调度的最小资源单位。

Go语言支持程序多创建线程(在Go语言中表现为协程,即用户态线程,比操作系统级别的线程机制占用资源更少),通常线程数量比物理核数多,Go运行环境会调度这些线程在多核上运行,要注意线程也并非免费的,创建线程要比一个函数方法调用还是费资源。

使用线程时的挑战:

  • 共享数据:处理临界资源(比如使用锁解决)
  • 线程协调:等待资源容易导致死锁(使用Go语言的channel机制或WaitGroup解决)
  • 并发粒度:并发度越大,越容易出现竞争和死锁

本期问题:请完成Crawler并发练习

需要解决两个挑战:

  1. 安排IO并发:获取一个URL内容的同时处理另一个URL
  2. 每个URL保证仅处理一次:避免浪费带宽,需要机制记录URL的访问历史

@chaozh
Copy link
Owner Author

chaozh commented Apr 16, 2017

解决方案思考: 查看Crawler示例,Go语言中的并发练习

  • 方案,使用go协程和共享map结构:为每个url创建线程,需要使用lock和waitGroup保证顺序,同时保证map的存取操作原子性
  • 方案,使用channels:go内部实现使用锁保证,会自动阻塞等待资源

最佳解决方案:
尽量使用channel取代共享变量(shared memory),与子线程同步使用channels
可以使用Go语言的并发检查机制
比如go test -race mypkg

@chaozh
Copy link
Owner Author

chaozh commented Apr 22, 2017

Remote Procedure Call (RPC)

分布式系统的关键部分(后面的实验都会涉及使用RPC),RPC理想上想把网络通信实现同本地函数调用一样,RPC的目的:

  • 更容易编写网络通信程序
  • 隐藏客户端服务器通信的细节
  • 客户端调用更加像本地的过程调用
  • 服务端处理更加像本地的过程调用

Go语言有比较好的实现机制

一些实现需要考虑的细节:

  • 应该调用哪个服务器函数(handler)?
  • 序列化:需要格式化数据到网络包中,可能需要处理棘手的数组,指针,对象等。还有些东西你不能传递,比如channels和function等。
  • 绑定:客户端怎么知道应该跟谁通信?也许客户端使用服务器的hostname。也许使用命名服务,将服务名字映射到最好的服务器。
  • 线程:客户端可能使用多线程,多于一个调用没有被处理,对应的处理器可能会缓慢;服务器经常将每个请求放置在独立的线程中处理。

特别是需要考虑怎么处理失败?比如:网络丢包,网络断线,服务器运行缓慢,服务器崩溃等问题。
客户端如何对待RPC请求失败?

  • 客户端没有获取到服务器的回复。
  • 客户端不知道服务器是否接收到请求!也许服务器的网络在发生请求前就失败了。

简单方案是实现“至少一次”机制:RPC库等待回复一段时间,如果还是没有回复到达,重新发生请求。重复多次,如果还是没有回复,那么返回错误给应用程序。但是需要应用处理可能出现的多个写副本(因为多次请求导致)

更好的方案是实现“至多一次”机制:服务器的RPC代码发现重复的请求,返回之前的回复,而不是重写运行。客户端让每一个请求带有唯一标示码XID(unique ID),相同请求使用相同的XID重新发送。

实现“至多一次”机制的困难之处:

  • 怎么确认xid是唯一的?使用很大的随机数或是将唯一的客户端ID(比如ip地址)和序列号组合起来
  • 老的RPC信息什么时候丢弃是安全的?使用唯一的客户端id、上一个rpc请求的序列号、客户端的每一个RPC请求包含"seen all replies <=X"、类似tcp中的seq和ack。保证每次只允许一个RPC调用,到达的是seq+1,那么忽略其他小于seq。客户端最多可以尝试5次,服务器会忽略大于5次的请求。
  • 当原来的请求还在执行,怎么样处理相同seq的请求?服务器不想运行两次,也不想回复。需要给每个执行的RPC标识pending;等待或者忽略。

Go RPC实现的”最多一次“?

  • 打开TCP连接
  • 向TCP连接写入请求
  • TCP也许会重传,但是服务器的TCP协议栈会过滤重复的信息
  • 在Go代码里面不会有重试(即:不会创建第二个TCP连接)
  • Go RPC代码当没有获取到回复之后将返回错误
    -- 也许是TCP连接的超时
    -- 也许是服务器没有看到请求
    -- 也许服务器处理了请求,但是在返回回复之前服务器的网络故障

参考讲义翻译

@lwhile
Copy link

lwhile commented Apr 22, 2017

@chaozh 讲义翻译404了

@chaozh
Copy link
Owner Author

chaozh commented May 16, 2017

先看看Lab2实验代码labrpc.go中的实现,它很像Go的RPC包,但是带有模拟网络

  • 这个模拟的网络会延迟请求和回复
  • 这个模拟的网络会丢失请求和回复
  • 这个模拟的网络会重新排序请求和回复
  • 对之后的实验二(Raft实现)测试非常有用

注意:实验一 MapReduce实现使用的是Go的RPC包

程序结构描述

  • 服务器(Server), 支持含有多个服务srv := MakeServer() srv.AddService(svc)
  • 客户端(ClientEnd),调用Call()函数,发生一个RPC请求并等待结果 reply := end.Call("Raft.AppendEntries", args, &reply)
  • 通信(Network),每个结构都持有一个sync.Mutex

关键方法

  • Server.AddService,可能在多个goroutine中调用,deter的作用是在函数退出前,调用之后的代码,就是添加完新服务后,做解锁操作。
  • Server.dispatch,分发请求,为什么持有锁?跟AddService并发访问可能冲突。
  • ClientEnd.Call,使用反射查找参数类型,使用“gob”序列化参数(Go的自带编解码包gob.NewEncoder),ClientEnd.ch(chan reqMsg)是用于发送请求的通道e.ch <- req,需要一个通道从接收回复(<- req.replyCh)
  • Network.MakeEnd,创建客户端,使用一个线程或者goroutine模拟网络,每个请求分别在不同的goroutine处理。一个端点是否可以拥有多个未处理的请求???。为什么使用rn.mu.Lock()?锁保护了什么?保护Network中的活跃数组信息
  • Network.ProcessReq,如果网络不可靠,可能会延迟或者丢失请求,在一个新的线程中分发请求。通过读取e.ch等待回复直到时间过去100毫秒。100毫秒只是来看看服务器是否崩溃。最后返回回复(req.replyCh <- reply),ProcessReq没有持有rn锁,是否安全?
  • Service.dispatch,为请求找到合适的处理方法

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants