[3][lecture] Infrastructure: RPC and threads

Posted WhateverYoung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[3][lecture] Infrastructure: RPC and threads相关的知识,希望对你有一定的参考价值。

6.824 2018 Lecture 2: Infrastructure: RPC and threads

Why Go? (多年来使用c++完成了也不错,但是内存问题始终是大问题,困扰了很多同学很多时间,这门课程重点不在于定位解决内存问题,c++ rpc package不太理想,估计主要还是过多的segment fault或者内存泄露… Go并发支持一流/rpc库也还不错/GC支持,内存不在成为问题/type safe,简而言之,具有简单和实用两大特点,可以使用)

Why threads? (线程代表了并发,利用多核环境,分布式I/O并发,并发的接收request处理请求,返回response)

线程数设置?(前台io线程/后台任务定时线程,cpu核数,复杂的场景需要慢慢提高直到系统throughput不在增加,Go thread 100s-1000s,虽然代价相比于posix thread小不过也是有的,创建go程代价高于方法调用,PC/regs/stack等等)

线程挑战? (共享数据的同步,mutex或者使用通信代替共享;彼此之间的协调,waitgroup或者channel;并发力度,粗粒度简单但是并发度低;细粒度,并发度高但是更多的竞争和死锁问题)

爬虫

  • 并发的fetch所有web页面,图结构有环,需要去重
  • 串行/锁保护并发模型/信道并发模型
  • 信道模式和锁模式,大多数并发可以用两种方式表达,取决于思考问题的角度,状态法——所保护共享变量,通信方式——信道,等待事件到来——信道

RPC

RPC message diagram:
  Client             Server
    request--->
       <---response

RPC tries to mimic local fn call:
  Client:
    z = fn(x, y)
  Server:
    fn(x, y) 
      compute
      return z
    
  Rarely this simple in practice...

Software structure
  client app         handlers
    stubs           dispatcher
   RPC lib           RPC lib
     net  ------------ net
go提供rpc lib
Uses Go's RPC library
  Common:
    You have to declare Args and Reply struct for each RPC type
  Client:
    connect()'s Dial() creates a TCP connection to the server
    Call() asks the RPC library to perform the call
      you specify server function name, arguments, place to put reply
      library marshalls args, sends request, waits, unmarshally reply
      return value from Call() indicates whether it got a reply
      usually you'll also have a reply.Err indicating service-level failure
  Server:
    Go requires you to declare an object with methods as RPC handlers
    You then register that object with the RPC library
    You accept TCP connections, give them to RPC library
    The RPC library
      reads each request
      creates a new goroutine for this request
      unmarshalls request
      calls the named method (dispatch)
      marshalls reply
      writes reply on TCP connection
    The server's Get() and Put() handlers
      Must lock, since RPC library creates per-request goroutines
      read args; modify reply

A few details:
  Binding: how does client know who to talk to?
    For Go's RPC, server name/port is an argument to Dial
    Big systems have some kind of name or configuration server
  Marshalling: format data into packets
    Go's RPC library can pass strings, arrays, objects, maps, &c
    Go passes pointers by copying (server can't directly use client pointer)
    Cannot pass channels or functions      
  • 客户端没有得到返回时,超时
  • 服务端没收到
  • 服务端执行失败
  • 服务端执行成功
  • Simplest failure-handling scheme:“best effort”,没收到采取一定策略重试,仍旧失败后返回失败
  • 要保证幂等性,否则很危险
  • Better RPC behavior: “at most once”
  • 需要server检测出同一个消息,返回之前执行的结果而不是再执行一次
  • 简单实现,通过每个请求一个XID
  • 复杂性,如何保证唯一?server服务确定何时失效结果(类似tcp,xid递增,假设client发来某个递增seq,则之前的可以失效)或者客户端显示控制失效
  • 当服务端正在执行过程中,dup消息到达?设置pending flag,wait or ignore策略
  • 如果需要保证高可用,需要持久化上述的server状态,同时还需要replica这些信息
  • go rpc实现:a simple form of “at-most-once”
  • Go RPC never re-sends a request,So server won’t see duplicate requests
  • Go RPC code returns an error if it doesn’t get a reply
  • 最理想的 “exactly once”?
    • unbounded retries + duplicate detection + fault-tolerant service
      Lab 3

了解go

go channel
go mutex
Use Go's race detector:  https://golang.org/doc/articles/race_detector.html
go test -race

go rpc lib

FAQ

Q: Go channels 原理,如何在并发go程中保证了同步

A: 总体来说,信道中有buffer和锁,buffer的访问通过锁来保证串行,同时结合条件变量等机制来完成阻塞和通知,可以通过Go sync.Mutex和sync.Cond 尝试实现信道,参考https://golang.org/src/runtime/chan.go

Q: goroutines如何完成并发,多核

A: Goroutine是用户态线程,由Go-runtime负责调度在实际的cpu核上,如果只有1个核心,为时间片模式,如果多核会保证调度到多核中

Q: 不想阻塞的情况下,信道如何周期性查看是否到达?

A: 建议创建独立Go程来阻塞单独的信道,主线程可以做其他事情,此模式可以生效时为最简单方式。也可以用select + default来等待多个信道同时不阻塞,如果要等一段时间,select+time.After,参考https://tour.golang.org/concurrency/6
https://gobyexample.com/timeouts

Q: sync.WaitGroup和信道关系?

A: sync.WaitGroup场景更特殊一些,仅用于等待多个任务结束,信道更加通用,原子和底层,信道可以实现sync.WaitGroup

Q: What are some important/useful Go-specific concurrency patterns to know?

A: Here’s a slide deck on this topic, from a Go expert:
https://talks.golang.org/2012/concurrency.slide

Q: When is it right to use a synchronous RPC call and when is it right to
use an asynchronous RPC call?

A: Most code needs the RPC reply before it can proceed; in that case it
makes sense to use synchronous RPC.
But sometimes a client wants to launch many concurrent RPCs; in that
case async may be better. Or the client wants to do other work while it
waits for the RPC to complete, perhaps because the server is far away
(so speed-of-light time is high) or because the server might not be
reachable so that the RPC suffers a long timeout period.
I have never used async RPC in Go. When I want to send an RPC but not
have to wait for the result, I create a goroutine, and have the
goroutine make a synchronous Call().

以上是关于[3][lecture] Infrastructure: RPC and threads的主要内容,如果未能解决你的问题,请参考以下文章

lecture-7 递归

lecture 3

CS3334 Lecture 3

CS3402 Lecture 3

Lecture 3

lecture 3