跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • RPC 的变革 —— ARPC 项目自荐
未分類
2 12 月 2020

RPC 的变革 —— ARPC 项目自荐

RPC 的变革 —— ARPC 项目自荐

資深大佬 : lesismal 2

已加入 awesome-go

RPC 的变革 —— ARPC 项目自荐

项目地址: https://github.com/lesismal/arpc

一、ARPC 示例

echo server

package main  import (  "log"   "github.com/lesismal/arpc" )  func onEcho(ctx *arpc.Context) {  str := ""  err := ctx.Bind(&str)  if err != nil {   log.Printf("/echo error: %v", err)   return  }  ctx.Write(str)  log.Printf("/echo: %v", str) }  func main() {  svr := arpc.NewServer()   // register handler  svr.Handler.Handle("/echo", onEcho)   svr.Run(":8888") } 

echo client

package main  import (  "context"  "log"  "net"  "time"   "github.com/lesismal/arpc" )  func dialer() (net.Conn, error) {  return net.DialTimeout("tcp", "localhost:8888", time.Second*3) }  func main() {  client, err := arpc.NewClient(dialer)  if err != nil {   log.Fatalf("NewClient failed: %v", err)  }  defer client.Stop()   request := "hello"  response := ""  // err = client.Call("/echo", &request, &response, time.Second*5)  err = client.CallWith(context.Background(), "/echo", &request, &response)  if err != nil {   log.Fatalf("Call /echo failed: %v", err)  } else {   log.Printf("Call /echo Response: "%v"", response)  } } 

二、传统主流的 RPC 框架的局限 /不爽

1. 网络交互模式单一,无法支持更丰富的场景

传统主流 RPC 的网络交互主要是 [客户端到服务端,请求-应答] 的模式,比较单一。按照这个模式以及顾名思义“远程过程调用”,其实 HTTP 也算是 RPC 的一种,只是由于其短连接和 HTTP 协议的文本编码格式等原因导致性能和资源的浪费,所以很少有直接把 HTTP 称为 RPC 。

网络通信的本质是数据收发,客户端和服务端都可以随时主动发送消息给对方,比如推送服务、IM、游戏等;而且一方发送数据给另一方,有时是不需要回复的,比如VOIP 电话,其他不要求强一致的消息广播、推送等。

这里把需要应答的通信定义为 Call ,不需要应答的通信定义为 Notify,则网络交互按照发起方、是否需要应答,可以分为以下四种基本模式:

1 )客户端发起请求,服务端应答

2 )服务端发起请求,客户端应答

3 )客户端向服务端发出通知 /推送,无需应答

4 )客户端向服务端发出通知 /推送,无需应答

如此看来,传统主流 RPC 就像是个大内男公务员,因为它只支持了第一种基本模式,只覆盖了 25%——甚至说它的网络通讯模式有点不完整,都算是一种褒奖,因为 25%的模式支持那是相当不完整。

而只支持请求-应答的模式也限制了很多业务场景,其他更广泛的业务场景比如推送服务、IM、游戏,我们还需要自定义各种协议。

2. Server 端函数调用的写法,函数返回即是调用结束,不够灵活

传统主流 RPC 服务端的写法通常是一个函数,函数返回后框架层把返回值打包发送给客户端作为应答,不支持在该函数中进行异步响应,尤其是 golang 的 RPC ,有的框架为了代码简单,没有写协程,发送数据时直接写到 Conn,高并发写时竞争比较明显会增加时延;有的框架默认采用读协程收到数据 one-by-one 的方式处理,存在线头阻塞的问题,有的框架采用每个消息新开一个 go 协程处理,高并发时协程数量可能暴增、比较浪费,不支持按单个 Method/Router 定制同步或者异步处理,也不支持在 Method/Router handler 内由业务层自主选择同步处理、新开 go 协程异步或者协程池等异步等方式的处理。

三、关于 ARPC

1. 高性能

想说 ARPC 比其他流行的 golang RPC 性能都好,但是自吹最强好像没有说服力,感谢 rpcx 有做一些主流 RPC 框架的性能对比,老仓库 已经废弃并且那时 ARPC 还没有出生,有兴趣的同学可以到 新仓库 跑下代码进行对比,测试时请注意排除其他程序的干扰。

目前最为主流的 gRPC 因为官方综合考量使用了 HTTP2 ,详情参考 gRPC 的动机和设计原则,注定了不能很高性能。而很多 RPC 的业务场景,是基于内部服务集群, HTTP2 的加密流程等显得有些性能浪费。而 ARPC 更注重性能和灵活性,通信协议部分交由业务层决定,通常建议使用 TCP 作为基础通信协议,如有需要,业务层也可以使用 TLS 、Websocket 或者 KCP 等 。

2. 网络交互模式全面

上面在 不爽 的部分提到了传统主流 RPC 的不完整, ARPC 当然要比较全面的支持这四种基本交互模式:

1 )客户端发起请求,服务端应答

2 )服务端发起请求,客户端应答

3 )客户端向服务端发出通知 /推送,无需应答

4 )客户端向服务端发出通知 /推送,无需应答

3. 丰富的业务场景支持

由于网络交互模式相对全面,ARPC 可以用于处理多种常规业务场景而不受类似 HTTP 短链接、单向请求-应答方式的限制。比如:

1 )推送服务

2 )游戏服务

3 )聊天服务

4 )其他需要长连接、双向、广播等灵活交互方式的业务

4. 写法简单

如[示例](#rpc 进化–arpc-项目自荐)所示,Handler 不采用函数返回即调用结束的形式,写法简单、更像 HTTP Handler 。由于也不强制使用编解码器,甚至不必生成结构化消息或者服务如 Protobuf 的 Message 、Service 等,这样也带来一些额外的好处,比如热点的结构化数据,业务层可以在数据更新时序列化一次并缓存起来,有需要时直接发送序列化之后的数据给需求方,避免每次发送给每个连接都需要进行一次序列化的浪费,在高在线量的广播类业务中这点尤为明显。

其他一些 RPC 框架喜欢注册对象的方式,由框架层通过反射去解析符合 Handler 格式的方法进行隐式注册,由于早年被 C++的各种语言标准、机制等背后动作玩弄得辛苦,golang 项目中希望框架层和业务层都尽量不让用户增加没有必要的心智负担(比如通过对象隐式注册的方式:没有带来性能提升,没有架构设计模块设计的解耦或者其他优化), ARPC 的设计遵循简单、透明的原则,所以像 HTTP 一样进行显式注册,如果有的同行喜欢玩弄语法糖技巧或者被语法糖技巧玩弄,可以自行定制。

5. 更灵活的同步异步

支持单个 Method/Router Handler 级别设置同步或者异步处理,也支持 Handler 内由业务层自主控制同步或异步回包、从而针对性定制快 /慢接口的协程数量控制与线头阻塞问题处理。

6. 最少依赖

目前如果只使用 ARPC 默认参数,则只使用了 golang 标准库,不需要依赖其他第三方 package 。

7. 易扩展

1 )网络协议支持:由用户自主决定,服务端实现 net.Listener 、客户端实现 net.Conn 即可做为 ARPC 的网络载体,arpc/examples/protocols 已经提供了 KCP 、 QUIC 、 TLS 、 UnixSocket 、 UTP 、 Websocket 等示例,欢迎参考。

2 )非结构化的消息体编解码支持:可以直接用 string 、 *string 、 []byte 、 *[]byte 、error 、 *error 等作为消息体参数。

3 )结构化的消息体编解码支持:为了最少依赖, ARPC 默认使用了 encoding/json 作为结构化消息体的编解码器,性能不够强,但是业务层可以很方便地设置使用 json-iter 、Protobuf 等作为结构化消息地编解码器。

4 )消息体编解码中间件支持: ARPC 提供了消息体编解码中间件机制, arpc/extension/middleware/coder 子包实现了 Gzip 、 Tracer 作为默认示例,有需要的用户可以参考实现自行定制,使用示例在 arpc/examples/middleware/coder 。

5 ) Method/Router 的中间件支持: ARPC 提供了类似流行的 golang HTTP 框架的中间件,方便业务层自行扩展, arpc/extension/middleware/router 子包实现了 Logger 、 Recover 、 Graceful 作为默认示例,有需要的用户可以参考并实现自行定制,使用示例在 arpc/examples/middleware/router

6 ) Web JS Client 支持: ARPC 提供了 JS Client 及示例:API 示例 、 聊天示例。有了 JS Client, 不需要类似其他 RPC 框架那样部署 HTTP 转换 RPC 的网关,前端可以直接通过 Websocket 与 ARPC 服务进行交互,而且因为 ARPC 已经包括了消息的编解码、Method/Router Handler,比 melody 等只封装了收发数据的基础 websocket 框架更方便。

其他扩展不一一列举了,欢迎有兴趣的同学查看代码或者 New issue 。

8. 更多示例

arpc/examples提供了较为丰富的示例,如 通知 、 广播 、 优雅退出 、 服务注册与发现 、 连接池 、 kcp/quic/tls/websocket 等协议支持 、 发布订阅 、 JS Web Chat 等,请见 arpc/examples 。

9. 其他

个人精力有限,并且 golang 是世界上第二好的编程语言,所以暂时不考虑对其他语言的支持,欢迎 pr 、issue 。

大佬有話說 (66)

  • 資深大佬 : wellsc

    安利一下 rSocket

  • 資深大佬 : no1xsyzy

    主要是 RPC 的含义就是 Remote Procedure Call
    无需应答是否要求保证送达?要保证送达需要回执,这个从 TCP 层面做还是从你应用层做多大额外开销的,把应答丢弃就行了
    不要求送达,那 TCP 相比 UDP 的开销比你应用层更明显,游戏恐怕不太可能用你这个方法。

    另外,ARPC 让人感觉这个是 ARP 的 Client 。

  • 資深大佬 : so1n

    如果不等函数调用结束就返回 那不就是消息队列吗…

  • 主 資深大佬 : lesismal

    @wellsc 看了下 rsocket-go,风格比较 java,有点臃肿了,使用起来不够方便简洁

    “`golang
    package main

    import (
    “context”
    “log”

    “github.com/rsocket/rsocket-go”
    “github.com/rsocket/rsocket-go/payload”
    )

    func main() {
    // Connect to server
    cli, err := rsocket.Connect().
    SetupPayload(payload.NewString(“Hello”, “World”)).
    Transport(rsocket.TCPClient().SetHostAndPort(“127.0.0.1”, 7878).Build()).
    Start(context.Background())
    if err != nil {
    panic(err)
    }
    defer cli.Close()
    // Send request
    result, err := cli.RequestResponse(payload.NewString(“你好”, “世界”)).Block(context.Background())
    if err != nil {
    panic(err)
    }
    log.Println(“response:”, result)
    }
    “`

  • 主 資深大佬 : lesismal

    @so1n “不等函数调用结束就返回” —— 这个可能是兄弟误解了,ARPC 说的不是不等结束就返回,而是可以收到请求后自由选择什么时候回复,可以在处理函数中回包也可以在处理函数之外异步回包之类的,不像其他 RPC 那样函数调用结束了就返回了。

  • 主 資深大佬 : lesismal

    @no1xsyzy “主要是 RPC 的含义就是 Remote Procedure Call”
    —— 这个定义没错,但正式因为这个定义,限制了很多场景的网络交互方式,比如 web 技术栈,在不同的年代以不同的方式去支持连接复用(比如 http 1.x keepalive, 2.0 以后的长连接)、非 RPC 方式的协议(比如 socketio 、websocket ),ARPC 就是为了简化这种交互模式来反推 RPC 场景,希望能够简化依赖、一个库能支持多数业务、而不是我用了 http 满足不了需求还得使用 grpc 然后还需要再使用个自定义长连接协议或者 websocket 等,这就是为什么我说传统主流 RPC 不爽的原因

    “无需应答是否要求保证送达?要保证送达需要回执,这个从 TCP 层面做还是从你应用层做多大额外开销的,把应答丢弃就行了”
    “不要求送达,那 TCP 相比 UDP 的开销比你应用层更明显,游戏恐怕不太可能用你这个方法。”
    —— 先说”送达”吧,这个是误解,ARPC 没说不要求送达,transport 层使用长连接或者可靠连接作为载体的应用层业务,transport 层本身来负责正常情况时连接能够保持情况下的送达,但是任何 transport 层也都无法保证自己这一层的 100%送达,比如链路中断、设备掉电、切换网络。应用层更没法保证送达,基于正常情况下的业务逻辑交互作业、加上完善的状态管理、错误处理之类的就可以了
    —— 再说 “不要求送达”,这个是兄弟的误解,”不需要应答” != “不要求送达”,所以基于”不要求送达”推断”游戏能不太可能用 ARPC”也是不必要的。而且,ARPC 本身就是基于游戏和其他一些有状态服务的框架、为了反推那些被 RPC 限制了的场景技术栈和资源优化而实现的

    另外,ARPC 让人感觉这个是 ARP 的 Client 。
    —— 名字这个没办法,众口难调,每个人都会有不同的看法。我定义成 ARPC 大概有两层意思:一是希望像 “老 A”一样,努力做成同类基础设施中最好的;二是 “Async RPC” 的缩写,因为可以自由选择同步还是异步回包、回包方式不受传统 RPC 那种处理函数结束就意味着调用结束的限制

  • 主 資深大佬 : lesismal

    @wellsc 另外,还没有深入研究 rsocket,不知道是否方便支持服务端广播之类的

  • 資深大佬 : mepwang

    传统的分布式调用有很多坑要填的,比如 90 年代的 CORBA 技术就试图搭出一套完全的分布式对象体系。比如你的框架里面,假如服务器端单个请求处理比较耗时的话,多个客户端的并发请求是否会被阻塞?当个客户端的同一个远程方法的多个并发调用,是否会被阻塞? RPC 框架一定和应用场景紧密相连的,能满足几个实际应用场景需求的框架,就是好框架

  • 主 資深大佬 : lesismal

    @mepwang

    5. 更灵活的同步异步
    支持单个 Method/Router Handler 级别设置同步或者异步处理,也支持 Handler 内由业务层自主控制同步或异步回包、从而针对性定制快 /慢接口的协程数量控制与线头阻塞问题处理。

    —— 主贴介绍的这部分有讲,每个 handler 都支持灵活的同步异步策略,用户可以自己设定请求来了是 one by one 的方式处理还是每个请求开一个新协程,甚至单个请求的处理函数里业务层自己根据实际情况选择同步还是新开协程或者协程池处理。至少 ARPC 框架层不存在这些坑点。除了 erlang golang 的其他语言可选的方式不多,要么像 node 这种也是语言层面提供异步以及各种语法糖,要么像 c++这种自己定制线程 /任务池、连接池各种基础轮子

    另外 “多个客户端的并发请求是否会被阻塞” 不只是服务端框架的问题。请求处理对应的业务逻辑比如数据层、其他调用链等耗时操作也可能导致响应慢,还有比如业务层没有做限流导致的请求量爆炸,甚至部署的网络链路不稳定导致 transport 层拥塞,这些非框架原因导致的超载是框架自己不可控的、需要留给业务层处理。当然,有的微服务框架做得大而全,框架本身包含了限流熔断负载均衡等全家桶组件,ARPC 的定位则是网络和协议交互这一层的小而美,毕竟大而全太耗精力而且并不是所有项目都需要大而全,绝大多数团队的业务场景直接拿别人大而全的框架反倒成本太高、不太合适

  • 主 資深大佬 : lesismal

    @mepwang 不同领域的分布式系统差别太大了,比如 web 、游戏、分布式数据库或者计算引擎。每种领域又有很多具体的子场景,业务耦合的方式不同,架构设计的方式也都不同,甚至天差地别。通常在 web 领域流行的分布式理论,拿到 MMORPG 里就完全不能用

    近十年的互联网发展速度太快了,最基本的一个需求,比如推送,很多应用可能都需要,但是传统的 RPC,server 端是不支持广播的,所以要使用 http static,http api,websocket,服务集群内部还要 RPC,而除了 http static,其他的场景 ARPC 都可以支撑,能很大程度简化技术栈,并且性能更高

  • 資深大佬 : Catstyle

    啊,13 年开始就这么用了

  • 資深大佬 : XiLingHost

    @lesismal 名字可以改成 aRPC,就类似于 gRPC

  • 資深大佬 : kevinwan

    我们有 zRPC,基于 gRPC 的,我觉得 gRPC 还是比较通用解决方案,当然也鼓励创新
    https://github.com/tal-tech/go-zero

  • 資深大佬 : fox0001

    感觉是造了双筷子,然后改个名叫“叉子”……纯直觉,没别的意思

  • 主 資深大佬 : lesismal

    @XiLingHost 这个都行,代码 package 都是 arpc,个人开发者没那么大的社区影响力,ARPC/aRPC/arpc 都随意 :joy:

  • 主 資深大佬 : lesismal

    @kevinwan 嗯嗯 star 支持了。前阵子还提了个服务注册发现确保强一致的 [issues/227]( https://github.com/tal-tech/go-zero/issues/227) ,其实加上强一致保障不复杂,etcd 的 “go.etcd.io/etcd/client/v3/concurrency” 子包自带了分布式锁的实现:

    “`golang
    client, err := clientv3.New(clientv3.Config{
    Endpoints: endpoints,
    DialTimeout: 5 * time.Second,
    })
    if err != nil {
    log.Error(“NewRegister [%v, %v] clientv3.New failed: %v”, key, value, err)
    return nil, err
    }

    session, err := concurrency.NewSession(client)
    if err != nil {
    log.Error(“NewRegister [%v, %v] concurrency.NewSession failed: %v”, key, value, err)
    return nil, err
    }

    mux := concurrency.NewMutex(session, RegisterMutexPrefix)
    err = mux.Lock(context.TODO())
    if err != nil {
    log.Error(“NewRegister [%v, %v] Lock failed: %v”, key, value, err)
    return nil, err
    }
    defer mux.Unlock(context.TODO())
    “`

    然后先 Get 判断再 Put 就行了

  • 主 資深大佬 : lesismal

    @fox0001 这么说也对,因为其实我最早不是做 web 服务为主的业务的,最开始做就都是有状态的长连接服务,后面再做 web 类的,觉得 http 相关的 api 、rpc 技术栈虽然工程实践上积累了很多,但是基础设施还是太低效了。这几年又是挖矿,又是全球升温环境恶化,而且以后随着大数据、AI 、5G+这些的更加普及,计算量会越来越大,对应的能源消耗也会越来越大。以前的 http 因其文本协议的便利极大促进了互联网的发展,但也正是由于它短链接、文本格式等低效浪费问题,会造成日趋爆发的数据和计算量的巨大浪费,所以才会有 http 2.0 3.0 quic mqtt 各种升级方案。

  • 主 資深大佬 : lesismal

    @lesismal @kevinwan @fox0001

    网络交互是通用的基础设施,4 种基础网络交互模式也早已有之,所以我这个也不算创新

  • 主 資深大佬 : lesismal

    @kevinwan 还是举推送的例子,gRPC 这些好像不太便利。很多接口类业务,其实如果换成有状态服务,性能和软硬件消耗都能节省不少,但是难度当然也略高些,如果是用户之间还存在复杂交互耦合的(比如游戏),则业务复杂度和编码难度更高

  • 主 資深大佬 : lesismal

    欢迎各位体验、尝试

  • 資深大佬 : kevinwan

    @lesismal 感谢,晚点我看看,也 star 一下 arpc

  • 資深大佬 : DoctorCat

    @kevinwan 看着不错啊,有支持 Tracing 么?

  • 主 資深大佬 : lesismal

    @kevinwan 感谢支持!多多交流跟各位大佬学习!

  • 主 資深大佬 : lesismal

    @DoctorCat 没有默认支持其他 tracing,有中间件机制可以进行扩展。

    这里有个简单 tracing 的扩展示例:
    https://github.com/lesismal/arpc/tree/master/extension/middleware/coder/tracer

    这里是简单 tracing 的使用示例:
    https://github.com/lesismal/arpc/tree/master/examples/middleware/coder/trace

    欢迎各路道友 pr 或者自己项目扩展实现、交流

  • 資深大佬 : kevinwan

    @DoctorCat 有的,不过正在适配到 opentracing,我们需要通过 kibana 查询到调用关系,所以 span id 是类似:0, 0.1, 0.1.1, 0.2 这种,最近会适配到 opentracing.

  • 資深大佬 : teawithlife

    看得出主花了不少精力,点个 star 支持一下

  • 資深大佬 : kevinwan

    @lesismal 已 star 。go-zero 的重点是把我们千万级日活的工程经验和最佳实践通过开源的方式带给大家,通过工具帮助大家更关注业务。不太会针对某个特定领域做深度定制,这可能是咱们两个框架的区别,不知道我是不是说错了,请指正哈

  • 資深大佬 : DoctorCat

    @kevinwan 等你们适配好的,我们这边试试,现在人手少没法参与到开源 PR

  • 主 資深大佬 : lesismal

    @DoctorCat 你们使用的哪些 tracing ?我空了学习研究下看看自己能不能加上

  • 主 資深大佬 : lesismal

    @teawithlife 感谢支持!

  • 主 資深大佬 : lesismal

    @kevinwan 感谢大佬支持!

  • 資深大佬 : DoctorCat

    @lesismal 亚马逊 xray 或者 sentry 这类的,要么就是开源的一些支持 OpenTracing 的平台

  • 資深大佬 : tkl

    推广挺用心 支持

  • 資深大佬 : kevinwan

    @lesismal go-zero 的 goctl 是支持自定义模板的,完全可以自定义为基于 arpc

  • 主 資深大佬 : lesismal

    @DoctorCat 好,闲了研究下

  • 主 資深大佬 : lesismal

    @tkl 感谢支持!

  • 主 資深大佬 : lesismal

    @kevinwan 赞,这个够灵活,哈哈哈

  • 資深大佬 : kevinwan

    @lesismal 你甚至可以通过插件生成 php 代码

  • 資深大佬 : kevinwan

    @DoctorCat 全链路追踪已经有的,只是要用 jaeger 展示的话需要适配一下

  • 主 資深大佬 : lesismal

    @kevinwan 我选择把世界上最好的语言供奉起来,干业务这种还是交给 go 好些

  • 資深大佬 : xeaglex

    赞,和我之前用 gRPC 时的感想不谋而合。区别是你真的做出来了

  • 資深大佬 : no1xsyzy

    @lesismal
    行吧…… 看上去想要弄个任何交互底层上的通用抽象层。

    “无需应答是否要求保证送达?”是个分支,分别分析了 “要求送达” 和 “不要求送达” 的情况

    送达的话,依赖送达回执和避免重复送达就成,我是指(类似 MQTT 的) QoS 。
    传输层送达不会反应在应用上,会导致重传浪费时间。

    不要求送达是指前提就是不要求送达(游戏通常是不要求送达的),那么解决方案一般不会是 TCP

    (其实 ARP 好像并不分 C/S )

  • 資深大佬 : IamYourDad

    主, 我没看懂, 样例里面 server->client 是不是多次一举啊, 你想调用 client.dosomthing, 直接在 response 返回不就行了吗, client 读 response 自己 dosomthing, 有什么应用场景, 能不能举例呀

  • 主 資深大佬 : lesismal

    @xeaglex 哈哈哈,欢迎品尝 ^_^

  • 主 資深大佬 : lesismal

    @no1xsyzy 嗯嗯,文字交流、一些场景没有既定的“黑话”,大家可能会理解出一些歧义

  • 主 資深大佬 : lesismal

    @IamYourDad 兄弟,我也没太看懂,能详细描述下不?比如

    “样例里面 server->client 是不是多次一举啊“,这里的多此一举是不是指 ctx.Write()?比如,return xxx 然后框架层自己 Write 给 client 就行了、不需要让用户自己去 Write ?如果是这个意思,请看主贴的这个部分: “2. Server 端函数调用的写法,函数返回即是调用结束,不够灵活” 。而且,这里是可以异步回包的,方便业务层灵活定制业务模块的任务池、流控等,比如:

    func onEcho(ctx *arpc.Context) {
    str := “”
    err := ctx.Bind(&str)
    if err != nil {
    log.Printf(“/echo error: %v”, err)
    return
    }

    // 这里也可能不直接用 go 、而是使用其他业务模块的协程池异步回包
    go func() {
    // do something.
    ctx.Write(str)
    }()
    }

    另外,兄弟,建议改个 ID,你这个 ID 别人读出来或者看文字心里默读的时候其实是你自己吃亏啊。。。

  • 資深大佬 : iyangyuan

    Spring Cloud 使用 http 协议怎么说

  • 主 資深大佬 : lesismal

    @iyangyuan 我不用 java

  • 主 資深大佬 : lesismal

    @iyangyuan 上一条 url 跟文字连一起了无法跳转,而且我还没有编辑权限,重新贴下 url:

    https://www.jianshu.com/p/ed3f8f983764

  • 資深大佬 : kevinwan

    @lesismal 我只是举个例子,go-zero 可以生成任意语言的服务端和客户端代码,插件即可

  • 主 資深大佬 : lesismal

    @kevinwan 嗯嗯了解

  • 資深大佬 : robot9

    感觉 rpc 最重要的是能方便准确的定义 interface 和 data structure

  • 資深大佬 : so1n

    @lesismal 是指有序的 request→response→request→response 变为 request,request 然后等处理完了再 response,response 吗?忘记叫啥了,io 多路复用?

  • 主 資深大佬 : lesismal

    @so1n
    单个连接上的消息是顺序读取的,你说的这种是 one-by-one 的方式进行处理,处理完一个再处理下一个,http 是这样子的,一个处理完之前下一个要排队等待,如果一个处理慢了会导致其他消息也被阻塞、这个问题通常叫线头阻塞
    io 多路复用是指 select 、poll 、epoll 、iocp 、kqueue 等,通过事件机制、异步 io 对多个文件描述符(网络连接也是文件描述符的一种)进行高效的异步 io 操作
    兄弟概念有点迷茫,可以多看些好书比如 CSAPP 、APUE 、UNP 之类的,啃下来消化消化应该会有很大帮助

  • 資深大佬 : so1n

    @lesismal 我是突然忘记了那种该叫啥,所以你的异步是不是指这个方式?

  • 主 資深大佬 : lesismal

    @robot9 这两点对于非 rpc 的领域好像也同样重要,所以,反倒不是 rpc 的重点了,而是通用场景的重点

  • 主 資深大佬 : lesismal

    @so1n 兄弟,先读点好书,或者搜知识点,阻塞、非阻塞、同步、异步,还有其他的很多基础知识补上再交流,否则问出来的问题容易把我问死,不是不想回答,但基础知识的科普,我没那么多时间啊,而且零碎的知识不如你自己系统性学习的效果好

  • 資深大佬 : so1n

    @lesismal 那算了,我时间也不多……我只是觉得你那个说不清,很难理解异步返回是代表什么

  • 主 資深大佬 : lesismal

    @so1n

    一次完整的调用过程指 client 端 Call 调用的返回,其中大致包括了几个主要流程:
    1. client 发送请求数据
    2. server 接收到请求数据
    3. server 处理请求
    4. server 发送响应数据
    5. client 收到请求数据,调用结束

    因为传统 RPC server 端的流程,以 go 的 “net/rpc” 为例,对于每个连接的流程大概是
    go func() {
    for {
    2. server 接收到请求数据
    go func() {
    3. server 处理请求 // 这里是回调业务层注册进来的 handler
    4. server 发送响应数据 // 业务层处理完之后,框架层把 3 中的 handler 返回值打包成响应数据,发送给 client
    }()
    }
    }()

    3 中 handler 是默认 go 一个新的协程进行处理,这种在连接数非常多、并发请求量大的时候协程数量多、各项资源消耗比较浪费
    但是业务层处理 3 的流程,又不能自主选择是否每次 go 一个新的协程

    我在主帖中说的是:”异步响应”和”异步回包”。ARPC 提供了更灵活的机制,大概如下:
    处理请求的 handler = 3+4 ( server 处理请求+server 发送响应数据)
    go func() {
    for {
    2. server 接收到请求数据
    if 注册时设置为异步处理 {
    // 此处是指 “异步响应”
    go handler() // 3+4
    } else {
    handler() // 3+4
    }
    }
    }()
    而 handler 的实现中也可以自主选择同步或者异步回包,比如:
    func handler(ctx *arpc.Context) {
    // do something
    if condition {
    go ctx.Write(…) // 此处指”异步回包”
    或者
    // 此处是指 “异步响应”
    go func() {
    // do something
    go ctx.Write(…) // 此处是指 “异步回包”
    }
    } else {
    // do something
    ctx.Write(…)
    }
    }

    晚上状态有点懵逼,不知道有没有写错的地方,先大概看下吧

  • 主 資深大佬 : lesismal

    v 站玩的少,markdown 和代码段的格式不知道怎么搞,编辑好的缩进发出来都给我整没了

  • 主 資深大佬 : lesismal

    @lesismal 或者分成”异步请求处理” 和 “异步回包”来描述更清楚些,但是这个处理流程比较简单,就几行代码,就不做太强的概念辨识度相关的解释了

  • 資深大佬 : so1n

    @lesismal 感谢你在很忙时详细的回复我的信息,非常抱歉我没有经过详细的思考就做了回复。

    大概懂了你的意思。不过我一般考虑到资源隔离,以及协程的资源占用不高,3 都是开个协程来处理

  • 主 資深大佬 : lesismal

    @lesismal 描述清楚了就好回答了,文字沟通不方便,如果是面对面沟通可能早就讲清楚了

  • 主 資深大佬 : lesismal

    @kevinwan @DoctorCat ARPC 也实现了个编码中间件的扩展示例,把 opentracing 的支持加上了,例子:

    https://github.com/lesismal/arpc/tree/master/examples/middleware/coder/tracing

  • 主 資深大佬 : lesismal

    @lesismal 参考自:

    https://github.com/opentracing/basictracer-go/blob/8e39e894ba59569ffb0b13167ebbe64b0b142e94/examples/dapperish.go

  • 資深大佬 : kevinwan

    @lesismal 赞!

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具