高手过招:用SQL解决环环相扣的刑侦推理问题(苏旭辉版本)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

SOFARPC 是近期蚂蚁金服开源的一个高可扩展性、高性能、生产级的 Java RPC 框架。在蚂蚁金服 SOFARPC 已经经历了十多年及五代版本的发展。SOFARPC 致力于简化应用之间的 RPC 调用,为应用提供方便透明、稳定高效的点对点远程服务调用方案。为了用户和开发者方便的进行功能扩展,SOFARPC 提供了丰富的模型抽象和可扩展接口,包括过滤器、路由、负载均衡等等。

伴随 SOFARPC 的开源,我们也开源了 sofa-bolt-node 和 sofa-rpc-node 两个 Nodejs RPC 基础模块。但细心的用户可能注意了我们在文档里面写到并不希望大家直接使用它们,并预告会在 Eggjs 里提供 RPC 最佳实践。

现在这个最佳实践来了,它就是:

egg-sofa-rpc 插件

https://github.com/eggjs/egg-sofa-rpc

egg-rpc-generator 工具

https://github.com/eggjs/egg-rpc-generator

本文通过 Step by Step 的形式介绍了 Eggjs 和 SOFA(Java)是如何进行互联互通的,涵盖了 RPC 的服务发现、接口定义、本地代理生成、服务端实现等各方面,期望展现给你一个相对完整的 Nodejs RPC 解决方案。考虑到社区的接受度、多语言友好性等因素,接下来的示例采用 protobuf 作为 RPC 的序列化方式。

准备工作

注意: 本文以 macOS 为例,其他操作系统的安装、使用方法请自行 google。

d47e62d2b349aca45e42305ed6714efbe5ed61d9安装 nodejs >= 8.0.0

    • 下载安装包:

        https://nodejs.org/en/download/

    • 执行安装

d47e62d2b349aca45e42305ed6714efbe5ed61d9安装 zookeeper

 

$ brew install zookeeper

d47e62d2b349aca45e42305ed6714efbe5ed61d9启动 zookeeper 服务

 

$ zkServer startZooKeeper JMX enabled by defaultUsing config: /usr/local/etc/zookeeper/zoo.cfgStarting zookeeper ... STARTED

d47e62d2b349aca45e42305ed6714efbe5ed61d9克隆 SOFARPC Java 的示例仓库

SOFARPC 的更多信息可以参考官方文档

 

git clone git@github.com:gxcsoccer/sofa-rpc-java-demo.git

d47e62d2b349aca45e42305ed6714efbe5ed61d9安装 egg-init

 

$ npm i egg-init -g

创建工程

d47e62d2b349aca45e42305ed6714efbe5ed61d9通过 egg-init 初始化项目脚手架,选择 simple 模板,接下来根据实际情况填写必要信息

 

$ egg-init? Please select a boilerplate type (Use arrow keys)  ────────────── simple - Simple egg app boilerplate  ts - Simple egg && typescript app boilerplate  empty - Empty egg app boilerplate  plugin - egg plugin boilerplate  framework - egg framework boilerplate

d47e62d2b349aca45e42305ed6714efbe5ed61d9进入生成好的项目目录,并安装依赖

 

$ cd /rpc-demo$ npm i

d47e62d2b349aca45e42305ed6714efbe5ed61d9安装 egg-sofa-rpc 插件和 egg-rpc-generator 工具

 

$ npm i egg-sofa-rpc --save$ npm i egg-rpc-generator --save-dev

d47e62d2b349aca45e42305ed6714efbe5ed61d9配置 package.json 的 scripts 节点,增加一个命令 rpc 如下

 

{  "scripts": {    "start": "egg-scripts start --daemon --title=egg-server-rpc-demo",    "stop": "egg-scripts stop --title=egg-server-rpc-demo",    "dev": "egg-bin dev",    "debug": "egg-bin debug",    "test": "npm run lint -- --fix && npm run test-local",    "test-local": "egg-bin test",    "cov": "egg-bin cov",    "lint": "eslint .",    "ci": "npm run lint && npm run cov",    "autod": "autod",    "rpc": "egg-rpc-generator"  }
}

d47e62d2b349aca45e42305ed6714efbe5ed61d9配置 config/plugin.js 开启 egg-sofa-rpc 插件

 

// config/plugin.js

exports.sofaRpc = {  enable: true,  package: 'egg-sofa-rpc'
};

定义接口

protobuf 有自己的接口定义语言,详细可以参考官方文档

 

# ProtoService.proto syntax = "proto3";package com.alipay.sofa.rpc.protobuf;option java_multiple_files = true; // 可选option java_outer_classname = "ProtoServiceModels"; // 可选service ProtoService {    rpc echoObj (EchoRequest) returns (EchoResponse) {}}message EchoRequest {    string name = 1;    Group group = 2;}message EchoResponse {    int32 code = 1;    string message = 2;}enum Group {    A = 0;    B = 1;}

上面这个 ProtoService.proto 文件定义了一个服务:com.alipay.sofa.rpc.protobuf.ProtoService,它有一个叫 echoObj 的方法,入口参数类型是 EchoRequest,返回值类型是 EchoResponse

调用Java暴露的RPC服务

1、启动 Java 服务端

进入上面克隆的 Java 示例仓库,运行 ProtobufServiceServerMain

2、配置服务发现参数

我们默认的服务发现依赖于 zookeeper,所以需要配置一个 zk 的地址。在 config/config.{env}.js 中配置如下:

 

// config/config.default.js
'use strict';

exports.sofaRpc = {  registry: {    address: '127.0.0.1:2181', // zk 地址指向本地 2181 端口  }
};

3、获取接口定义

在 egg 项目根目录下创建 proto 目录,然后将上面定义的 ProtoService.proto 文件放到里

 

.├── app│   ├── controller│   │   └── home.js│   └── router.js├── config│   ├── config.default.js│   └── plugin.js├── package.json└── proto    └── ProtoService.proto

4、配置要调用的接口

在 config/proxy.js 中配置要调用的服务信息

 

'use strict';

module.exports = {  services: [{    appName: 'sofarpc',    api: {      ProtoService: 'com.alipay.sofa.rpc.protobuf.ProtoService',    }  }]
};

d47e62d2b349aca45e42305ed6714efbe5ed61d9appName(必选): 服务提供方的应用名,如果没有可以任意起一个
d47e62d2b349aca45e42305ed6714efbe5ed61d9api(必选): 接口列表,是一个 key-value 键值对,key 是生成的 proxy 文件名,value 是接口名(如果要跟精细的配置也可以是一个对象)

config/proxy.js 详细的配置说明可以参考文档

5、生成调用代理

在根目录下运行 npm run rpc,生成调用的 proxy 文件

 

$ npm run rpc
> rpc-demo@1.0.0 rpc /egg-rpc-demo
> egg-rpc-generator

[EggRpcGenerator] framework: /egg-rpc-demo/node_modules/egg, baseDir: /egg-rpc-demo
[ProtoRPCPlugin] found "com.alipay.sofa.rpc.protobuf.ProtoService" in proto file
[ProtoRPCPlugin] save all proto info into "/egg-rpc-demo/run/proto.json"

运行成功以后,会发现生成了两个文件

d47e62d2b349aca45e42305ed6714efbe5ed61d9app/proxy/ProtoService.js - 调用服务的代理文件
d47e62d2b349aca45e42305ed6714efbe5ed61d9run/proto.json - 从 .proto 文件中导出的接口信息,是一个 json 格式文件

 

├── app│   ├── controller│   │   └── home.js│   ├── proxy│   │   └── ProtoService.js│   └── router.js├── config│   ├── config.default.js│   ├── plugin.js│   └── proxy.js├── package.json├── proto│   └── ProtoService.proto└── run    └── proto.json

生成的 app/proxy/ProtoService.js 文件内容如下(注意:不要手动去改这个文件):

 

// Don't modified this file, it's auto created by egg-rpc-generator

'use strict';

const path = require('path');

/* eslint-disable */
/* istanbul ignore next */
module.exports = app => {  const consumer = app.sofaRpcClient.createConsumer({    interfaceName: 'com.alipay.sofa.rpc.protobuf.ProtoService',    targetAppName: 'sofarpc',    version: '1.0',    group: 'SOFA',    proxyName: 'ProtoService',    responseTimeout: 3000,  });  if (!consumer) {    // `app.config['sofarpc.rpc.service.enable'] = false` will disable this consumer    return;  }  app.beforeStart(async() => {    await consumer.ready();  });  class ProtoService extends app.Proxy {    constructor(ctx) {      super(ctx, consumer);    }    async echoObj(req) {      return await consumer.invoke('echoObj', [ req ], {         ctx: this.ctx,codecType: 'protobuf',      });    }  }  return ProtoService;
};
/* eslint-enable */

6、调用代理类,实现业务逻辑

上面定义的这个 ProtoService 这个类,会挂载在 app.proxyClasses 上。通过 ctx.proxy.protoService(注意这里是小驼峰)可以访问它的实例,这样我们就可以在业务中调用 RPC 的服务了,例如:下面我们在 home controller 调用 ProtoService 的 echoObj 方法

 

// app/controller/home.js

'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {  async index() {    const { ctx } = this;    const res = await ctx.proxy.protoService.echoObj({      name: 'gxcsoccer',  group: 'A',    });    ctx.body = res;  }
}

module.exports = HomeController;

7、启动应用,调试

 

$ npm run dev

在浏览器中访问 http://127.0.0.1:7001/,得到下面的结果,说明成功了

a1dbef727dba143dfa4c7f467413c9946aee91fe

暴露RPC服务给Java调用

_____

这回换做 Nodejs 来暴露同样的服务,Java 端作为消费者

1、配置服务发现参数

和上面作为调用者的配置一样

 

// config/config.default.js

'use strict';

exports.sofaRpc = {  registry: {    address: '127.0.0.1:2181', // zk 地址指向本地 2181 端口  }
};

2、定义接口

同样需要先定义接口,然后将 .proto 文件放到 proto 目录下,然后运行 npm run rpc,这些和上面作为调用者时都一样

3、配置 RPC 服务端的参数

通过 config/config.{env}.js 配置 RPC 服务端的参数

 

// config/config.default.js

'use strict';

exports.sofaRpc = {  server: {    namespace: 'com.alipay.sofa.rpc.protobuf'  }
};

其中最主要的配置就是 namespace,其他配置都可以缺省:

d47e62d2b349aca45e42305ed6714efbe5ed61d9namespace(必选): 接口的命名空间,所有的暴露的接口默认都在该命名空间下
d47e62d2b349aca45e42305ed6714efbe5ed61d9selfPublish(可选): 是否每个 worker 进程独立暴露服务。nodejs 多进程模式下,如果多个进程共享一个端口,在 RPC 这种场景可能造成负载不均,所以 selfPublish 默认为 true,代表每个进程独立监听端口和发布服务
d47e62d2b349aca45e42305ed6714efbe5ed61d9port(可选): 服务监听的端口(注意:在 selfPublish=true 时,监听的端口是基于这个配置生成的)
d47e62d2b349aca45e42305ed6714efbe5ed61d9maxIdleTime(可选): 客户端连接如果在该配置时长内没有任何流量,则主动断开连接
d47e62d2b349aca45e42305ed6714efbe5ed61d9responseTimeout(可选): 服务端建议的超时时长,具体的超时还是以客户端配置为准
d47e62d2b349aca45e42305ed6714efbe5ed61d9codecType(可选): 推荐的序列化方式,默认为 protobuf

4、实现接口逻辑

在 app/rpc 目录下创建 ProtoService.js 文件,用于实现接口逻辑

 

'use strict';

exports.echoObj = async function(req) {  return {    code: 200,    message: 'hello ' + req.name + ', you are in ' + req.group,  };
};

5、启动应用,发布服务

 

$ npm run dev

6、Java 作为客户端调用服务

进入上面克隆的 Java 示例仓库,运行 ProtobufServiceClientMain

执行的结果如下:

 

Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc Log4j2 ]



原文发布时间为:2018-06-21

本文作者:宗羽

本文来自云栖社区合作伙伴“中生代技术”,了解相关信息可以关注“中生代技术”。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
3月前
|
SQL 流计算
Flink CDC 1.12版本引入了对SQL Server的支持
【1月更文挑战第26天】【1月更文挑战第124篇】Flink CDC 1.12版本引入了对SQL Server的支持
33 1
|
3月前
|
SQL 安全 大数据
SQL Server主流版本生命周期管理
SQL Server主流版本提供至少10年的支持周期,包括5年主要支持期(含功能更新、性能改进等)和5年扩展支持期(仅限安全更新),直至终止支持为止。
53 0
|
3月前
|
SQL Shell 数据库
无人参与安装最新版本SQL Server Management Studio (SSMS)
通过power shell完成SSMS的自动安装,给大家争取打水的时间,离开位置走走,活动活动筋骨。
34 0
|
4月前
|
SQL JSON 关系型数据库
【SQL编程】MySQL 5.7.28 版本使用 SQL 直接解析 JSON 字符串(判断是否是合法JSON类型+文本深度+文本长度+值类型+keys获取+值获取+不同深度数据获取)
【SQL编程】MySQL 5.7.28 版本使用 SQL 直接解析 JSON 字符串(判断是否是合法JSON类型+文本深度+文本长度+值类型+keys获取+值获取+不同深度数据获取)
50 0
|
11月前
|
SQL 存储 大数据
SQL Server 跨版本数据迁移实践
SQL Server 的导入和导出向导是一个非常有用的工具,可以帮助用户快速导入和导出数据,而无需编写复杂的 SQL 查询或程序代码。使用导入和导出向导,用户可以选择数据源、目标数据、映射源和目标列、指定导入或导出选项以及完成导入或导出操作,整个使用体验也非常简单便捷。
231 0
|
10月前
|
SQL Oracle NoSQL
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
1050 1
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
|
11月前
|
SQL 安全 关系型数据库
SQL注入 安全狗apache3.5.12048版本绕过(下)
SQL注入 安全狗apache3.5.12048版本绕过
130 0
|
11月前
|
SQL 安全 关系型数据库
SQL注入 安全狗apache3.5.12048版本绕过(上)
SQL注入 安全狗apache3.5.12048版本绕过
93 0
|
SQL 关系型数据库 Linux
知识分享之PostgreSQL——OIDS的特性与新版本去除SQL
之前一直使用的PostgreSQL 9.6系列版本,由于官方不再维护了,就准备换成最新稳定版本的,查看了一下官方版本说明,发现13系列版本是目前稳定性较好的版本,于是兴冲冲的更换了过来,但随之而来的就是一些新特性,其中就比如表中的OID字段,这个字段是对象标识符,之前能用于行标记,现在发现只有表才具有这个隐藏字段,行数据没有这个支持了,于是就需要将老版本的表进行关闭掉这个字段。下面我们就开始关闭之旅。
131 0
知识分享之PostgreSQL——OIDS的特性与新版本去除SQL
|
SQL 关系型数据库 MySQL
SQL追踪器phpgjx2.0版本配置(二)
SQL追踪器phpgjx2.0版本配置(二)
117 0
SQL追踪器phpgjx2.0版本配置(二)