gRPC Streaming的操作对象由服务端和客户端组成。在一个包含了多个不同服务的集群环境中可能需要从一个服务里调用另一个服务端提供的服务。这时调用服务端又成为了提供服务端的客户端了(服务消费端)。那么如果我们用streaming形式来提交服务需求及获取计算结果就是以一个服务端为Source另一个服务端为通过式passthrough Flow的stream运算了。讲详细点就是请求方用需求构建Source,以连接Flow的方式把需求传递给服务提供方。服务提供方在Flow内部对需求进行处理后再把结果返回来,请求方run这个连接的stream应该就可以得到需要的结果了。下面我们就针对以上场景在一个由JDBC,Cassandra,MongoDB几种gRPC服务组成的集群环境里示范在这几个服务之间的stream连接和运算。

首先,我们设计一个简单但比较有代表性的例子:从JDBC的客户端传一个字符型消息hello给JDBC服务端、JDBC服务端在hello后面添加“,from jdbc to cassandra”然后通过Cassandra客户端把消息当作请求传给Cassandra服务端、Cassandra服务端在消息后面再加上“,from cassandra to mongo”并通过MongoDB客户端把消息传给MongoDB服务端、最后MongoDB服务端在消息后面添加“,mongo says hi”。整个stream的形状是 jdbc-client->jdbc-service->cassandra-service-mongodb-service。如果run这个stream得到的结果应该是一个描述完整移动路径的消息。从请求-服务角度来描述:我们可以把每个节点消息更新处理当作某种完整的数据处理过程。

以下分别是JDBC,Cassandra,MongoDB gRPC IDL定义:

service JDBCServices {
rpc greeting(stream HelloMsg) returns (stream HelloMsg) {}
} service CQLServices {
rpc greeting(stream HelloMsg) returns (stream HelloMsg) {}
} service MGOServices {
rpc greeting(stream HelloMsg) returns (stream HelloMsg) {}
}

三个服务共用了protobuf消息类型HelloMsg。我们把共用的消息统一放到一个common.proto文件里:

syntax = "proto3";

package sdp.grpc.services;

message HelloMsg {
string hello = ;
} message DataRow {
string countyname = ;
string statename = ;
int32 reportyear = ;
int32 value = ;
}

然后在示范应用的.proto文件中用import 把所有protobuf,gRPC服务定义都集中起来:

syntax = "proto3";

import "google/protobuf/wrappers.proto";
import "google/protobuf/any.proto";
import "scalapb/scalapb.proto"; option (scalapb.options) = {
// use a custom Scala package name
// package_name: "io.ontherocks.introgrpc.demo" // don't append file name to package
flat_package: true // generate one Scala file for all messages (services still get their own file)
single_file: true // add imports to generated file
// useful when extending traits or using custom types
// import: "io.ontherocks.hellogrpc.RockingMessage" // code to put at the top of generated file
// works only with `single_file: true`
//preamble: "sealed trait SomeSealedTrait"
}; /*
* Demoes various customization options provided by ScalaPBs.
*/ package sdp.grpc.services; import "misc/sdp.proto";
import "common.proto";
import "cql/cql.proto";
import "jdbc/jdbc.proto";
import "mgo/mgo.proto";

下面我们把最核心的服务实现挑出来讲解一下,先看看Cassandra服务的实现:

import sdp.grpc.mongo.client.MGOClient

class CQLStreamingServices(implicit ec: ExecutionContextExecutor,
mat: ActorMaterializer, session: Session)
extends CqlGrpcAkkaStream.CQLServices with LogSupport{
val mongoClient = new MGOClient
val stub = mongoClient.stub def sayHelloTo(msg: String): Flow[HelloMsg, HelloMsg, NotUsed] =
Flow[HelloMsg].map { r => HelloMsg(r.hello + msg)}
.via(stub.greeting) override def greeting: Flow[HelloMsg, HelloMsg, NotUsed] =
Flow[HelloMsg]
.via(sayHelloTo(",from cassandra to mongo")) }

streaming方式的gRPC服务其实就是一个akka-stream的Flow[R1,R2,M],它把收到的数据R1处理后转换成R2输出。在处理R1的环节里可能会需要其它服务的运算结果。在以上例子里CQLService把收到的消息加工转换后传给MGOService并等待MGOService再深度加工返还的结果,所以sayHelloTo还是一个有两个节点的Flow:在第一个节点中对收到的消息进行加工,第二个节点把加工的消息传给另一个服务并连接它的运算结果作为本身最终的输出。调用其它跨集群节点的服务必须经该服务的gRPC客户端进行,这里调用的MGOClient:

package sdp.grpc.mongo.client

import sdp.grpc.services._
import sdp.logging.LogSupport
import io.grpc._
import common._
import sdp.grpc.services._
import akka.stream.scaladsl._
import akka.NotUsed class MGOClient extends LogSupport { val channel = ManagedChannelBuilder
.forAddress("localhost", )
.usePlaintext()
.build() val stub = MgoGrpcAkkaStream.stub(channel) }

JDBCService连接CQLService, CQLService连接MGOService:

import sdp.grpc.cassandra.client.CQLClient

class JDBCStreamingServices(implicit ec: ExecutionContextExecutor)
extends JdbcGrpcAkkaStream.JDBCServices with LogSupport {
val cassandraClient = new CQLClient
val stub = cassandraClient.stub
def sayHelloTo(msg: String): Flow[HelloMsg,HelloMsg,NotUsed] =
Flow[HelloMsg]
.map {r => HelloMsg(r.hello + msg)}
.via(stub.greeting) override def greeting: Flow[HelloMsg, HelloMsg, NotUsed] =
Flow[HelloMsg]
.via(sayHelloTo(",from jdbc to cassandra")) }

最后我们用DemoApp来示范整个过程:

package demo.sdp.grpc

import akka.actor.ActorSystem
import akka.stream.{ActorMaterializer, ThrottleMode} import sdp.grpc.jdbc.client.JDBCClient object DemoApp extends App {
implicit val system = ActorSystem("jdbcClient")
implicit val mat = ActorMaterializer.create(system)
implicit val ec = system.dispatcher val jdbcClient = new JDBCClient jdbcClient.sayHello.runForeach(r => println(r.hello)) scala.io.StdIn.readLine()
mat.shutdown()
system.terminate() }

DemoApp调用了JDBCClient:

package sdp.grpc.jdbc.client

import sdp.grpc.services._
import sdp.logging.LogSupport
import io.grpc._
import common._
import sdp.grpc.services._
import akka.stream.scaladsl._
import akka.NotUsed class JDBCClient extends LogSupport { val channel = ManagedChannelBuilder
.forAddress("localhost", )
.usePlaintext()
.build() val stub = JdbcGrpcAkkaStream.stub(channel) def sayHello: Source[HelloMsg, NotUsed] = {
val row = HelloMsg("hello ")
val rows = List.fill[HelloMsg]()(row)
Source
.fromIterator(() => rows.iterator)
.via(stub.greeting)
}
}

运行DemoApp显示的结果:

hello ,from jdbc to cassandra,from cassandra to mongo, mongo says hi
hello ,from jdbc to cassandra,from cassandra to mongo, mongo says hi
hello ,from jdbc to cassandra,from cassandra to mongo, mongo says hi
hello ,from jdbc to cassandra,from cassandra to mongo, mongo says hi
hello ,from jdbc to cassandra,from cassandra to mongo, mongo says hi
...

PICE(6):集群环境里多异类端点gRPC Streaming - Heterogeneous multi-endpoints gRPC streaming的更多相关文章

  1. PICE(1):Programming In Clustered Environment - 集群环境内编程模式

    首先声明:标题上的所谓编程模式是我个人考虑在集群环境下跨节点(jvm)的流程控制编程模式,纯粹按实际需要构想,没什么理论支持.在5月份的深圳scala meetup上我分享了有关集群环境下的编程模式思 ...

  2. elasticsearch与mongodb分布式集群环境下数据同步

    1.ElasticSearch是什么 ElasticSearch 是一个基于Lucene构建的开源.分布式,RESTful搜索引擎.它的服务是为具有数据库和Web前端的应用程序提供附加的组件(即可搜索 ...

  3. Oracle rac集群环境中的特殊问题

    备注:本文摘抄于张晓明<大话Oracle RAC:集群 高可用性 备份与恢复> 因为集群环境需要多个计算机协同工作,要达到理想状态,必须要考虑在集群环境下面临的新挑战. 1.并发控制 在集 ...

  4. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.3配置共享磁盘

    2.3.配置共享磁盘 2.3.1.创建共享磁盘 在cmd中进入WMware Workstation 10.0 安装目录: 1.创建存储Oracle Clusterware文件  (Oracle Clu ...

  5. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:4.安装Oracle RAC FAQ-4.4.无法图形化安装Grid Infrastructure

    无法图形化安装: [grid@linuxrac1 grid]$ ./runInstaller Starting Oracle Universal Installer... Checking Temp ...

  6. (2)虚拟机下hadoop1.1.2集群环境搭建

    hadoop集群环境的搭建和单机版的搭建差点儿相同,就是多了一些文件的配置操作. 一.3台主机的hostname改动和IP地址绑定 注意:以下的操作我都是使用root权限进行! (1)3太主机的基本网 ...

  7. Hadoop化繁为简-从安装Linux到搭建集群环境

    简介与环境准备 hadoop的核心是分布式文件系统HDFS以及批处理计算MapReduce.近年,随着大数据.云计算.物联网的兴起,也极大的吸引了我的兴趣,看了网上很多文章,感觉还是云里雾里,很多不必 ...

  8. 在 WebSphere Application Server V7 集群环境中管理 HTTP session[阅读]

    http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1012_dingsj_wascluster/1012_ding ...

  9. Hadoop集群环境安装

    转载请标明出处:  http://blog.csdn.net/zwto1/article/details/45647643:  本文出自:[zhang_way的博客专栏] 工具: 虚拟机virtual ...

随机推荐

  1. SpringMvc 使用Thumbnails压缩图片

    ```java @PostMapping(value = "/upLoadFile") @ApiOperation(value = "上传文件") public ...

  2. 使用jQuery+huandlebars防止编码注入攻击

    兼容ie8(很实用,复制过来,仅供技术参考,更详细内容请看源地址:http://www.cnblogs.com/iyangyuan/archive/2013/12/12/3471227.html) & ...

  3. 虚拟网络VDC与VPC

    当前互联网行业,内部 IT 基础资源云端化是主要趋势.云平台将资源管理抽象出来,比如云主机.云 DB 等,以服务的方式提供给用户,按需使用,从而带来更大的灵活性与经济性. 随着主机.DB.缓存.存储等 ...

  4. “AS3.0高级动画编程”学习:第三章等角投影(上)

    什么是等角投影(isometric)? 原作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com 刚接触这个概念时,我也很茫然,百度+google了N天后,找到了一些文章: [转 ...

  5. poj2115(扩展欧基里德定理)

    题目链接:https://vjudge.net/problem/POJ-2115 题意:模拟for循环for(int i=A;i!=B;i+=C),且数据范围为k位无符号数以内,即0~1<< ...

  6. Win7上安装scapy

    1.环境 操作环境:win7 python版本:python3.5 依赖模块:Npcap(推荐)或WinPcap 下载scapy 2.安装步骤 操作环境,python及依赖模块安装省略(一直点击下一步 ...

  7. AltiumDesigner PCB导入CAD

    点击File菜单下的New的PCB,新建PCB文件. 在AD09中点击File菜单下的Import,导入CAD文件 选择要导入的CAD文件,点击打开. 选择单位mm,这里的单位选择要与CAD单位一致, ...

  8. Eclipse 创建Android 模拟器失败:no cpu/abi system image available for this target

    (从网上搜了一个使用Android 4.4 API 20编译的图片) 这是因为SDK中没有模拟器使用的操作系统镜像. 如果项目使用API 19编译,则SDK中的system-images文件夹下,需要 ...

  9. 65. Valid Number 判断字符串是不是数字

    [抄题]: Validate if a given string is numeric. Some examples:"0" => true" 0.1 " ...

  10. RIDE 接口自动化请求体参数中文时报错:“UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 9......”

    在进行robotframework  接口自动化,在请求体参数中输入中文会报以下错误: UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 ...