高手过招:用SQL解决环环相扣的刑侦推理问题(苏旭辉版本)-阿里云开发者社区

开发者社区> 技术小能手> 正文

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

简介:
+关注继续查看

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

本文作者:宗羽

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
iBatis解决自动防止sql注入
#xxx# 代表xxx是属性值,map里面的key或者是你的pojo对象里面的属性, ibatis会自动在它的外面加上引号,表现在sql语句是这样的where xxx = 'xxx' ; ...
770 0
VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结
Background MSDN中对于在不同的配置下Link的LIB作了说明: C Runtime Library: 开关 对应的库 版本 /MD MSVCRT.
918 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4523 0
成功解决连接SQL输出出现中文乱码问题(10001, 'oracle¿ìËÙÈëÃÅ', 'Íõº£ÁÁ', 'Ë®Àû³ö°æÉç',
成功解决连接SQL输出出现中文乱码问题(10001, 'oracle¿ìËÙÈëÃÅ', 'Íõº£ÁÁ', 'Ë®Àû³ö°æÉç',
7 0
Mac mysql 解决中文乱码
Mac mysql 解决中文乱码问题 出现“???”之类的无法识别的乱码 到/etc目录下自己建一个my.cnf文件(需要最高权限,使用sudo su),然后写入内容: [client] default-character-set=utf8 [mysqld] character-set-server=utf8 保存,修改。
950 0
mysql 5.7版本安装问题
2013年10月,MySQL开发团队正式宣布支持Yum仓库,这就意味着我们现在可以从这个Yum库中获得最新和最优版的MySQL安装包。本文将在一台全新安装的CentOS6上安装MySQL5.6,如果你不熟悉MySQL5.6的新特性,我建议从MySQL 5.6的新特性开始,其中有很多非常有用的特性。 首先我们需要从MySQ
1524 0
+关注
技术小能手
云栖运营小编~
5962
文章
9
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载