帮酷LOGO
  • 显示原文与译文双语对照的内容
文章标签:RPC  LANG  ERL  Scalable  BASE  LAN  Erlang  SCA  
An Erlang RPC library for out-of-band messaging

  • 源代码名称:gen_rpc
  • 源代码网址:http://www.github.com/priestjim/gen_rpc
  • gen_rpc源代码文档
  • gen_rpc源代码下载
  • Git URL:
    git://www.github.com/priestjim/gen_rpc.git
  • Git Clone代码到本地:
    git clone http://www.github.com/priestjim/gen_rpc
  • Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/priestjim/gen_rpc
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
  • :基于虚拟机的可以扩展RPC库。

    概述

    • 最新版本:Tag Version
    • 分支状态( master ): Build StatusCoverage Status
    • 分支状态( develop ): Build StatusCoverage Status
    • 问题:GitHub issues
    • 许可证:GitHub license
    • 工厂 2016 Talk 。

    构建依赖项

    要生成这里项目,你需要具备以下条件:

    • /otp> = 19.1

    • > = 1.7

    • GNU Make> = 3.80

    • rebar3> = 3.2

    用法

    gen_rpc 入门很简单。 首先,将适当的依赖项添加到你的rebar.config:

    {deps, [
     {gen_rpc, {git, "https://github.com/priestjim/gen_rpc.git", {branch, "master"}}}
    ]}.

    或者,如果你使用的是 hex.pm/rebar3:

    {deps [
     {gen_rpc, "~> 2.0"}
    ]}.

    或者,如果你使用的是 elixir/mix:

    defprojectdo [
     deps: [
     {:gen_rpc, "~> 2.0"}
     ]
     ]

    然后,将 gen_rpc 作为依赖项应用程序添加到 .app.src/.app file:

    {application, my_app, [
     {applications, [kernel, stdlib, gen_rpc]}
    ]}

    或者你的mix.exs file:

    defapplicationdoapplications: [:gen_rpc]end

    最后,启动几个节点来测试它:

    (my_app@127.0.0.1)1>gen_rpc:call('other_node@1.2.3.4', erlang, node, []).'other_node@1.2.3.4'

    API

    gen_rpc 只实现 rpc 库功能的子集,这对它所要解决的问题有意义。 库接口和返回值的函数为 100%,与 rpc 兼容,只有一个添加: 错误返回值包括基于rpc的错误的{badrpc, Error},也包括基于tcp的错误的{badtcp, Error}

    有关以下功能的更多信息,请运行 erl -man rpc

    函数导出

    • call(NodeOrNodeAndKey, Module, Function, Args)call(NodeOrNodeAndKey, Module, Function, Args, Timeout)gen_server 时尚中的阻塞同步调用。

    • cast(NodeOrNodeAndKey, Module, Function, Args) :非阻塞fire-and-forget调用。

    • async_call(NodeOrNodeAndKey, Module, Function, Args)yield(Key)nb_yield(Key)nb_yield(Key, Timeout): 提供基于 async_call的调用,并在需要 yield 或者 nb_yield 时异步检索结果,并将它的异步检索。

    • multicall(Module, Function, Args)multicall(Nodes, Module, Function, Args) , multicall(Module, Function, Args, Timeout)multicall(NodesOrNodesWithKeys, Module, Function, Args, Timeout)call 函数的多节点版本。

    • abcast(NodesOrNodesWithKeys, Name, Msg)abcast(Name, Msg): 异步广播函数,将消息 Msg 发送到 NodesOrNodesWithKeys 中所有节点的命名进程 Name

    • sbcast(NodesOrNodesWithKeys, Name, Msg)sbcast(Name, Msg): 同步广播函数,将消息 Msg 发送到 NodesOrNodesWithKeys 中所有节点的命名进程 Name 。 返回指定进程处于活动状态的节点及其不在其中的节点。

    • eval_everywhere(Module, Function, Args)eval_everywhere(NodesOrNodesWithKeys, Module, Function, Args)cast 函数的多节点版本。

    每个密钥分片的

    使用任意类型的键,gen_rpc 支持每个 node的多个传出连接,以区分连接。 要利用这里功能,请用 {Node, Key} 替换你的调用( 单节点和节点 alike ) 中的Node 。 使用 erlang:phash2/1 散列 Key,附加到客户机进程 NAME,并启动一个新连接。

    注意:当使用调用 gen_rpc:nodes/0 隐式( 如 gen_rpc:multicall/3 )的函数时,用于与节点通信的通道是无键的无键的。 要利用切分功能,先创建 {Node, Key} 列表,然后在多节点函数中将它们作为 node 列表传递。

    MODULE 版本控制

    gen_rpc 支持在仅运行特定 MODULE 版本的远程节点上执行RPC调用。 为了利用该特性,在上面的部分中代替 Module,使用 {Module, Version} 。 如果远程 Module 不在请求的版本上,则返回 {badrpc,incompatible]

    应用程序设置

    • tcp_server_port: 普通TCP端口 gen_rpc 将用于传入连接或者 false,如果你不希望启用普通 TCP,则。

    • tcp_client_port: 普通TCP端口 gen_rpc 将用于传出连接。

    • ssl_server_port: 如果你不希望启用 SSL,端口 gen_rpc 将用于传入的SSL连接或者 false

    • ssl_client_port: 端口 gen_rpc 将用于传出SSL连接。

    • ssl_server_optionsssl_client_options: gen_rpc 用于连接到远程 gen_rpc 服务器的ssl 接口的设置。

    • default_client_driver: 默认驱动程序 gen_rpc 将用于连接到远程 gen_rpc 节点。 它应该是 tcp 或者 ssl

    • client_config_per_node: 一张地图 Node => {Driver, Port} 或者 Node => Port,指示 Port 和/或者 Driver 在连接到 Node 时使用的gen_rpc 。 如果使用外部发现服务映射 Nodes{Driver, Port} 元组,则需要使用作为单个参数,使用作为单个参数,使用外部发现服务并返回 {Driver, Port} 元组。

    • 将这些模块设置为,定义不会暴露到 gen_rpc 或者 whitelist的模块列表,以定义将公开到 gen_rpc的模块列表。 将它的设置为 disabled 以禁用这里功能。

    • rpc_module_list: 将被列入黑名单或者白名单的模块列表。

    • authentication_timeout: 传入连接的身份验证状态的默认超时时间为毫秒。 用于在DoS攻击中防止半开放连接。

    • connect_timeout: 初始node-to-node连接的默认超时时间为毫秒。

    • send_timeout: 将请求( call/cast 等等 ) 从本地 node 传输到远程 node的默认超时,以毫秒为单位。

    • call_receive_timeout: 接收响应的默认超时,以毫秒为单位,以毫秒为单位。

    • sbcast_receive_timeout: 接收响应的默认超时,以毫秒为单位,以毫秒为单位。

    • client_inactivity_timeout: 活动时间为毫秒,之后将关闭与的客户端连接,以关闭( 因此,已经释放了TCP文件描述符) 。

    • server_inactivity_timeout: Inactivity毫秒 in 毫秒服务器端口将关闭后的milliseconds 。

    • async_call_inactivity_timeout: 活动时间为毫秒等待等待的进程持有 async_call 返回值的等待过程。 这是用于过程卫生的目的,所以请确保在一个足够高的( 或者 infinity ) 中设置它。

    • socket_keepalive_idle: 发送最后一个数据包后的秒闲置,开始发送用户定义的探测器( 。适用于两个驱动程序) 。

    • socket_keepalive_interval: keepalive探测之间的秒数。

    • socket_keepalive_count: Probs丢失,无法考虑关闭套接字

    日志记录

    gen_rpc 使用小屋 。 这样开发人员就可以在他们的rebar.config 中提供适当的定义,从而集成他们选择的日志库。 hut的默认日志记录工具是 SASL 。

    有关如何使 gen_rpc 使用你自己的日志记录工具的更多信息,请参考 hutREADME.md

    SSL配置

    gen_rpc 支持内部节点通信的SSL 。 这允许在不安全的通道如因特网上进行安全通信和执行,实际上允许在全球分布式的erlang/tcm 设置中进行。 gen_rpc 对SSL应该如何配置非常固执,捆绑的缺省选项包括:

    • 正确的pfs密码套件

    • 基于服务器和客户端的SSL node ( 公用名称) 验证

    • 安全重新协商

    • TLS 1.1/1.2 实施

    所有这些设置都可以在 include/ssl.hrl 中找到,并通过在 ssl_client_optionsssl_server_options 中重新定义必要的选项来覆盖。 要实际使用SSL支持,你需要在 ssl_client_optionsssl_server_options 中定义:

    • public 和 private 键,用于运行 gen_rpc的node,使用常规的certfilekeyfile 选项。

    • 在文件 cacertfile 点中,标签了 node的键和 gen_rpc 应该信任的public 键的in的public 键。

    • 可以选择使用 dhfile 选项的diffie hellman参数文件。

    为了生成自己的自签名CA和 node 证书,可以在网上找到许多文章,如

    通常,对客户端和服务器SSL证书进行签名的CA将相同,因此,包含对 gen_rpc的SSL支持的名义 sys.confg 将如下所示:

     {gen_rpc, [
     {ssl_client_options, [
     {certfile, "priv/cert.pem"},
     {keyfile, "priv/cert.key"},
     {cacertfile, "priv/ca.pem"},
     {dhfile, "priv/dhparam.pem"}
     ]},
     {ssl_server_options, [
     {certfile, "priv/cert.pem"},
     {keyfile, "priv/cert.key"},
     {cacertfile, "priv/ca.pem"},
     {dhfile, "priv/dhparam.pem"}
     ]}
     ]}

    对于多站点部署,可以以使用internet上的边缘 gen_rpc 节点和内部数据交换的SSL来配置性能优化的设置。 这种情况下,非边缘节点可以有 {ssl_server_port, false}{default_client_driver, tcp} 节点,边缘节点可以在外部和外部设置firewalled端口。

    外部源支持

    如果你想使用外部发现服务( 如 etcd ) 进行 node 配置管理,gen_rpc 可以调用外部 MODULE 来提供驱动程序/端口映射。 MODULE 应该实现 gen_rpc_external_source 行为,以 Node 作为参数,应该返回 {Driver, Port} ( Drivertcp 或者 sslPort 是远程 gen_rpc的node 驱动程序正在侦听的端口) 或者 {error, Reason} ( 如果服务不可用) 。 要设置它,将 client_config_per_node{internal, #{}}的默认值改为 {external, ModuleName},其中 ModuleName 是实现 gen_rpc_external_source 行为的MODULE 。

    生成目标

    gen_rpc 提供了一个使开发变得简单的Makefile

    要生成 gen_rpc,只需运行:

    make

    要运行完整的测试套件,运行:

    make test

    要运行完整的测试套件,外部参照工具和透析器,运行:

    make dist

    要在开发过程中生成项目并在控制台中放置,请运行:

    make shell-master

    或者

    make shell-slave

    如果你想运行"母版"和"从" gen_rpc 节点来运行测试。

    要清理每个生成构件和日志,运行:

    make distclean

    测试

    已经为 gen_rpc 实现了完整的测试套件。 你可以通过以下方式运行基于ct的测试套件,过滤器和外部参照:

    make dist

    如果你的系统中有 Docker,则可以通过运行以下命令,使用"物理的"分离的主机/节点运行动态集成测试:

    make integration

    这将启动 3个从容器和 1主( 通过 NODES=5 make integration 更改),并运行 integration_SUITE CT测试套件。

    的基本原理

    收费费:gen_rpc 博士使用mailbox-per-node架构和 gen_tcp 进程并行化来自多个节点的数据接收,而不阻塞虚拟机端口的分布。

    开发 gen_rpc 基础架构的尝试和错误之后,在尝试使用 rpc 库扩展分布式Erlang基础架构时,开发变得明显。 这两个解决方案在请求数量足够多的情况下都会受到非常特殊的问题。

    通过在 rpc的分布式端口上通过分布式端口将数据传送到另一个被称为( 远程执行服务器)的注册服务器,库作为标准分配的一部分运行。 在高流量方案中,这允许运行单个 gen_server 服务器的固有问题: 邮箱溢出随着与 node 中的数据交换的数量增加,rex 必须处理的消息对处理( 不要忘了这只限于一个线程)的过程太大。

    输入 erlang:spawn/4 ( 远程繁殖从现在开始) 。 远程生成在远程 node 上动态生成进程,跳过 rex 所具有的单个邮箱限制。 不同的库是用来利用这个漏洞( 例如 Rexi )的,但是有一个捕捉。

    远程繁殖不是设计用来作为调用参数的一部分来传送大量数据的。 如果你想在远程繁殖中传送像图片或者事务日志的大型二进制文件,那么如果你通过订阅系统监视器,你迟早会看到该消息出现在你的日志中:

    {monitor,<4685.187.0>,busy_dist_port,#Port<4685.41652>}

    这个消息基本上意味着在VM尝试使用other分布式Erlang心跳信号beacons或者的mnesia同步,分布式虚拟机端口对正忙 busy 。 当然,这些子系统具有一定的时序期望,这些子系统具有和结果可能会有问题: 即使一切正常,VM也会检测到一个 node,即使一切都是正常的,而且 mnesia 可能会导致网络分区。

    通过对来自不同节点的数据进行切分,并使用不同的端口对不同节点的( 因此不使用分布式Erlang端口) 进行处理,gen_rpc 解决了这两个。

    体系结构

    为了实现mailbox-per-node功能,gen_rpc 使用了一个非常特殊的架构:

    • 每当客户端需要向远程 node 发送数据时,它将对以远程 node 为名的进程执行 whereis

    • 如果指定的client 进程不存在,它将通过 dispatcher 进程请求新的进程,然后通过适当的client 管理器启动它。 由于来自dispatcher序列> 启动client|的| whereis> 请求可以由许多不同的进程并发进行,因此在 gen_server 之后序列化可以避免争用条件。

    • dispatcher 进程将通过客户机的主管启动一个新的client 进程。

    • 新客户端进程将连接到 node的远程 gen_rpc server,提交一个新服务器的请求并等待。

    • gen_rpc server 服务器将要求 acceptor 主管启动一个新的acceptor 流程并将它的交给新的套接字连接。

    • acceptor 接管新套接字并使用当前的Erlang cookie和所选驱动程序支持的任何额外协议级别身份验证对 client 进行身份验证。

    • client 最终将请求( 。callcast 等等 ) 编码为一些元数据( 调用方的PID和引用),并通过TCP通道发送它。 对于 async callclient 还启动一个进程,负责将服务器的应答传递给请求方。

    • 另一方的acceptor 解码接收到的TCP消息并生成一个新进程,该进程将执行请求的函数。 通过在服务器外部生成进程,acceptor 保护自身不受行为调用行为的影响。

    • 服务器应答后,服务器发出应答消息,服务器将发送消息到服务器,并将消息发送回请求方,然后客户端将消息发送回请求方。 在 async call的情况下,派生的工作人员和工作人员的client 消息会带来结果的响应。

    所有 gen_tcp 进程都被正确连接,这样任何TCP故障都将级联并关闭TCP通道,任何新连接将分配新进程和端口。

    clientserver 进程内实现了一个非活动超时,以便在需要时免费使用未使用的TCP连接。

    性能

    gen_rpc 在 production 8-core incoming CPU CPU和英镑的Erlang,在生产中广泛使用了 150.000 incoming calls/sec/node 。 中等负荷大小为 一年内没有检测到稳定性或者可伸缩性问题。

    已知问题

    • 当将匿名函数传送到其他 node 时,由于Erlang实现匿名函数( Erlang序列化函数元数据,但不序列化函数体)的方式,它将无法执行。 这个问题在 rpc 和远程生成中也存在。

    许可证

    这个项目是发布和发布在许可协议下。

    请参见 CONTRIBUTING.md

    贡献者:



    文章标签:BASE  LAN  LANG  SCA  Scala  Erlang  ERL  Scalable  

    Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语