spark rpc 简单示例

本文介绍了SparkRPC的简单使用示例,包括如何创建Hello服务的Endpoint,如何通过RpcEnv管理服务生命周期,以及客户端如何异步调用服务。SparkRPC通过模式匹配实现方法路由,无需传统RPC的接口定义,简化了内部组件通信。同时,它利用Netty处理网络通信,提供序列化、重试等机制,提高了易用性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spark rpc 简单示例

假设我们要开发一个Hello服务,客户端可以传输string,服务端响应hi或者bye,并echo回去输入的string。

第一步,定义一个HelloEndpoint继承自RpcEndpoint表明可以并发的调用该服务,如果继承自ThreadSafeRpcEndpoint则表明该Endpoint不允许并发。

class HelloEndpoint(override val rpcEnv: RpcEnv) extends RpcEndpoint {
  override def onStart(): Unit = {
    println("start hello endpoint")
  }

  override def receiveAndReply(context: RpcCallContext): PartialFunction[Any, Unit] = {
    case SayHi(msg) => {
      println(s"receive $msg")
      context.reply(s"hi, $msg")
    }
    case SayBye(msg) => {
      println(s"receive $msg")
      context.reply(s"bye, $msg")
    }
  }

  override def onStop(): Unit = {
    println("stop hello endpoint")
  }
}

case class SayHi(msg: String)
case class SayBye(msg: String)

和Java传统的RPC解决方案对比,可以看出这里不用定义接口或者方法标示(比如通常的id或者name),使用scala的模式匹配进行方法的路由。虽然点对点通信的契约交换受制于语言,这里就是SayHi和SayBye两个case class,但是Spark RPC定位于内部组件通信,所以无伤大雅。

第二步,把刚刚开发好的Endpoint交给Spark RPC管理其生命周期,用于响应外部请求。RpcEnvServerConfig可以定义一些参数、server名称(仅仅是一个标识)、bind地址和端口。通过NettyRpcEnvFactory这个工厂方法,生成RpcEnv,RpcEnv是整个Spark RPC的核心所在,后文会详细展开,通过setupEndpoint将"hello-service"这个名字和第一步定义的Endpoint绑定,后续client调用路由到这个Endpoint就需要"hello-service"这个名字。调用awaitTermination来阻塞服务端监听请求并且处理。

val config = RpcEnvServerConfig(new RpcConf(), "hello-server", "localhost", 52345)
val rpcEnv: RpcEnv = NettyRpcEnvFactory.create(config)
val helloEndpoint: RpcEndpoint = new HelloEndpoint(rpcEnv)
rpcEnv.setupEndpoint("hello-service", helloEndpoint)
rpcEnv.awaitTermination()

第三步,开发一个client调用刚刚启动的server,首先RpcEnvClientConfig和RpcEnv都是必须的,然后通过刚刚提到的"hello-service"名字新建一个远程Endpoint的引用(Ref),可以看做是stub,用于调用,这里首先展示通过异步的方式来做请求。

val rpcConf = new RpcConf()
val config = RpcEnvClientConfig(rpcConf, "hello-client")
val rpcEnv: RpcEnv = NettyRpcEnvFactory.create(config)
val endPointRef: RpcEndpointRef = rpcEnv.setupEndpointRef(RpcAddress("localhost", 52345), "hell-service")
val future: Future[String] = endPointRef.ask[String](SayHi("neo"))
future.onComplete {
    case scala.util.Success(value) => println(s"Got the result = $value")
    case scala.util.Failure(e) => println(s"Got error: $e")
}
Await.result(future, Duration.apply("30s"))

这就是Spark RPC的通信过程,使用起来易用性可想而知,非常简单,RPC框架屏蔽了Socket I/O模型、线程模型、序列化/反序列化过程、使用netty做了包识别,长连接,网络重连重试等机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值