├── README.md ├── agent-v2 ├── .gitignore ├── Dockerfile ├── mesh-agent │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── alibaba │ │ │ └── dubbo │ │ │ └── performance │ │ │ └── demo │ │ │ └── agent │ │ │ ├── AgentApp.java │ │ │ ├── proto │ │ │ ├── Agent.java │ │ │ └── Agent.proto │ │ │ ├── registry │ │ │ ├── Endpoint.java │ │ │ ├── EtcdRegistry.java │ │ │ ├── IRegistry.java │ │ │ └── IpHelper.java │ │ │ ├── rpc │ │ │ ├── ConsumerRpcClient.java │ │ │ ├── ConsumerRpcHandler.java │ │ │ ├── DubboRpcDecoder.java │ │ │ ├── DubboRpcEncoder.java │ │ │ ├── ProviderRpcClient.java │ │ │ ├── ProviderRpcHandler.java │ │ │ ├── loadbalance │ │ │ │ ├── LoadBalance.java │ │ │ │ └── RoundRobinLoadBalance.java │ │ │ └── model │ │ │ │ ├── Bytes.java │ │ │ │ ├── JsonUtils.java │ │ │ │ ├── Request.java │ │ │ │ ├── RpcFuture.java │ │ │ │ ├── RpcInvocation.java │ │ │ │ └── RpcResponse.java │ │ │ └── server │ │ │ ├── AgentConstant.java │ │ │ ├── ConsumerAgentServer.java │ │ │ ├── ConsumerAgentServerHandler.java │ │ │ ├── IdGenerator.java │ │ │ ├── ProviderAgentServer.java │ │ │ ├── ProviderAgentServerHandler.java │ │ │ └── api │ │ │ └── AgentServer.java │ │ └── resources │ │ ├── application.properties │ │ └── logback.xml ├── pom.xml ├── start-agent.sh └── start-agent.sh.template ├── agent ├── .gitignore ├── Dockerfile ├── Pipfile ├── consumer-agent-netty │ ├── dependency-reduced-pom.xml │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ ├── communication │ │ ├── MessageProtos.java │ │ ├── ProviderAgentClient.java │ │ └── ProviderAgentClientHandler.java │ │ ├── message.proto │ │ ├── registry │ │ ├── Endpoint.java │ │ ├── EtcdRegistry.java │ │ ├── IRegistry.java │ │ └── IpHelper.java │ │ └── server │ │ ├── ConsumerAgentHttpServerHandler.java │ │ └── ConsumerAgentServer.java ├── pom.xml ├── provider-agent-netty │ ├── dependency-reduced-pom.xml │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ ├── HashServerHandler.java │ │ ├── ProviderAgent.java │ │ ├── communication │ │ └── MessageProtos.java │ │ ├── dubbo │ │ ├── DubboRpcDecoder.java │ │ ├── DubboRpcEncoder.java │ │ ├── RpcClient.java │ │ ├── RpcClientHandler.java │ │ └── model │ │ │ ├── Bytes.java │ │ │ ├── JsonUtils.java │ │ │ ├── Request.java │ │ │ ├── RpcFuture.java │ │ │ ├── RpcInvocation.java │ │ │ ├── RpcRequestHolder.java │ │ │ └── RpcResponse.java │ │ ├── message.proto │ │ └── registry │ │ ├── Endpoint.java │ │ ├── EtcdRegistry.java │ │ ├── IRegistry.java │ │ └── IpHelper.java ├── start-agent.sh └── start-agent.sh.template ├── benchmarker ├── .gitignore ├── README.md ├── mock │ └── server.py ├── process.yml ├── scripts │ └── bootstrap.sh └── workflow │ ├── Pipfile │ ├── Pipfile.lock │ ├── benchmark │ ├── configuration.py │ ├── model │ │ ├── task.py │ │ └── workspace.py │ ├── task_agent.py │ ├── utils.py │ ├── workflow.py │ └── wrk.lua │ ├── bootstrap.py │ └── logging.yml └── services ├── .gitignore ├── Dockerfile ├── README.md ├── docker-entrypoint.sh ├── mesh-consumer ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── alibaba │ │ └── dubbo │ │ └── performance │ │ └── demo │ │ └── consumer │ │ ├── ConsumerApp.java │ │ └── HelloController.java │ └── resources │ ├── application.properties │ └── logback.xml ├── mesh-provider ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── alibaba │ │ └── dubbo │ │ └── performance │ │ └── demo │ │ └── provider │ │ ├── Configuration.java │ │ ├── HelloService.java │ │ ├── IHelloService.java │ │ └── ProviderApp.java │ └── resources │ ├── application.properties │ ├── dubbo-provider.xml │ └── logback.xml └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | # 第四届阿里中间件性能挑战赛(初赛) 2 | 3 | ## 更新记录 4 | 5 | ### 【2018-05-17】Docker 容器以网桥形式启动 6 | 7 | 出于安全性考虑,现将所有 Docker 容器以网桥的形式启动。 8 | 9 | 在 benchmarker 脚本中,创建了一个名为 benchmarker 的网络,并分配地址段为 `10.10.10.0/24`,后续启动的 Docker 容器均在此网络内部运行。此番改动可以带来如下一些好处: 10 | 11 | 1. etcd 服务以容器的形式启动,不需要在宿主机上再部署 etcd 服务了 12 | 2. Docker 自定义网络有内建的 DNS 功能,因此容器之间可以通过 `etcd`、`consumer`、`provider-small`、`provider-medium` 和 `provider-large` 等域名的形式访问各个服务,不用再去寻找 `docker0` 网卡上的 IP 地址了 13 | 3. nc/ncat 检测服务端口是否可用的逻辑也通过一个容器来完成,避免了 nc/ncat 命令不存在,或版本不兼容引发的问题 14 | 4. 不需要将所有服务的端口都暴露给宿主机,只要将最终用于压测的 Consumer 服务的端口暴露出来可以了。避免引入大量不必要的端口,端口与文档可以保持较好的一致性,见下表: 15 | 16 | | 服务 | 容器主机名 | 端口 | 备注 | 17 | | ---- | ---- | ---- | ---- | 18 | | etcd | etcd | 2379 | | 19 | | Consumer | consumer | 8087 | 映射到宿主机的时候变为 80 | 20 | | Consumer Agent | consumer | 20000 | | 21 | | Provider Agent (small) | provider-small | 30000 | | 22 | | Provider Agent (medium) | provider-medium | 30000 | | 23 | | Provider Agent (large) | provider-large | 30000 | | 24 | | Provider (small) | provider-small | 20880 | | 25 | | Provider (medium) | provider-medium | 20880 | | 26 | | Provider (large) | provider-large | 20880 | | 27 | 28 | 可能对现有 Agent 的实现产生的影响如下: 29 | 30 | 1. 访问方式上的变化。以前是通过 `docker0` 网卡获取 IP 地址,现在可以直接使用域名 31 | 2. 以前需要暴露的大量不同端口也尽量使用服务默认的端口 32 | 3. 对服务注册和发现有一定的影响(这个主要取决于服务注册与发现功能实现的是否足够通用) 33 | 4. Provider Agent 访问 Provider 的时候需要指定的连接信息发生了变化,如果是以配置文件的形式(就像 demo 那样)来实现的,则只需要修改配置信息即可 34 | 5. `bootstrap_samples.conf` 文件修改了,需要替换原来的 `bootstrap.conf` 文件,并填充留空的字段 35 | 36 | ### 【2018-05-15】Consumer 改为双异步 37 | 38 | 使用了 Servlet 3.0 异步 API 和 AsyncHttpClient 对 Consumer 进行改造,大幅提升了 Consumer 的性能。 39 | 40 | ## 〇、相关澄清(不定期更新) 41 | 42 | **1、关于宣传文章中“使用缓存”的澄清。** 43 | 44 | 在宣传文章的第四章第 3 小节中说到:使用缓存。合理缓存响应结果,当相同的请求再次到来的时候,调用链可以不必经过系统中的每一个节点,从而尽快返回。 45 | 46 | 这里澄清一下缓存使用的范围: 47 | 48 | 1. 可以缓存 etcd 注册中心里的数据,及其他配置数据 49 | 2. 不可以对请求的数据流进行缓存 50 | 3. 不可以对返回结果进行缓存 51 | 52 | ## 一、赛题背景 53 | 54 | ### 1.1、Apache Dubbo (incubating) 简介 55 | 56 | ![Apache Dubbo (incubating) Architecture](assets/dubbo-architecture.png) 57 | 58 | Apache Dubbo (incubating) 是阿里巴巴中间件团队开源的一款高性能 Java RPC 通讯框架。在分布式应用场景下,服务间通讯是非常重要的能力,通常由服务提供者暴露服务,由服务消费者调用服务。在 Dubbo 服务整合能力的支持下,使用 RPC 可以像使用本地调用一样轻松、便捷。但是在异常复杂的系统环境下,服务间调用也会变得非常复杂,如果没有一套完善的、经过大规模生产环境验证的服务治理能力的话,系统将会处于非常危险的境地。因此,从另一个方面来讲,Dubbo 不只是单纯的服务通讯框架,更是一套完备的服务治理框架。 59 | 60 | 有关 Dubbo 的更详细介绍,请登录[官方网站](http://dubbo.apache.org/)。 61 | 62 | ### 1.2、Service Mesh 简介 63 | 64 | ![Service Mesh Architecture](assets/service-mesh-architecture.png) 65 | 66 | 提到服务治理能力就不能不说一下微服务。微服务不光是创造性的将曾经的单体系统拆分为若干个独立的微服务系统,更重要的是其为这些服务的和谐运行提供了最佳实践和解决方案。服务注册、服务发现、服务治理、负载均衡、服务监控、流量管控、服务降级、服务熔断和服务安全等等,这些能力都是一个可用和可靠的微服务系统所不可或缺的。微服务的一大问题在于改造过程必须深入服务内部,拿使用 Dubbo 来说,所有接入的微服务系统都必须引入 Dubbo 组件,并暴露或消费相关的服务。 67 | 68 | 而 Service Mesh 则另辟蹊径,其实现服务治理的过程不需要改变服务本身。通过以 proxy 或 sidecar 形式部署的 Agent,所有进出服务的流量都会被 Agent 拦截并加以处理,这样一来微服务场景下的各种服务治理能力都可以通过 Agent 来完成,这大大降低了服务化改造的难度和成本。而且 Agent 作为两个服务之间的媒介,还可以起到协议转换的作用,这能够使得基于不同技术框架和通讯协议建设的服务也可以实现互联互通,这一点在传统微服务框架下是很难实现的。 69 | 70 | 有关 Service Mesh 的更多内容,请参考下列文章: 71 | 72 | * [What Is a Service Mesh?](https://www.nginx.com/blog/what-is-a-service-mesh/) 73 | * [What’s a service mesh? And why do I need one?](https://buoyant.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/) ([中文翻译](https://blog.csdn.net/wangqingjiewa/article/details/78677912)) 74 | * [聊一聊新一代微服务技术 Service Mesh](https://www.sdnlab.com/20363.html) 75 | 76 | ### 1.3、赛题由来 77 | 78 | 众所周知,Dubbo 的 RPC 通讯和服务治理能力一直局限在 Java 领域,因此增加多语言适配是建设 Dubbo 生态环境的一个重要方向。随着微服务及相关技术实践的落地,Service Mesh 已经成为分布式场景下服务化改造的热门解决方案,并与底层设施及周边环境实现了很好的融合,这些都与 Dubbo 的能力如出一辙,未来 Dubbo 将有可能发展成为 Service Mesh 的一种通用解决方案。 79 | 80 | 在初步了解了 Dubbo 和 Service Mesh 的情况下,我们来实现一个简化版本的 Agent,用 Service Mesh 的思想对 Dubbo 进行一下改进。 81 | 82 | ## 二、赛题说明 83 | 84 | ### 2.1、系统架构 85 | 86 | 赛题限定的系统架构如下。得益于 Docker 提供的容器化能力,我们可以非常方便的在有限资源下模拟出这样的系统结构。有关 Docker 的功能和使用方法超出了本文的讨论范围,请移步[官方文档](https://docs.docker.com/)。 87 | 88 | ![系统架构](assets/system-architecture.png) 89 | 90 | 图中每个蓝色的方框代表一个 Docker 实例,全部运行在一台宿主机上。最上面的一个实例运行有 etcd 服务,左边的一个实例运行有 Consumer 服务及其 Agent,而右边的三个实例运行有 Provider 服务及其 Agent。从图中可以看出,Consumer 和 Provider 并不会直接通讯,所有进出服务的流量都需要经过 Agent 中转。 91 | 92 | ### 2.2、服务 93 | 94 | etcd 是注册中心服务,用来存储服务注册信息,为了简化系统复杂度,etcd 是单节点运行的,并没有部署高可用能力。Provider 是服务提供者,Consumer 是服务消费者,Consumer 消费 Provider 提供的服务。**Consumer 及 Provider 服务的实现是由赛会官方提供的。** 95 | 96 | 在系统场景设定中,每个运行服务的实例所占用的系统资源都是不同的,如下表所示: 97 | 98 | | 实例 | 百分比 | 99 | |-----|-------:| 100 | | 操作系统 | 5% | 101 | | 运行 etcd 服务的实例 | 5% | 102 | | 运行 Consumer 服务及其 Agent 的实例 | 45% | 103 | | 运行 Provider (small) 服务及其 Agent 的实例 | 7.5% | 104 | | 运行 Provider (medium) 服务及其 Agent 的实例 | 15% | 105 | | 运行 Provider (large) 服务及其 Agent 的实例 | 22.5% | 106 | | 总计 | 100% | 107 | 108 | 从表中可以看出,运行 Consumer 服务及其 Agent 的实例(为了便于描述,下文将简称为 Consumer 实例,Provider 实例类似)占用的系统资源是最多的,而三个 Provider 实例占用的系统资源总和与 Consumer 实例是相同的,而且按照 small:medium:large = 1:2:3 的比例进行分配。 109 | 110 | 在每个 Consumer 和 Provider 实例中,都存在一个以 sidecar 形式运行的 Agent,其在整个系统中起到了非常关键的作用。 111 | 112 | 第一、Consumer 服务是基于 Spring Cloud 实现的,其远程通讯协议使用 HTTP。但是 Provider 服务是基于 Dubbo 实现的,其远程通讯协议使用 DUBBO。因此在没有任何外界支援的情况下,Consumer 和 Provider 服务是无法直接通讯的。这就要求 Agent 实现 HTTP 协议到 DUBBO 协议的转换。有关 DUBBO 协议的格式,请参见附录3。 113 | 114 | 第二、因为任何一个 Provider 实例的性能都是小于 Consumer 实例的,这就要求在 Agent 实现的过程中考虑负载均衡的因素。 115 | 116 | 第三、Consumer Agent 在负载均衡过程中到底需要访问哪一个 Provider Agent 不是在配置文件中写死的,而是需要通过服务注册与发现机制来完成。在 Agent 启动的时候,其要把相关服务的信息写到注册中心里,当服务调用发生的时候,再从注册中心中读取信息,并路由到指定的服务节点。 117 | 118 | ### 2.3、服务运行及调用流程 119 | 120 | 1. 启动 etcd 实例 121 | 2. 启动三个 Provider 实例,Provider Agent 将 Provider 服务信息写入 etcd 注册中心 122 | 3. 启动 Consumer 实例,Consumer Agent 从注册中心中读取 Provider 信息 123 | 4. 客户端访问 Consumer 服务 124 | 5. Consumer 服务通过 HTTP 协议调用 Consumer Agent 125 | 6. Consumer Agent 根据当前的负载情况决定调用哪个 Provider Agent,并使用自定义协议将请求发送给选中的 Provider Agent 126 | 7. Provider Agent 收到请求后,将通讯协议转换为 DUBBO,然后调用 Provider 服务 127 | 8. Provider 服务将处理后的请求返回给 Agent 128 | 9. Provider Agent 收到请求后解析 DUBBO 协议,并将数据取出,以自定义协议返回给 Consumer Agent 129 | 10. Consumer Agent 收到请求后解析出结果,再通过 HTTP 协议返回给 Consumer 服务 130 | 11. Consumer 服务最后将结果返回给客户端 131 | 12. 结束 132 | 133 | 每个通讯环节所使用的协议如下: 134 | 135 | | 通讯环节 | 序列化协议 | 远程通讯协议 | 备注 | 136 | |---------|----------|------------|-----| 137 | | Client => Consumer | (无参数传递) | HTTP | | 138 | | Consumer => Consumer Aagent | FORM | HTTP | | 139 | | Consumer Agent => Provider Agent | FORM | HTTP | 可根据需要自定义 | 140 | | Provider Agent => Provider | JSON | DUBBO | | 141 | | Provider => Provider Agent | JSON | DUBBO | | 142 | | Provider Agent => Consumer Agent | TEXT | HTTP | 可以根据需要自定义 | 143 | | Consumer Agent => Consumer | TEXT | HTTP | | 144 | | Consumer => Client | TEXT | HTTP || 145 | 146 | ### 2.4、功能与接口 147 | 148 | Provider 服务接口: 149 | 150 | ```java 151 | public interface IHelloService { 152 | 153 | /** 154 | * 计算传入参数的哈希值. 155 | * 156 | * @param str 随机字符串 157 | * @return 该字符串的哈希值 158 | */ 159 | int hash(String str); 160 | } 161 | ``` 162 | 163 | Provider 接口的实现会人为增加 50ms 的延迟,以模拟现实情况下查询数据库等耗时的操作。 164 | 165 | Consumer 在接收到客户端请求以后,会生成一个随机字符串,该字符串经过 Consumer Agent 和 Provider Agent 后到达 Provider,由 Provider 计算哈希值后返回,客户端会校验该哈希值与其生成的数据是否相同,如果相同则返回正常(200),否则返回异常(500)。 166 | 167 | Consumer 发送给 Consumer Agent 的 HTTP POST 请求格式如下: 168 | 169 | | key | value | 说明 | 170 | | --- | ----- | ---- | 171 | | interface | com.alibaba.performance.dubbomesh.provider.IHelloService | 拟调用的服务名。因 Provider 只暴露了一个服务,因此这个参数是固定的。但考虑到实现的通用性,该值不允许缓存。| 172 | | method | hash | 拟调用的方法。同理 Provider 只提供了一个方法,因此该值也是固定的。不允许缓存。 | 173 | | parameterTypesString | Ljava/lang/String;(注意这后面有个分号) | 同一个方法名可能会有重载的版本,所以需要指定参数类型来确定方法的签名。由于只存在一个方法重载,这个参数是固定的,永远是`Ljava/lang/String;`。 Dubbo 内部用它来表示方法的参数是 String 类型。不允许缓存。| 174 | | parameter | <生成的随机字符串> | 传递给 `hash` 方法的参数值,是 Consumer 生成的一个随机的字符串。| 175 | 176 | ### 2.5、要求与限制 177 | 178 | 由于本次比赛是不限语言的,因此仅对 Agent 的能力做出要求。Agent 必须实现如下一些功能: 179 | 180 | 1. 服务注册与发现 181 | 2. 负载均衡 182 | 3. 协议转换 183 | 4. 要具有一定的通用性 184 | 185 | 同样由于不限定语言,本次比赛将构建 Consumer 和 Provider 镜像的主动权交给了参赛选手,选手们可以根据自己使用的技术和实现手段对镜像进行定制——可以安装额外的运行时环境、添加依赖库、调整 Agent 启动参数等,但如下一些行为是不被允许的: 186 | 187 | 1. 必须使用官方提供的 Consumer 和 Provider 实现、以及启动脚本,不允许对其进行修改(如果发现缺陷,请提交 Merge Request 或发起 Issue) 188 | 2. 启动 Consumer 和 Provider 所使用的 JDK 版本必须与官方镜像中提供的版本保持一致(当前版本是 Oracle JDK 1.8.0_172-b11) 189 | 3. 不允许通过脚本等手段停止官方启动的服务后替换为自己的服务 190 | 4. 不允许在 Consumer 和 Provider 运行过程中使用一些字节码增强技术替换现有实现 191 | 5. 不限制使用第三方应用服务器,如 Tomcat、Nginx 或 Envoy 等,但不可以使用现成的 Service Mesh 解决方案 192 | 6. 可以参考第三方实现,借用其思想和少量代码,但不可以全盘复制 193 | 194 | ## 三、评测 195 | 196 | ### 3.1、评测环境 197 | 198 | 每一组评测环境由三台主机构成,如下图所示: 199 | 200 | ![评测系统架构](assets/benchmarker-architecture.png) 201 | 202 | 左边的一台是施压机(配置为 4C8G),右边的两台是被压机(配置为 8C16G),施压机上运行两个 Benchmarker 进程,每个进程向一台被压机施加压力,而被压机上则运行选手提交的各种服务。每组评测环境中三台主机的角色是固定的,且各组评测环境之间是相互隔离的。 203 | 204 | Benchmarker 会通过调度程序不断运行,每次运行都会执行一个评测任务(评测任务就是选手在页面上使用的一次评测机会),因此一组评测环境同时可以运行两个评测任务。评测任务开始执行的时候,会进行各种环境准备,启动服务等,然后分别以不同的压力水平对系统进行评测并获取得分。在每次评测任务执行的过程中,服务仅启动一次,中途不重启。任务执行完成以后,环境会被清理,因此每次评测任务之间是互不干扰的。 205 | 206 | 需要特别说明的是每组评测环境中主机的发现机制。为了更加方便的发现主机,我们在施压机的 `/etc/hosts` 文件中做了如下的映射: 207 | 208 | | 角色 | 主机名 | 说明 | 209 | | --- | ----- | ----- | 210 | | 施压机 | <组别>.<根主机名> | 组别是类似 g1, g2, g3 这样的编号,图中为 g1;根主机名是内部 DNS 分配给当前主机的名称,图中为 tianchi001.test | 211 | | 被压机 | shuke.<组别>.<根主机名> | 其中 shuke 是固定的,而组别和根主机名与被压机是相同的 | 212 | | 被压机 | beita.<组别>.<根主机名> | 其中 beita 是固定的,而组别和根主机名与被压机是相同的 | 213 | 214 | 这样做的好处是,只要获取到施压机的主机名,就可以方便的通过添加 shuke 或者 beita 的前缀找到指定的被压机。 215 | 216 | ### 3.2、评测环境搭建 217 | 218 | 请参考 benchmarker 项目的 [README](https://code.aliyun.com/middlewarerace2018/benchmarker)。 219 | 220 | ## 四、常见问题 221 | 222 | ### 4.1、评测环境的操作系统内核版本是多少? 223 | 224 | ```bash 225 | $ uname -r 226 | 3.10.0-327.ali2015.alios7.x86_64 227 | ``` 228 | 229 | ### 4.2、评测环境的 Docker 版本是多少? 230 | 231 | ```bash 232 | $ docker --version 233 | Docker version 1.12.6, build 69e6d1b BUILDTIME:2018-03-27 19:57:15 234 | ``` 235 | 236 | ### 4.3、是否可以使用其他版本的 JDK 或者是自行编译的 JDK? 237 | 238 | 原则上对此行为不做限制,但是需要确保启动 Consumer 和 Provider 服务所使用的 JDK 不受影响。也就是说,如果要使用其他版本的 JDK 或自行编译的 JDK,就要安装两个版本:一个是原来的版本,用来启动 Consumer 和 Provider,另外一个用来启动 Agent。 239 | 240 | ### 4.4、是否可以调整 Consumer 和 Provider 的启动参数? 241 | 242 | 不可以。主要原因是确保所有参赛团队的运行环境是公平的。 243 | 244 | ### 4.5、是否可以使用第三方依赖? 245 | 246 | 可以使用像 Netty, Vert.x, Boost 等第三方依赖,但不可以使用具有 Service Mesh 功能的依赖库。 247 | 248 | ### 4.6、是否可以调整操作系统参数? 249 | 250 | 评测环境启动 Docker 实例的时候是以非 `privileged` 模式启动的,因此不能对操作系统的参数进行调整。评测环境的有关系统参数如下: 251 | 252 | ``` 253 | net.core.somaxconn = 40000 254 | net.core.wmem_default = 8388608 255 | net.core.rmem_default = 8388608 256 | net.core.rmem_max = 134217728 257 | net.core.wmem_max = 134217728 258 | net.core.netdev_max_backlog = 300000 259 | net.ipv4.tcp_max_syn_backlog = 40000 260 | net.ipv4.tcp_sack = 1 261 | net.ipv4.tcp_window_scaling = 1 262 | net.ipv4.tcp_fin_timeout = 15 263 | net.ipv4.tcp_keepalive_intvl = 30 264 | net.ipv4.tcp_tw_reuse = 1 265 | net.ipv4.tcp_moderate_rcvbuf = 1 266 | net.ipv4.tcp_mem = 134217728 134217728 134217728 267 | net.ipv4.tcp_rmem = 4096 277750 134217728 268 | net.ipv4.tcp_wmem = 4096 277750 134217728 269 | net.ipv4.ip_local_port_range=1025 65535 270 | ``` 271 | 272 | ### 4.7、评测环境使用的 Etcd 版本是多少?协议版本是多少? 273 | 274 | 评测环境使用的 Etcd 版本为 [3.3.4](https://github.com/coreos/etcd/releases/tag/v3.3.4),协议版本是 v3。 275 | 276 | 切换 `etcdctl` 命令默认使用的协议版本的方法,请参考[这里](https://coreos.com/etcd/docs/latest/dev-guide/interacting_v3.html)。 277 | 278 | ### 4.8、镜像仓库的地址为什么在浏览器中打不开? 279 | 280 | 镜像仓库的地址不是用来在浏览器上进行访问的,而是用来拉取镜像的。 281 | 282 | ### 4.9、Mock Server 是做什么用的? 283 | 284 | 在正式的评测环境上,评测任务是从天池系统获得的。但是在测试环境上,选手们无法连接到天池系统获取数据,因此提供了这个 Mock Server 用来模拟天池返回的数据。Mock Server 是个非常小的程序,跟施压机跑在一起就可以了。 285 | 286 | 使用 Mock Server 获取数据时,需要将 `bootstrap.conf` 文件中的 `Host` 参数修改为 `http://localhost:3000`,`TaskFetchPath` 参数修改为 `/`。 287 | 288 | ### 4.10、服务总是起不来该怎么办? 289 | 290 | 服务起不来,在 Benchmarker 脚本的日志里面主要体现在端口连接不上,使用 `docker ps` 命令查看 Docker 实例的时候,发现实例启动后马上就退出了,而且也没有任何有意义的服务日志生成。造成实例启动后马上退出的原因是这样的:Consumer 或 Provider 容器启动的时候,会先执行 `docker-entrypoint.sh` 脚本,在这个脚本里面会以 `nohup` 的形式在后台启动服务,之后 `docker-entrypoint.sh` 脚本会调用 `start-agent.sh` 脚本,在这个脚本里面以前台模式启动 agent。这样的话如果 agent 启动失败,就没有前台程序驻留运行,导致 Docker 实例立即退出。 291 | 292 | 有很多种原因可能导致这个问题,这里主要介绍一下调试的手段。 293 | 294 | 首先,检查一下 `start-agent.sh` 脚本是否有可执行权限(尤其是开发环境使用 Windows 系统的选手)。最新版的 Benchmarker 脚本会检查这个文件是否具有可执行权限,如果没有会输出错误信息。 295 | 296 | 然后,以交互模式启动一个 Docker 实例,并进入 shell: 297 | 298 | ```bash 299 | $ docker run -it --entrypoint="" bash 300 | ``` 301 | 302 | 分别运行 `docker-entrypoint.sh` 和 `start-agent.sh` 脚本,看一下会出现什么错误,再根据这些错误指引进行问题排查。 303 | 304 | Benchmarker 脚本里面检查服务是否启动的方法是:尝试连接服务所暴露的端口,如果能够成功连接则认为服务启动成功。而如果连接不上会等待 5s 钟以后重试,尝试 10 次如果仍然无法连接到端口,则认为服务启动失败。那么因为每个服务所占用的系统资源是不同的,在性能比较差的宿主机上,确实有可能出现服务用时 50s 都没有起来的情况,此时可以酌情修改脚本,增加重试次数。 305 | 306 | ### 4.11、本地构建镜像的时候报告类似这样的错误 `Error parsing reference: "registry.cn-hangzhou.aliyuncs.com/aliware2018/services AS builder" is not a valid repository/tag: invalid reference format` 怎么办? 307 | 308 | Docker 版本过低,不支持 `FROM ... AS ...` 语法,请升级 Docker 到最新版。 309 | 310 | ### 4.12、测试环境签名检查不通过怎么办? 311 | 312 | 打开 `workflow.py` 文件,找到 `run` 方法,注释掉里面的 `self.____check_signatures()` 方法调用即可。 313 | 314 | 在测试环境下可以不用校验签名,在正式跑分时会强制校验 `/root/dists/mesh-consumer.jar`、`/root/dists/mesh-provider.jar` 和 `/usr/local/bin/docker-entrypoint.sh` 三个文件的签名,以防止其被修改,影响评测的公平性。 315 | 316 | ### 4.13、正式环境签名检查不通过怎么办? 317 | 318 | 需要保证 `mesh-consumer.jar`、`mesh-provider.jar` 和 `docker-entrypoint.sh` 三个文件是从 services 镜像中复制过来的,而不是自己在本地构建以后再 push 到镜像仓库中去的。后者相当于重新生成了这些 jar 包,会导致 sha256 哈希值发生变化。 319 | 320 | 如果依旧出现签名不匹配的问题,可以进入到镜像内部,执行如下三条命令: 321 | 322 | ```bash 323 | $ sha256sum /root/dists/mesh-consumer.jar 324 | $ sha256sum /root/dists/mesh-provider.jar 325 | $ sha256sum /usr/local/bin/docker-entrypoint.sh 326 | ``` 327 | 328 | 然后将结果发送给群里面的支持同学,跟评测环境中的内容做个对比。 329 | 330 | ### 4.14、评测结束以后如何下载日志? 331 | 332 | 日志下载地址: 333 | 334 | ``` 335 | https://middlewarerace2018.oss-cn-hangzhou.aliyuncs.com/{teamId}/{taskId}/logs.tar.gz 336 | ``` 337 | 338 | 请用提交任务以后显示的 `teamId` 和 `taskId` 来替换上述 URL 中的占位符。 339 | 340 | **注:日志在 OSS 上保存 3 天。 ** 341 | 342 | ### 4.15、如何提交评测任务 343 | 344 | 首先,点击菜单栏左侧的“提交结果”菜单项,在右边的界面中,点击文本框中的“修改地址”连接。 345 | 346 | ![提交结果](assets/submit-result.png) 347 | 348 | 然后,在弹出的对话框中,填写以下信息: 349 | 350 | ![修改地址](assets/submit-dialog.png) 351 | 352 | * **git路径** http://code.aliyun.com 上面创建的代码仓库 353 | * **镜像路径** http://cr.console.aliyun.com 上面的创建的镜像仓库(注意要使用公网地址,地址的格式请参考“镜像列表”界面中的“仓库地址”列) 354 | * **用户名** 登录阿里云的用户名(可以是淘宝或支付宝账号) 355 | * **密码** 登录镜像仓库的密码(注意不是登录淘宝或支付宝的密码,该密码在镜像仓库的页面上创建) 356 | 357 | 填写完成以后,点击确定,再点击上一步文本框旁边蓝色的“提交结果”按钮。 358 | 359 | ## 附录1:代码仓库 360 | 361 | * **[Agent 示例](https://code.aliyun.com/middlewarerace2018/agent-demo)** 362 | * **[Provider 及 Consumer 服务](https://code.aliyun.com/middlewarerace2018/services)** 363 | * **[评测工具](https://code.aliyun.com/middlewarerace2018/benchmarker)** 364 | * **[基础镜像](https://code.aliyun.com/middlewarerace2018/docker)** 365 | 366 | ## 附录2:镜像仓库 367 | 368 | * **Agent 示例:**registry.cn-hangzhou.aliyuncs.com/aliware2018/agent-demo 369 | * **Provider 及 Consumer 服务:**registry.cn-hangzhou.aliyuncs.com/aliware2018/services 370 | * **etcd 服务:**registry.cn-hangzhou.aliyuncs.com/aliware2018/alpine-etcd 371 | 372 | ## 附录3:DUBBO 协议 373 | 374 | ![DUBBO 协议](assets/dubbo-protocol.png) 375 | 376 | * Magic - Magic High & Magic Low (16 bits) 377 | 378 | Identifies dubbo protocol with value: 0xdabb. 379 | 380 | * Req/Res (1 bit) 381 | 382 | Identifies this is a request or response. Request - 1; Response - 0. 383 | 384 | * 2 Way (1 bit) 385 | 386 | Only useful when Req/Res is 1 (Request), expect for a return value from server or not. Set to 1 if need a return value from server. 387 | 388 | * Event (1 bit) 389 | 390 | Identifies an event message or not, for example, heartbeat event. Set to 1 if this is an event. 391 | 392 | * Serialization ID (5 bit) 393 | 394 | Identifies serialization type: the value for fastjson is 6. 395 | 396 | * Status (8 bits) 397 | 398 | Only useful when Req/Res is 0 (Response), identifies the status of response: 399 | 400 | ``` 401 | 20 - OK 402 | 30 - CLIENT_TIMEOUT 403 | 31 - SERVER_TIMEOUT 404 | 40 - BAD_REQUEST 405 | 50 - BAD_RESPONSE 406 | 60 - SERVICE_NOT_FOUND 407 | 70 - SERVICE_ERROR 408 | 80 - SERVER_ERROR 409 | 90 - CLIENT_ERROR 410 | 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR 411 | ``` 412 | 413 | * Request ID (64 bits) 414 | 415 | Identifies an unique request. Numeric (long). 416 | 417 | * Data Length (32) 418 | 419 | Length of the content (the variable part) after serialization, counted by bytes. Numeric (integer). 420 | 421 | * Variable Part 422 | 423 | Each part is a byte[] after serialization with specific serialization type, identifies by Serialization ID. 424 | 425 | Every part is a byte[] after serialization with specific serialization type, identifies by Serialization ID. 426 | 427 | If the content is a Request (Req/Res = 1), each part consists of the content, in turn is: 428 | 429 | ``` 430 | * Dubbo version 431 | * Service name 432 | * Service version 433 | * Method name 434 | * Method parameter types 435 | * Method arguments 436 | * Attachments 437 | ``` 438 | 439 | If the content is a Response (Req/Res = 0), each part consists of the content, in turn is: 440 | 441 | ``` 442 | * Return value type, identifies what kind of value returns from server side: RESPONSE_NULL_VALUE - 2, RESPONSE_VALUE - 1, RESPONSE_WITH_EXCEPTION - 0. 443 | * Return value, the real value returns from server. 444 | ``` 445 | 446 | 注意:对于 Variable Part,当前版本的 Dubbo 框架使用 JSON 序列化时,在每部分内容间额外增加了换行符作为分隔,请选手在 Variable Part 的每个 part 后额外增加换行符,如: 447 | 448 | ``` 449 | Dubbo version bytes (换行符) 450 | Service name bytes (换行符) 451 | ... 452 | ``` 453 | 454 | 关于 DUBBO 协议的更多细节,请参考代码实现: 455 | 456 | * [ExchangeCodec.java](https://github.com/apache/incubator-dubbo/blob/master/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java) 457 | * [DubboCodec.java](https://github.com/apache/incubator-dubbo/blob/master/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java) 458 | -------------------------------------------------------------------------------- /agent-v2/.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | !.mvn/wrapper/* 5 | *.war 6 | *.zip 7 | *.tar 8 | *.tar.gz 9 | 10 | # eclipse ignore 11 | .settings/ 12 | .project 13 | .classpath 14 | 15 | # idea ignore 16 | .idea/ 17 | *.ipr 18 | *.iml 19 | *.iws 20 | 21 | # temp ignore 22 | *.log 23 | *.cache 24 | *.diff 25 | *.patch 26 | *.tmp 27 | 28 | # system ignore 29 | .DS_Store 30 | Thumbs.db 31 | -------------------------------------------------------------------------------- /agent-v2/Dockerfile: -------------------------------------------------------------------------------- 1 | # Builder container 2 | FROM registry.cn-hangzhou.aliyuncs.com/aliware2018/services AS builder 3 | 4 | COPY . /root/workspace/agent 5 | WORKDIR /root/workspace/agent 6 | #RUN set -ex && mvn clean package 7 | 8 | 9 | # Runner container 10 | FROM registry.cn-hangzhou.aliyuncs.com/aliware2018/debian-jdk8 11 | 12 | COPY --from=builder /root/workspace/services/mesh-provider/target/mesh-provider-1.0-SNAPSHOT.jar /root/dists/mesh-provider.jar 13 | COPY --from=builder /root/workspace/services/mesh-consumer/target/mesh-consumer-1.0-SNAPSHOT.jar /root/dists/mesh-consumer.jar 14 | COPY --from=builder /root/workspace/agent/mesh-agent/target/mesh-agent-1.0-SNAPSHOT.jar /root/dists/mesh-agent.jar 15 | 16 | COPY --from=builder /usr/local/bin/docker-entrypoint.sh /usr/local/bin 17 | COPY start-agent.sh /usr/local/bin 18 | 19 | RUN set -ex && mkdir -p /root/logs 20 | 21 | ENTRYPOINT ["docker-entrypoint.sh"] 22 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dubbo-mesh 7 | com.alibaba 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mesh-agent 13 | 1.0-SNAPSHOT 14 | 15 | 16 | 17 | 18 | 19 | 3.4.0 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-tomcat 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-undertow 38 | 39 | 40 | 41 | io.netty 42 | netty-all 43 | 4.1.12.Final 44 | 45 | 46 | com.alibaba 47 | fastjson 48 | 49 | 50 | log4j 51 | log4j 52 | 1.2.17 53 | 54 | 55 | 56 | junit 57 | junit 58 | test 59 | 60 | 61 | org.apache.httpcomponents 62 | httpclient 63 | 64 | 65 | com.coreos 66 | jetcd-core 67 | 0.0.1 68 | 69 | 70 | io.netty 71 | netty-codec-http2 72 | 73 | 74 | io.netty 75 | netty-handler-proxy 76 | 77 | 78 | 79 | 80 | com.google.protobuf 81 | protobuf-java 82 | ${protobuf.version} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | org.springframework.boot 116 | spring-boot-maven-plugin 117 | 118 | 119 | 120 | repackage 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/AgentApp.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.server.AgentConstant; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AgentApp { 8 | 9 | public static void main(String[] args) { 10 | AgentConstant.AGENT_SERVER.run(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/proto/Agent.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.alibaba.dubbo.performance.demo.agent.server.proto"; 4 | 5 | message AgentRequest { 6 | int64 id = 1; 7 | string interfaceName = 2; 8 | string methodName = 3; 9 | string parameterTypesString = 4; 10 | string parameter = 5; 11 | } 12 | 13 | message AgentResponse { 14 | int64 id = 1; 15 | string value = 2; 16 | } 17 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/registry/Endpoint.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.registry; 2 | 3 | public class Endpoint { 4 | private final String host; 5 | private final int port; 6 | 7 | private int weight; 8 | 9 | public Endpoint(String host,int port, int weight) { 10 | this.host = host; 11 | this.port = port; 12 | this.weight = weight; 13 | } 14 | 15 | public String getHost() { 16 | return host; 17 | } 18 | 19 | public int getPort() { 20 | return port; 21 | } 22 | 23 | public int getWeight() { 24 | return weight; 25 | } 26 | 27 | public void setWeight(int weight) { 28 | this.weight = weight; 29 | } 30 | 31 | public String toString(){ 32 | return host + ":" + port; 33 | } 34 | 35 | public boolean equals(Object o){ 36 | if (!(o instanceof Endpoint)){ 37 | return false; 38 | } 39 | Endpoint other = (Endpoint) o; 40 | return other.host.equals(this.host) && other.port == this.port; 41 | } 42 | 43 | public int hashCode(){ 44 | return host.hashCode() + port; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/registry/EtcdRegistry.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.registry; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.server.AgentConstant; 4 | import com.coreos.jetcd.Client; 5 | import com.coreos.jetcd.KV; 6 | import com.coreos.jetcd.Lease; 7 | import com.coreos.jetcd.data.ByteSequence; 8 | import com.coreos.jetcd.kv.GetResponse; 9 | import com.coreos.jetcd.options.GetOption; 10 | import com.coreos.jetcd.options.PutOption; 11 | import io.netty.util.concurrent.DefaultThreadFactory; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.text.MessageFormat; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.concurrent.Executors; 19 | 20 | public class EtcdRegistry implements IRegistry { 21 | private Logger logger = LoggerFactory.getLogger(EtcdRegistry.class); 22 | // 该EtcdRegistry没有使用etcd的Watch机制来监听etcd的事件 23 | // 添加watch,在本地内存缓存地址列表,可减少网络调用的次数 24 | // 使用的是简单的随机负载均衡,如果provider性能不一致,随机策略会影响性能 25 | 26 | private final String rootPath = "dubbomesh"; 27 | private Lease lease; 28 | private KV kv; 29 | private long leaseId; 30 | 31 | public EtcdRegistry(String registryAddress) { 32 | Client client = Client.builder().endpoints(registryAddress).build(); 33 | this.lease = client.getLeaseClient(); 34 | this.kv = client.getKVClient(); 35 | logger.info(AgentConstant.AGENT_TYPE + " Resigtry"); 36 | try { 37 | this.leaseId = lease.grant(30).get().getID(); 38 | logger.info("LeaseId : " + leaseId); 39 | } catch (Exception e) { 40 | logger.error("Fail to get leaseId :" + e.getMessage()); 41 | } 42 | 43 | keepAlive(); 44 | String type = System.getProperty("type"); // 获取type参数 45 | if ("provider".equals(type)){ 46 | // 如果是provider,去etcd注册服务 47 | try { 48 | int port = Integer.valueOf(System.getProperty("server.port")); 49 | register("com.alibaba.dubbo.performance.demo.provider.IHelloService", port); 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | // 向ETCD中注册服务 58 | public void register(String serviceName,int port) throws Exception { 59 | String weight = AgentConstant.WEIGHT; 60 | String strKey = MessageFormat.format("/{0}/{1}/{2}:{3}",rootPath,serviceName, IpHelper.getHostIp(),String.valueOf(port)); 61 | ByteSequence key = ByteSequence.fromString(strKey); 62 | ByteSequence val = ByteSequence.fromString(weight); 63 | kv.put(key,val, PutOption.newBuilder().withLeaseId(leaseId).build()).get(); 64 | logger.info("Register a new service at:" + strKey + " weight : " + weight); 65 | } 66 | 67 | // 发送心跳到ETCD,表明该host是活着的 68 | public void keepAlive(){ 69 | Executors.newSingleThreadExecutor(new DefaultThreadFactory("heart-beat")).submit( 70 | () -> { 71 | try { 72 | Lease.KeepAliveListener listener = lease.keepAlive(leaseId); 73 | listener.listen(); 74 | logger.info("KeepAlive lease:" + leaseId + "; Hex format:" + Long.toHexString(leaseId)); 75 | } catch (Exception e) { logger.error("",e); } 76 | } 77 | ); 78 | } 79 | 80 | @Override 81 | public List find(String serviceName) throws Exception { 82 | String strKey = MessageFormat.format("/{0}/{1}",rootPath,serviceName); 83 | ByteSequence key = ByteSequence.fromString(strKey); 84 | GetResponse response = kv.get(key, GetOption.newBuilder().withPrefix(key).build()).get(); 85 | 86 | List endpoints = new ArrayList<>(); 87 | 88 | for (com.coreos.jetcd.data.KeyValue kv : response.getKvs()){ 89 | String s = kv.getKey().toStringUtf8(); 90 | int index = s.lastIndexOf("/"); 91 | String endpointStr = s.substring(index + 1,s.length()); 92 | String host = endpointStr.split(":")[0]; 93 | int port = Integer.valueOf(endpointStr.split(":")[1]); 94 | int cores = Integer.valueOf(kv.getValue().toStringUtf8()); 95 | endpoints.add(new Endpoint(host, port, cores)); 96 | } 97 | return endpoints; 98 | } 99 | 100 | 101 | } 102 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/registry/IRegistry.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.registry; 2 | 3 | import java.util.List; 4 | 5 | public interface IRegistry { 6 | 7 | // 注册服务 8 | void register(String serviceName, int port) throws Exception; 9 | 10 | List find(String serviceName) throws Exception; 11 | } 12 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/registry/IpHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.registry; 2 | 3 | import java.net.InetAddress; 4 | 5 | public class IpHelper { 6 | 7 | public static String getHostIp() throws Exception { 8 | 9 | String ip = InetAddress.getLocalHost().getHostAddress(); 10 | return ip; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/ConsumerRpcClient.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.registry.Endpoint; 5 | import com.alibaba.dubbo.performance.demo.agent.registry.IRegistry; 6 | import com.alibaba.dubbo.performance.demo.agent.rpc.loadbalance.LoadBalance; 7 | import com.alibaba.dubbo.performance.demo.agent.rpc.loadbalance.RoundRobinLoadBalance; 8 | import com.alibaba.dubbo.performance.demo.agent.server.ConsumerAgentServer; 9 | import io.netty.bootstrap.Bootstrap; 10 | import io.netty.buffer.PooledByteBufAllocator; 11 | import io.netty.channel.Channel; 12 | import io.netty.channel.ChannelInitializer; 13 | import io.netty.channel.ChannelOption; 14 | import io.netty.channel.EventLoop; 15 | import io.netty.channel.epoll.EpollSocketChannel; 16 | import io.netty.channel.socket.SocketChannel; 17 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 18 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 19 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 20 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 21 | import io.netty.util.concurrent.FastThreadLocal; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.util.HashMap; 26 | import java.util.List; 27 | import java.util.Map; 28 | import java.util.concurrent.ConcurrentHashMap; 29 | 30 | import static javax.swing.UIManager.put; 31 | 32 | 33 | /** 34 | * Created with IntelliJ IDEA. 35 | * Description: 36 | * User: chenyifan 37 | * Date: 2018-05-23 38 | * Time: 下午3:52 39 | */ 40 | public class ConsumerRpcClient{ 41 | 42 | private IRegistry registry; 43 | 44 | private Logger logger = LoggerFactory.getLogger(ConsumerRpcHandler.class); 45 | 46 | 47 | private LoadBalance loadBalance = null; 48 | 49 | private Map channelMap = new HashMap<>(); 50 | 51 | private final Object lock = new Object(); 52 | 53 | public ConsumerRpcClient(IRegistry registry) { 54 | this.registry = registry; 55 | try { 56 | List endpoints = registry.find("com.alibaba.dubbo.performance.demo.provider.IHelloService"); 57 | loadBalance = new RoundRobinLoadBalance(endpoints); 58 | init(); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | private void init() { 65 | ConsumerAgentServer.worker.forEach( 66 | eventExecutor -> { 67 | Bootstrap bootstrap = createBootstrap((EventLoop) eventExecutor, loadBalance.select()); 68 | try { 69 | Channel channel = bootstrap.connect().sync().channel(); 70 | channelMap.put((EventLoop) eventExecutor, channel); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | ); 76 | } 77 | 78 | private Bootstrap createBootstrap(EventLoop eventLoop, Endpoint endpoint) { 79 | return new Bootstrap() 80 | .group(eventLoop) 81 | .remoteAddress(endpoint.getHost(), endpoint.getPort()) 82 | .option(ChannelOption.SO_KEEPALIVE, true) 83 | .option(ChannelOption.TCP_NODELAY, true) 84 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 85 | .channel(EpollSocketChannel.class) 86 | .handler(new ChannelInitializer() { 87 | @Override 88 | protected void initChannel(SocketChannel ch) throws Exception { 89 | ch.pipeline().addLast( 90 | // decoded 91 | new ProtobufVarint32FrameDecoder(), 92 | new ProtobufDecoder(Agent.AgentResponse.getDefaultInstance()), 93 | // encoded 94 | new ProtobufVarint32LengthFieldPrepender(), 95 | new ProtobufEncoder(), 96 | new ConsumerRpcHandler()); 97 | } 98 | }); 99 | } 100 | 101 | public Channel getChannel(EventLoop eventLoop) throws Exception { 102 | return channelMap.get(eventLoop); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/ConsumerRpcHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.server.ConsumerAgentServer; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelInboundHandlerAdapter; 9 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 10 | import io.netty.handler.codec.http.FullHttpResponse; 11 | import io.netty.handler.codec.http.HttpHeaderNames; 12 | import io.netty.handler.codec.http.HttpHeaderValues; 13 | import io.netty.handler.codec.http.HttpResponseStatus; 14 | import io.netty.handler.codec.http.HttpVersion; 15 | import io.netty.util.ReferenceCountUtil; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | /** 20 | * Created with IntelliJ IDEA. 21 | * Description: 22 | * User: chenyifan 23 | * Date: 2018-05-24 24 | * Time: 下午11:20 25 | */ 26 | public class ConsumerRpcHandler extends ChannelInboundHandlerAdapter { 27 | 28 | private Logger logger = LoggerFactory.getLogger(ConsumerRpcHandler.class); 29 | 30 | @Override 31 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 32 | Agent.AgentResponse response = (Agent.AgentResponse) msg; 33 | Channel sourceChannel = ConsumerAgentServer.channels.get(response.getId()); 34 | if (null == sourceChannel) { 35 | logger.error("Fail to get channel : " + response.getId()); 36 | } else { 37 | FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 38 | HttpResponseStatus.OK, 39 | Unpooled.wrappedBuffer(response.getValue().getBytes())); 40 | resp.headers().set(HttpHeaderNames.CONTENT_LENGTH, resp.content().readableBytes()); 41 | resp.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); 42 | sourceChannel.writeAndFlush(resp, sourceChannel.voidPromise()); 43 | } 44 | ReferenceCountUtil.release(msg); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/DubboRpcDecoder.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.Bytes; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.RpcResponse; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.ByteToMessageDecoder; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * Created with IntelliJ IDEA. 14 | * Description: 15 | * User: chenyifan 16 | * Date: 2018-05-27 17 | * Time: 上午11:30 18 | */ 19 | public class DubboRpcDecoder extends ByteToMessageDecoder { 20 | // header length. 21 | protected static final int HEADER_LENGTH = 16; 22 | 23 | protected static final byte FLAG_EVENT = (byte) 0x20; 24 | 25 | @Override 26 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { 27 | 28 | try { 29 | do { 30 | int savedReaderIndex = byteBuf.readerIndex(); 31 | Object msg = null; 32 | try { 33 | msg = decode2(byteBuf); 34 | } catch (Exception e) { 35 | throw e; 36 | } 37 | if (msg == DecodeResult.NEED_MORE_INPUT) { 38 | byteBuf.readerIndex(savedReaderIndex); 39 | break; 40 | } 41 | 42 | list.add(msg); 43 | } while (byteBuf.isReadable()); 44 | } finally { 45 | if (byteBuf.isReadable()) { 46 | byteBuf.discardReadBytes(); 47 | } 48 | } 49 | 50 | 51 | //list.add(decode2(byteBuf)); 52 | } 53 | 54 | enum DecodeResult { 55 | NEED_MORE_INPUT, SKIP_INPUT 56 | } 57 | 58 | /** 59 | * Demo为简单起见,直接从特定字节位开始读取了的返回值,demo未做: 60 | * 1. 请求头判断 61 | * 2. 返回值类型判断 62 | * 63 | * @param byteBuf 64 | * @return 65 | */ 66 | private Object decode2(ByteBuf byteBuf){ 67 | 68 | int savedReaderIndex = byteBuf.readerIndex(); 69 | int readable = byteBuf.readableBytes(); 70 | 71 | if (readable < HEADER_LENGTH) { 72 | return DecodeResult.NEED_MORE_INPUT; 73 | } 74 | 75 | byte[] header = new byte[HEADER_LENGTH]; 76 | byteBuf.readBytes(header); 77 | byte[] dataLen = Arrays.copyOfRange(header,12,16); 78 | int len = Bytes.bytes2int(dataLen); 79 | int tt = len + HEADER_LENGTH; 80 | if (readable < tt) { 81 | return DecodeResult.NEED_MORE_INPUT; 82 | } 83 | 84 | byteBuf.readerIndex(savedReaderIndex); 85 | byte[] data = new byte[tt]; 86 | byteBuf.readBytes(data); 87 | 88 | 89 | 90 | //byte[] data = new byte[byteBuf.readableBytes()]; 91 | //byteBuf.readBytes(data); 92 | 93 | // HEADER_LENGTH + 1,忽略header & Response value type的读取,直接读取实际Return value 94 | // dubbo返回的body中,前后各有一个换行,去掉 95 | byte[] subArray = Arrays.copyOfRange(data,HEADER_LENGTH + 2, data.length -1 ); 96 | 97 | byte[] requestIdBytes = Arrays.copyOfRange(data,4,12); 98 | long requestId = Bytes.bytes2long(requestIdBytes,0); 99 | 100 | RpcResponse response = new RpcResponse(); 101 | response.setRequestId(requestId); 102 | response.setBytes(subArray); 103 | return response; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/DubboRpcEncoder.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.Bytes; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.JsonUtils; 5 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.Request; 6 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.RpcInvocation; 7 | import io.netty.buffer.ByteBuf; 8 | import io.netty.buffer.CompositeByteBuf; 9 | import io.netty.buffer.Unpooled; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import io.netty.handler.codec.MessageToByteEncoder; 12 | 13 | import java.io.ByteArrayOutputStream; 14 | import java.io.OutputStream; 15 | import java.io.OutputStreamWriter; 16 | import java.io.PrintWriter; 17 | 18 | public class DubboRpcEncoder extends MessageToByteEncoder{ 19 | // header length. 20 | protected static final int HEADER_LENGTH = 16; 21 | // magic header. 22 | protected static final short MAGIC = (short) 0xdabb; 23 | // message flag. 24 | protected static final byte FLAG_REQUEST = (byte) 0x80; 25 | protected static final byte FLAG_TWOWAY = (byte) 0x40; 26 | protected static final byte FLAG_EVENT = (byte) 0x20; 27 | 28 | @Override 29 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf buffer) throws Exception { 30 | Request req = (Request)msg; 31 | 32 | // header. 33 | byte[] header = new byte[HEADER_LENGTH]; 34 | // set magic number. 35 | Bytes.short2bytes(MAGIC, header); 36 | 37 | // set request and serialization flag. 38 | header[2] = (byte) (FLAG_REQUEST | 6); 39 | 40 | if (req.isTwoWay()) header[2] |= FLAG_TWOWAY; 41 | if (req.isEvent()) header[2] |= FLAG_EVENT; 42 | 43 | // set request id. 44 | Bytes.long2bytes(req.getId(), header, 4); 45 | 46 | // encode request data. 47 | int savedWriteIndex = buffer.writerIndex(); 48 | buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); 49 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 50 | encodeRequestData(bos, req.getData()); 51 | 52 | int len = bos.size(); 53 | buffer.writeBytes(bos.toByteArray()); 54 | Bytes.int2bytes(len, header, 12); 55 | 56 | // write 57 | buffer.writerIndex(savedWriteIndex); 58 | buffer.writeBytes(header); // write header. 59 | buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); 60 | } 61 | 62 | public void encodeRequestData(OutputStream out, Object data) throws Exception { 63 | RpcInvocation inv = (RpcInvocation)data; 64 | 65 | PrintWriter writer = new PrintWriter(new OutputStreamWriter(out)); 66 | 67 | JsonUtils.writeObject(inv.getAttachment("dubbo", "2.0.1"), writer); 68 | JsonUtils.writeObject(inv.getAttachment("path"), writer); 69 | JsonUtils.writeObject(inv.getAttachment("version"), writer); 70 | JsonUtils.writeObject(inv.getMethodName(), writer); 71 | JsonUtils.writeObject(inv.getParameterTypes(), writer); 72 | 73 | JsonUtils.writeBytes(inv.getArguments(), writer); 74 | JsonUtils.writeObject(inv.getAttachments(), writer); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/ProviderRpcClient.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.JsonUtils; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.Request; 5 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.RpcInvocation; 6 | import com.alibaba.dubbo.performance.demo.agent.server.AgentConstant; 7 | import io.netty.bootstrap.Bootstrap; 8 | import io.netty.buffer.PooledByteBufAllocator; 9 | import io.netty.channel.*; 10 | import io.netty.channel.epoll.EpollSocketChannel; 11 | import io.netty.channel.socket.SocketChannel; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.io.ByteArrayOutputStream; 16 | import java.io.OutputStreamWriter; 17 | import java.io.PrintWriter; 18 | 19 | /** 20 | * Created with IntelliJ IDEA. 21 | * Description: 22 | * User: chenyifan 23 | * Date: 2018-05-23 24 | * Time: 下午3:20 25 | */ 26 | public class ProviderRpcClient { 27 | 28 | private Logger logger = LoggerFactory.getLogger(ProviderRpcClient.class); 29 | 30 | private Channel channel; 31 | 32 | public ProviderRpcClient(Channel sourceChannel) throws InterruptedException { 33 | 34 | Bootstrap bootstrap = new Bootstrap() 35 | .group(sourceChannel.eventLoop()) 36 | .remoteAddress("127.0.0.1", AgentConstant.DUBBO_PORT) 37 | .option(ChannelOption.SO_KEEPALIVE, true) 38 | .option(ChannelOption.TCP_NODELAY, true) 39 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 40 | .channel(EpollSocketChannel.class) 41 | .handler(new ChannelInitializer() { 42 | @Override 43 | public void initChannel(SocketChannel ch) throws Exception { 44 | ChannelPipeline pipeline = ch.pipeline(); 45 | pipeline.addLast(new DubboRpcEncoder()); 46 | pipeline.addLast(new DubboRpcDecoder()); 47 | pipeline.addLast(new ProviderRpcHandler(sourceChannel)); 48 | } 49 | }); 50 | 51 | channel = bootstrap.connect().channel(); 52 | 53 | // ChannelFuture f = bootstrap.connect("127.0.0.1", Integer.valueOf(System.getProperty("dubbo.protocol.port"))); 54 | // 55 | // f.addListener(future -> channel = ((ChannelFuture) future).channel()); 56 | 57 | } 58 | 59 | 60 | public void write(Long requestId, String interfaceName, String method, String parameterTypesString, String parameter) throws Exception { 61 | 62 | RpcInvocation invocation = new RpcInvocation(); 63 | invocation.setMethodName(method); 64 | invocation.setAttachment("path", interfaceName); 65 | invocation.setParameterTypes(parameterTypesString); // Dubbo内部用"Ljava/lang/String"来表示参数类型是String 66 | 67 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 68 | PrintWriter writer = new PrintWriter(new OutputStreamWriter(out)); 69 | JsonUtils.writeObject(parameter, writer); 70 | invocation.setArguments(out.toByteArray()); 71 | 72 | Request request = new Request(requestId); 73 | request.setVersion("2.0.0"); 74 | request.setTwoWay(true); 75 | request.setData(invocation); 76 | 77 | channel.writeAndFlush(request, channel.voidPromise()); 78 | } 79 | 80 | public void deactivate() { 81 | channel.close(); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/ProviderRpcHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.RpcResponse; 5 | import com.alibaba.dubbo.performance.demo.agent.server.ProviderAgentServer; 6 | import com.google.protobuf.ByteString; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.ChannelInboundHandlerAdapter; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | import io.netty.util.ReferenceCountUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.util.regex.Pattern; 16 | 17 | /** 18 | * Created with IntelliJ IDEA. 19 | * Description: 20 | * User: chenyifan 21 | * Date: 2018-05-24 22 | * Time: 下午10:00 23 | */ 24 | public class ProviderRpcHandler extends SimpleChannelInboundHandler { 25 | 26 | private Logger logger = LoggerFactory.getLogger(ProviderRpcHandler.class); 27 | 28 | private Channel sourceChannel; 29 | 30 | ProviderRpcHandler(Channel sourceChannel) { 31 | this.sourceChannel = sourceChannel; 32 | } 33 | 34 | @Override 35 | public void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception { 36 | 37 | Agent.AgentResponse agentResponse = Agent.AgentResponse.newBuilder() 38 | .setId(response.getRequestId()) 39 | .setValueBytes(ByteString.copyFrom(response.getBytes())) 40 | .build(); 41 | 42 | sourceChannel.writeAndFlush(agentResponse, sourceChannel.voidPromise()); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/loadbalance/LoadBalance.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.loadbalance; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.registry.Endpoint; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * Description: 8 | * User: chenyifan 9 | * Date: 2018-05-29 10 | * Time: 下午2:06 11 | */ 12 | public interface LoadBalance { 13 | 14 | Endpoint select(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/loadbalance/RoundRobinLoadBalance.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.loadbalance; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.registry.Endpoint; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | /** 12 | * Created with IntelliJ IDEA. 13 | * Description: 14 | * User: chenyifan 15 | * Date: 2018-05-29 16 | * Time: 下午2:22 17 | */ 18 | public class RoundRobinLoadBalance implements LoadBalance { 19 | 20 | private Logger logger = LoggerFactory.getLogger(RoundRobinLoadBalance.class); 21 | 22 | private AtomicInteger count = new AtomicInteger(); 23 | 24 | private List index = new ArrayList<>(); 25 | 26 | private int totalWeight; 27 | 28 | public RoundRobinLoadBalance(List endpoints) { 29 | totalWeight = endpoints.stream().mapToInt(Endpoint::getWeight).sum(); 30 | 31 | for (int i = 0; i < endpoints.size(); i++) { 32 | for (int j = 0; j < endpoints.get(i).getWeight(); j++) { 33 | index.add(endpoints.get(i)); 34 | } 35 | } 36 | } 37 | 38 | @Override 39 | public Endpoint select() { 40 | 41 | int order = count.getAndIncrement() % totalWeight; 42 | 43 | return index.get(order); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/Bytes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 18 | 19 | 20 | /** 21 | * CodecUtils. 22 | */ 23 | 24 | public class Bytes { 25 | 26 | private Bytes() { 27 | } 28 | 29 | public static byte[] short2bytes(short v) { 30 | byte[] ret = {0, 0}; 31 | short2bytes(v, ret); 32 | return ret; 33 | } 34 | 35 | /** 36 | * to byte array. 37 | * 38 | * @param v value. 39 | * @param b byte array. 40 | */ 41 | public static void short2bytes(short v, byte[] b) { 42 | short2bytes(v, b, 0); 43 | } 44 | 45 | /** 46 | * to byte array. 47 | * 48 | * @param v value. 49 | * @param b byte array. 50 | */ 51 | public static void short2bytes(short v, byte[] b, int off) { 52 | b[off + 1] = (byte) v; 53 | b[off + 0] = (byte) (v >>> 8); 54 | } 55 | 56 | /** 57 | * to byte array. 58 | * 59 | * @param v value. 60 | * @param b byte array. 61 | * @param off array offset. 62 | */ 63 | public static void int2bytes(int v, byte[] b, int off) { 64 | b[off + 3] = (byte) v; 65 | b[off + 2] = (byte) (v >>> 8); 66 | b[off + 1] = (byte) (v >>> 16); 67 | b[off + 0] = (byte) (v >>> 24); 68 | } 69 | 70 | /** 71 | * to byte array. 72 | * 73 | * @param v value. 74 | * @param b byte array. 75 | * @param off array offset. 76 | */ 77 | public static void long2bytes(long v, byte[] b, int off) { 78 | b[off + 7] = (byte) v; 79 | b[off + 6] = (byte) (v >>> 8); 80 | b[off + 5] = (byte) (v >>> 16); 81 | b[off + 4] = (byte) (v >>> 24); 82 | b[off + 3] = (byte) (v >>> 32); 83 | b[off + 2] = (byte) (v >>> 40); 84 | b[off + 1] = (byte) (v >>> 48); 85 | b[off + 0] = (byte) (v >>> 56); 86 | } 87 | 88 | /** 89 | * to long. 90 | * 91 | * @param b byte array. 92 | * @param off offset. 93 | * @return long. 94 | */ 95 | public static long bytes2long(byte[] b, int off) { 96 | return ((b[off + 7] & 0xFFL) << 0) + 97 | ((b[off + 6] & 0xFFL) << 8) + 98 | ((b[off + 5] & 0xFFL) << 16) + 99 | ((b[off + 4] & 0xFFL) << 24) + 100 | ((b[off + 3] & 0xFFL) << 32) + 101 | ((b[off + 2] & 0xFFL) << 40) + 102 | ((b[off + 1] & 0xFFL) << 48) + 103 | (((long) b[off + 0]) << 56); 104 | } 105 | 106 | public static int bytes2int(byte[] b, int off) 107 | { 108 | return ((b[off + 3] & 0xFF) << 0) + 109 | ((b[off + 2] & 0xFF) << 8) + 110 | ((b[off + 1] & 0xFF) << 16) + 111 | ((b[off + 0]) << 24); 112 | } 113 | 114 | public static int bytes2int(byte[] b) 115 | { 116 | return bytes2int(b, 0); 117 | } 118 | } -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 2 | 3 | import com.alibaba.fastjson.serializer.JSONSerializer; 4 | import com.alibaba.fastjson.serializer.SerializeWriter; 5 | import com.alibaba.fastjson.serializer.SerializerFeature; 6 | 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | 10 | /** 11 | * @author ken.lj 12 | * @date 02/04/2018 13 | */ 14 | public class JsonUtils { 15 | 16 | public static void writeObject(Object obj, PrintWriter writer) throws IOException { 17 | SerializeWriter out = new SerializeWriter(); 18 | JSONSerializer serializer = new JSONSerializer(out); 19 | serializer.config(SerializerFeature.WriteEnumUsingToString, true); 20 | serializer.write(obj); 21 | out.writeTo(writer); 22 | out.close(); // for reuse SerializeWriter buf 23 | writer.println(); 24 | writer.flush(); 25 | } 26 | 27 | public static void writeBytes(byte[] b, PrintWriter writer) { 28 | writer.print(new String(b)); 29 | writer.flush(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/Request.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 2 | 3 | 4 | public class Request { 5 | private long id; 6 | private String version; 7 | private boolean twoWay = true; 8 | private boolean event = false; 9 | 10 | private Object mData; 11 | 12 | public Request(long id){ 13 | this.id = id; 14 | } 15 | 16 | public long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getVersion() { 25 | return version; 26 | } 27 | 28 | public void setVersion(String version) { 29 | this.version = version; 30 | } 31 | 32 | public boolean isTwoWay() { 33 | return twoWay; 34 | } 35 | 36 | public void setTwoWay(boolean twoWay) { 37 | this.twoWay = twoWay; 38 | } 39 | 40 | public boolean isEvent() { 41 | return event; 42 | } 43 | 44 | public void setEvent(boolean event) { 45 | this.event = event; 46 | } 47 | 48 | public Object getData() { 49 | return mData; 50 | } 51 | 52 | public void setData(Object msg) { 53 | mData = msg; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/RpcFuture.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 2 | 3 | import java.util.concurrent.*; 4 | 5 | public class RpcFuture implements Future { 6 | private CountDownLatch latch = new CountDownLatch(1); 7 | 8 | private RpcResponse response; 9 | 10 | @Override 11 | public boolean cancel(boolean mayInterruptIfRunning) { 12 | return false; 13 | } 14 | 15 | @Override 16 | public boolean isCancelled() { 17 | return false; 18 | } 19 | 20 | @Override 21 | public boolean isDone() { 22 | return false; 23 | } 24 | 25 | @Override 26 | public Object get() throws InterruptedException { 27 | //boolean b = latch.await(100, TimeUnit.MICROSECONDS); 28 | latch.await(); 29 | try { 30 | return response.getBytes(); 31 | }catch (Exception e){ 32 | e.printStackTrace(); 33 | } 34 | return "Error"; 35 | } 36 | 37 | @Override 38 | public Object get(long timeout, TimeUnit unit) throws InterruptedException { 39 | boolean b = latch.await(timeout,unit); 40 | return response.getBytes(); 41 | } 42 | 43 | public void done(RpcResponse response){ 44 | this.response = response; 45 | latch.countDown(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/RpcInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 18 | 19 | 20 | import java.io.Serializable; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * RPC Invocation. 26 | * 27 | * @serial Don't change the class name and properties. 28 | */ 29 | public class RpcInvocation implements Serializable { 30 | 31 | private static final long serialVersionUID = -4355285085441097045L; 32 | 33 | private String methodName; 34 | 35 | private String parameterTypes; 36 | 37 | private byte[] arguments; 38 | 39 | private Map attachments; 40 | 41 | public RpcInvocation() { 42 | } 43 | 44 | public String getMethodName() { 45 | return methodName; 46 | } 47 | 48 | public void setMethodName(String methodName) { 49 | this.methodName = methodName; 50 | } 51 | 52 | public String getParameterTypes() { 53 | return parameterTypes; 54 | } 55 | 56 | public void setParameterTypes(String parameterTypes) { 57 | this.parameterTypes = parameterTypes; 58 | } 59 | 60 | public byte[] getArguments() { 61 | return arguments; 62 | } 63 | 64 | public void setArguments(byte[] arguments) { 65 | this.arguments = arguments; 66 | } 67 | 68 | 69 | public void setAttachment(String key, String value) { 70 | if (attachments == null) { 71 | attachments = new HashMap<>(); 72 | } 73 | attachments.put(key, value); 74 | } 75 | 76 | public String getAttachment(String key, String defaultValue) { 77 | if (attachments == null) { 78 | return defaultValue; 79 | } 80 | String value = attachments.get(key); 81 | if (value == null || value.length() == 0) { 82 | return defaultValue; 83 | } 84 | return value; 85 | } 86 | 87 | public String getAttachment(String key) { 88 | if (attachments == null) { 89 | return null; 90 | } 91 | return attachments.get(key); 92 | } 93 | 94 | public Map getAttachments() { 95 | return attachments; 96 | } 97 | } -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/rpc/model/RpcResponse.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.rpc.model; 2 | 3 | public class RpcResponse { 4 | 5 | private long requestId; 6 | private byte[] bytes; 7 | 8 | public long getRequestId() { 9 | return requestId; 10 | } 11 | 12 | public void setRequestId(long requestId) { 13 | this.requestId = requestId; 14 | } 15 | 16 | public byte[] getBytes() { 17 | return bytes; 18 | } 19 | 20 | public void setBytes(byte[] bytes) { 21 | this.bytes = bytes; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/AgentConstant.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.server.api.AgentServer; 4 | 5 | /** 6 | * Created with IntelliJ IDEA. 7 | * Description: 8 | * User: chenyifan 9 | * Date: 2018-05-28 10 | * Time: 上午12:42 11 | */ 12 | public class AgentConstant { 13 | public static final String AGENT_TYPE = System.getProperty("type"); 14 | 15 | public static final String WEIGHT = System.getProperty("weight", "1"); 16 | 17 | public static final int SERVER_PORT = Integer.parseInt(System.getProperty("server.port")); 18 | 19 | public static final int DUBBO_PORT = Integer.valueOf(System.getProperty("dubbo.protocol.port", "80")); 20 | 21 | public static final String ETCD_URL = System.getProperty("etcd.url"); 22 | 23 | public static final boolean IS_PROVIDER = "provider".equals(AGENT_TYPE); 24 | 25 | public static final boolean IS_CONSUMER = "consumer".equals(AGENT_TYPE); 26 | 27 | public static final AgentServer AGENT_SERVER = 28 | IS_PROVIDER ? new ProviderAgentServer(SERVER_PORT) : new ConsumerAgentServer(SERVER_PORT); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/ConsumerAgentServer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.registry.EtcdRegistry; 4 | import com.alibaba.dubbo.performance.demo.agent.registry.IRegistry; 5 | import com.alibaba.dubbo.performance.demo.agent.rpc.ConsumerRpcClient; 6 | import com.alibaba.dubbo.performance.demo.agent.server.api.AgentServer; 7 | import io.netty.bootstrap.ServerBootstrap; 8 | import io.netty.buffer.PooledByteBufAllocator; 9 | import io.netty.channel.Channel; 10 | import io.netty.channel.ChannelFuture; 11 | import io.netty.channel.ChannelInitializer; 12 | import io.netty.channel.ChannelOption; 13 | import io.netty.channel.EventLoopGroup; 14 | import io.netty.channel.epoll.EpollEventLoopGroup; 15 | import io.netty.channel.epoll.EpollServerSocketChannel; 16 | import io.netty.channel.socket.SocketChannel; 17 | import io.netty.handler.codec.http.HttpObjectAggregator; 18 | import io.netty.handler.codec.http.HttpServerCodec; 19 | import io.netty.util.collection.IntObjectHashMap; 20 | import io.netty.util.collection.LongObjectHashMap; 21 | 22 | /** 23 | * Created with IntelliJ IDEA. 24 | * Description: 25 | * User: chenyifan 26 | * Date: 2018-05-23 27 | * Time: 下午2:46 28 | */ 29 | public class ConsumerAgentServer implements AgentServer { 30 | 31 | public static EventLoopGroup worker = new EpollEventLoopGroup(); 32 | 33 | public static LongObjectHashMap channels = new LongObjectHashMap<>(3000); 34 | 35 | private ServerBootstrap bootstrap; 36 | 37 | private IRegistry registry; 38 | 39 | private int port; 40 | 41 | public ConsumerAgentServer(int port) { 42 | init(); 43 | this.port = port; 44 | } 45 | 46 | private void init() { 47 | registry = new EtcdRegistry(AgentConstant.ETCD_URL); 48 | bootstrap = new ServerBootstrap(); 49 | EventLoopGroup boss = new EpollEventLoopGroup(1); 50 | ConsumerRpcClient client = new ConsumerRpcClient(registry); 51 | 52 | bootstrap.group(boss, worker) 53 | .channel(EpollServerSocketChannel.class) 54 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 55 | .childOption(ChannelOption.SO_KEEPALIVE, true) 56 | .childOption(ChannelOption.TCP_NODELAY, true) 57 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 58 | .childHandler(new ChannelInitializer() { 59 | @Override 60 | protected void initChannel(SocketChannel ch) throws Exception { 61 | ch.pipeline().addLast( 62 | new HttpServerCodec(), 63 | new HttpObjectAggregator(65536), 64 | new ConsumerAgentServerHandler(client) 65 | ); 66 | } 67 | }); 68 | } 69 | 70 | @Override 71 | public void run() { 72 | try { 73 | ChannelFuture future = bootstrap.bind(port); 74 | future.channel().closeFuture().sync(); 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } finally { 78 | bootstrap.config().group().shutdownGracefully(); 79 | bootstrap.config().childGroup().shutdownGracefully(); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/ConsumerAgentServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.ConsumerRpcClient; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import io.netty.handler.codec.http.FullHttpRequest; 9 | import io.netty.handler.codec.http.HttpMethod; 10 | import io.netty.handler.codec.http.multipart.Attribute; 11 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; 12 | import io.netty.handler.codec.http.multipart.InterfaceHttpData; 13 | import io.netty.util.ReferenceCountUtil; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.io.IOException; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * Created with IntelliJ IDEA. 24 | * Description: 25 | * User: chenyifan 26 | * Date: 2018-05-23 27 | * Time: 下午3:49 28 | */ 29 | public class ConsumerAgentServerHandler extends ChannelInboundHandlerAdapter { 30 | 31 | private Logger logger = LoggerFactory.getLogger(ConsumerAgentServerHandler.class); 32 | 33 | private static final String METHOD = "method"; 34 | private static final String INTERFACE = "interface"; 35 | private static final String PARAMETER_TYPE = "parameterTypesString"; 36 | private static final String PARAMETER = "parameter"; 37 | 38 | private ConsumerRpcClient client; 39 | 40 | private long channelId; 41 | 42 | private Channel targetChannel; 43 | 44 | public ConsumerAgentServerHandler(ConsumerRpcClient client) { 45 | this.client = client; 46 | } 47 | 48 | @Override 49 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 50 | if (msg instanceof FullHttpRequest) { 51 | Map pMap = parse((FullHttpRequest) msg); 52 | 53 | Agent.AgentRequest request = Agent.AgentRequest.newBuilder() 54 | .setId(channelId) 55 | .setMethodName(pMap.get(METHOD)) 56 | .setInterfaceName(pMap.get(INTERFACE)) 57 | .setParameterTypesString(pMap.get(PARAMETER_TYPE)) 58 | .setParameter(pMap.get(PARAMETER)).build(); 59 | 60 | targetChannel.writeAndFlush(request, targetChannel.voidPromise()); 61 | ReferenceCountUtil.release(msg); 62 | } 63 | } 64 | 65 | @Override 66 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 67 | channelId = IdGenerator.getInstance().getChannelId(); 68 | ConsumerAgentServer.channels.put(channelId, ctx.channel()); 69 | targetChannel = client.getChannel(ctx.channel().eventLoop()); 70 | } 71 | 72 | @Override 73 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 74 | ctx.fireChannelInactive(); 75 | ConsumerAgentServer.channels.remove(channelId); 76 | } 77 | 78 | private Map parse(FullHttpRequest fullReq) throws IOException { 79 | 80 | 81 | Map parmMap = new HashMap<>(); 82 | 83 | 84 | HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(fullReq); 85 | decoder.offer(fullReq); 86 | 87 | List paramList = decoder.getBodyHttpDatas(); 88 | 89 | for (InterfaceHttpData param : paramList) { 90 | 91 | Attribute data = (Attribute) param; 92 | parmMap.put(data.getName(), data.getValue()); 93 | } 94 | decoder.cleanFiles(); 95 | decoder.destroy(); 96 | 97 | return parmMap; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/IdGenerator.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | /** 7 | * Created with IntelliJ IDEA. 8 | * Description: 9 | * User: chenyifan 10 | * Date: 2018-06-06 11 | * Time: 下午5:25 12 | */ 13 | public class IdGenerator { 14 | private AtomicLong channelId; 15 | private AtomicLong requestId; 16 | 17 | 18 | private static IdGenerator instance = new IdGenerator(); 19 | 20 | public static IdGenerator getInstance() { 21 | return instance; 22 | } 23 | 24 | public long getChannelId() { 25 | return channelId.incrementAndGet(); 26 | } 27 | 28 | public long getRequestId() { 29 | return requestId.incrementAndGet(); 30 | } 31 | 32 | private IdGenerator() { 33 | channelId = new AtomicLong(); 34 | requestId = new AtomicLong(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/ProviderAgentServer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.registry.EtcdRegistry; 5 | import com.alibaba.dubbo.performance.demo.agent.registry.IRegistry; 6 | import com.alibaba.dubbo.performance.demo.agent.rpc.ProviderRpcClient; 7 | import com.alibaba.dubbo.performance.demo.agent.server.api.AgentServer; 8 | import io.netty.bootstrap.ServerBootstrap; 9 | import io.netty.buffer.PooledByteBufAllocator; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelFuture; 12 | import io.netty.channel.ChannelInitializer; 13 | import io.netty.channel.ChannelOption; 14 | import io.netty.channel.EventLoopGroup; 15 | import io.netty.channel.epoll.EpollEventLoopGroup; 16 | import io.netty.channel.epoll.EpollServerSocketChannel; 17 | import io.netty.channel.socket.SocketChannel; 18 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 19 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 20 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 21 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 22 | import io.netty.util.collection.IntObjectHashMap; 23 | import io.netty.util.collection.LongObjectHashMap; 24 | 25 | /** 26 | * Created with IntelliJ IDEA. 27 | * Description: 28 | * User: chenyifan 29 | * Date: 2018-05-23 30 | * Time: 下午2:34 31 | */ 32 | public class ProviderAgentServer implements AgentServer { 33 | 34 | public static EventLoopGroup worker = new EpollEventLoopGroup(); 35 | 36 | public static LongObjectHashMap channels = new LongObjectHashMap<>(); 37 | 38 | private ServerBootstrap bootstrap; 39 | private IRegistry registry; 40 | private int port; 41 | 42 | public ProviderAgentServer(int port) { 43 | init(); 44 | this.port = port; 45 | } 46 | 47 | private void init() { 48 | bootstrap = new ServerBootstrap(); 49 | registry = new EtcdRegistry(AgentConstant.ETCD_URL); 50 | EventLoopGroup boss = new EpollEventLoopGroup(1); 51 | // ProviderRpcClient client = new ProviderRpcClient(); 52 | 53 | bootstrap.group(boss, worker) 54 | .channel(EpollServerSocketChannel.class) 55 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 56 | .childOption(ChannelOption.TCP_NODELAY, true) 57 | .childOption(ChannelOption.SO_KEEPALIVE, true) 58 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 59 | .childHandler(new ChannelInitializer() { 60 | @Override 61 | protected void initChannel(SocketChannel ch) throws Exception { 62 | ch.pipeline().addLast( 63 | // decoded 64 | new ProtobufVarint32FrameDecoder(), 65 | new ProtobufDecoder(Agent.AgentRequest.getDefaultInstance()), 66 | // encoded 67 | new ProtobufVarint32LengthFieldPrepender(), 68 | new ProtobufEncoder(), 69 | new ProviderAgentServerHandler()); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | public void run() { 76 | try { 77 | ChannelFuture future = bootstrap.bind(port); 78 | future.channel().closeFuture().sync(); 79 | } catch (InterruptedException e) { 80 | e.printStackTrace(); 81 | } finally { 82 | bootstrap.config().group().shutdownGracefully(); 83 | bootstrap.config().childGroup().shutdownGracefully(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/ProviderAgentServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server; 2 | 3 | import com.alibaba.dubbo.performance.demo.agent.proto.Agent; 4 | import com.alibaba.dubbo.performance.demo.agent.rpc.ProviderRpcClient; 5 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.JsonUtils; 6 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.Request; 7 | import com.alibaba.dubbo.performance.demo.agent.rpc.model.RpcInvocation; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.ChannelInboundHandlerAdapter; 11 | import io.netty.util.ReferenceCountUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.io.ByteArrayOutputStream; 16 | import java.io.OutputStreamWriter; 17 | import java.io.PrintWriter; 18 | 19 | /** 20 | * Created with IntelliJ IDEA. 21 | * Description: 22 | * User: chenyifan 23 | * Date: 2018-05-23 24 | * Time: 下午3:38 25 | */ 26 | public class ProviderAgentServerHandler extends ChannelInboundHandlerAdapter { 27 | 28 | private Logger logger = LoggerFactory.getLogger(ProviderAgentServerHandler.class); 29 | 30 | private static final String REQUEST_VERSION = "2.0.0"; 31 | 32 | private ProviderRpcClient client; 33 | 34 | @Override 35 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 36 | Agent.AgentRequest agentRequest = (Agent.AgentRequest) msg; 37 | 38 | Long requestId = agentRequest.getId(); 39 | String interfaceName = agentRequest.getInterfaceName(); 40 | String method = agentRequest.getMethodName(); 41 | String parameterTypesString = agentRequest.getParameterTypesString(); 42 | String parameter = agentRequest.getParameter(); 43 | 44 | client.write(requestId, interfaceName, method, parameterTypesString, parameter); 45 | 46 | ReferenceCountUtil.release(msg); 47 | } 48 | 49 | @Override 50 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 51 | client = new ProviderRpcClient(ctx.channel()); 52 | } 53 | 54 | @Override 55 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 56 | ctx.fireChannelInactive(); 57 | client.deactivate(); 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/java/com/alibaba/dubbo/performance/demo/agent/server/api/AgentServer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.agent.server.api; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * Description: 6 | * User: chenyifan 7 | * Date: 2018-05-23 8 | * Time: 下午2:48 9 | */ 10 | public interface AgentServer { 11 | void run(); 12 | } 13 | -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #server.port=9000 2 | 3 | # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 4 | server.undertow.io-threads=4 5 | # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 6 | server.undertow.worker-threads=60 7 | # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 8 | # 每块buffer的空间大小,越小的空间被利用越充分 9 | server.undertow.buffer-size=1024 10 | # 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region 11 | server.undertow.buffers-per-region=1024 12 | # 是否分配的直接内存 13 | server.undertow.direct-buffers=true -------------------------------------------------------------------------------- /agent-v2/mesh-agent/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 10 | 11 | 12 | 13 | 14 | ${LOG_HOME}/agent.log 15 | true 16 | 17 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /agent-v2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | dubbo-mesh 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | mesh-agent 13 | 14 | 15 | 16 | 17 | 4.0.35.Final 18 | 1.5.7.RELEASE 19 | 4.12 20 | 21 | 1.0-SNAPSHOT 22 | UTF-8 23 | 1.8 24 | ${java.version} 25 | ${java.version} 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-dependencies 34 | ${springboot.version} 35 | pom 36 | import 37 | 38 | 39 | 40 | io.netty 41 | netty-all 42 | ${netty4.version} 43 | 44 | 45 | junit 46 | junit 47 | ${junit.version} 48 | test 49 | 50 | 51 | com.alibaba 52 | fastjson 53 | 1.2.46 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-configuration-processor 66 | true 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /agent-v2/start-agent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ETCD_HOST=etcd 4 | ETCD_PORT=2379 5 | ETCD_URL=http://$ETCD_HOST:$ETCD_PORT 6 | 7 | echo ETCD_URL = $ETCD_URL 8 | 9 | if [[ "$1" == "consumer" ]]; then 10 | echo "Starting consumer agent..." 11 | java -jar \ 12 | -Xms1536M \ 13 | -Xmx1536M \ 14 | -Dio.netty.leakDetectionLevel=disabled \ 15 | -Dio.netty.recycler.maxCapacity.default=0 \ 16 | -Dtype=consumer \ 17 | -Dserver.port=20000 \ 18 | -Detcd.url=$ETCD_URL \ 19 | -Dlogs.dir=/root/logs \ 20 | /root/dists/mesh-agent.jar 21 | elif [[ "$1" == "provider-small" ]]; then 22 | echo "Starting small provider agent..." 23 | java -jar \ 24 | -Xms1500M \ 25 | -Xmx1500M \ 26 | -Dio.netty.leakDetectionLevel=disabled \ 27 | -Dio.netty.recycler.maxCapacity.default=0 \ 28 | -Dtype=provider \ 29 | -Dweight=3 \ 30 | -Ddubbo.protocol.port=20880 \ 31 | -Dserver.port=30000 \ 32 | -Detcd.url=$ETCD_URL \ 33 | -Dlogs.dir=/root/logs \ 34 | /root/dists/mesh-agent.jar 35 | elif [[ "$1" == "provider-medium" ]]; then 36 | echo "Starting medium provider agent..." 37 | java -jar \ 38 | -Xms2000M \ 39 | -Xmx2000M \ 40 | -Dio.netty.leakDetectionLevel=disabled \ 41 | -Dio.netty.recycler.maxCapacity.default=0 \ 42 | -Dtype=provider \ 43 | -Dweight=4 \ 44 | -Ddubbo.protocol.port=20880 \ 45 | -Dserver.port=30000 \ 46 | -Detcd.url=$ETCD_URL \ 47 | -Dlogs.dir=/root/logs \ 48 | /root/dists/mesh-agent.jar 49 | elif [[ "$1" == "provider-large" ]]; then 50 | echo "Starting large provider agent..." 51 | java -jar \ 52 | -Xms2560M \ 53 | -Xmx2560M \ 54 | -Dio.netty.leakDetectionLevel=disabled \ 55 | -Dio.netty.recycler.maxCapacity.default=0 \ 56 | -Dtype=provider \ 57 | -Dweight=5 \ 58 | -Ddubbo.protocol.port=20880 \ 59 | -Dserver.port=30000 \ 60 | -Detcd.url=$ETCD_URL \ 61 | -Dlogs.dir=/root/logs \ 62 | /root/dists/mesh-agent.jar 63 | else 64 | echo "Unrecognized arguments, exit." 65 | exit 1 66 | fi 67 | -------------------------------------------------------------------------------- /agent-v2/start-agent.sh.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ETCD_HOST=$(ip addr show docker0 | grep 'inet\b' | awk '{print $2}' | cut -d '/' -f 1) 4 | ETCD_PORT=2379 5 | ETCD_URL=http://$ETCD_HOST:$ETCD_PORT 6 | 7 | echo ETCD_URL = $ETCD_URL 8 | 9 | if [[ "$1" == "consumer" ]]; then 10 | echo "Starting consumer agent..." 11 | # Your command to start consumer agent 12 | elif [[ "$1" == "provider-small" ]]; then 13 | echo "Starting small provider agent..." 14 | # Your command to start provider agent 15 | elif [[ "$1" == "provider-medium" ]]; then 16 | echo "Starting medium provider agent..." 17 | # Your command to start provider agent 18 | elif [[ "$1" == "provider-large" ]]; then 19 | echo "Starting large provider agent..." 20 | # Your command to start provider agent 21 | else 22 | echo "Unrecognized arguments, exit." 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /agent/.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | !.mvn/wrapper/* 5 | *.war 6 | *.zip 7 | *.tar 8 | *.tar.gz 9 | 10 | # eclipse ignore 11 | .settings/ 12 | .project 13 | .classpath 14 | 15 | # idea ignore 16 | .idea/ 17 | *.ipr 18 | *.iml 19 | *.iws 20 | 21 | # temp ignore 22 | *.log 23 | *.cache 24 | *.diff 25 | *.patch 26 | *.tmp 27 | 28 | # system ignore 29 | .DS_Store 30 | Thumbs.db 31 | -------------------------------------------------------------------------------- /agent/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM runner-container 2 | COPY ./consumer-agent-netty/target/consumer-agent-netty-1.0.jar /root/dists/consumer-agent.jar 3 | COPY ./provider-agent-netty/target/provider-agent-netty-1.0.jar /root/dists/provider-agent.jar 4 | COPY start-agent.sh /usr/local/bin 5 | 6 | RUN set -ex \ 7 | && chmod a+x /usr/local/bin/start-agent.sh \ 8 | && mkdir -p /root/logs 9 | 10 | EXPOSE 8087 11 | ENTRYPOINT ["docker-entrypoint.sh"] -------------------------------------------------------------------------------- /agent/Pipfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelloYym/mesh-agent/846bc419703bb70aff36b4791a2cbb31137266fc/agent/Pipfile -------------------------------------------------------------------------------- /agent/consumer-agent-netty/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dubbo-mesh 5 | com.alibaba 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | me.yangym 10 | consumer-agent-netty 11 | 1.0 12 | 13 | 14 | 15 | maven-shade-plugin 16 | 2.1 17 | 18 | 19 | package 20 | 21 | shade 22 | 23 | 24 | 25 | 26 | server.ConsumerAgentServer 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | junit 38 | junit 39 | 4.12 40 | test 41 | 42 | 43 | hamcrest-core 44 | org.hamcrest 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dubbo-mesh 7 | com.alibaba 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | me.yangym 13 | consumer-agent-netty 14 | 1.0 15 | 16 | 17 | 18 | 19 | io.netty 20 | netty-all 21 | 4.1.12.Final 22 | 23 | 24 | com.alibaba 25 | fastjson 26 | 27 | 28 | log4j 29 | log4j 30 | 1.2.17 31 | 32 | 33 | 34 | junit 35 | junit 36 | test 37 | 38 | 39 | org.apache.httpcomponents 40 | httpclient 41 | 42 | 43 | com.squareup.okhttp3 44 | okhttp 45 | 3.10.0 46 | 47 | 48 | com.coreos 49 | jetcd-core 50 | 0.0.1 51 | 52 | 53 | io.netty 54 | netty-codec-http2 55 | 56 | 57 | io.netty 58 | netty-handler-proxy 59 | 60 | 61 | 62 | 63 | 64 | com.google.protobuf 65 | protobuf-java 66 | 3.5.1 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-shade-plugin 75 | 2.1 76 | 77 | 78 | package 79 | 80 | shade 81 | 82 | 83 | 84 | 86 | server.ConsumerAgentServer 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/communication/ProviderAgentClient.java: -------------------------------------------------------------------------------- 1 | package communication; 2 | 3 | import io.netty.channel.*; 4 | import io.netty.channel.epoll.EpollEventLoopGroup; 5 | import io.netty.channel.epoll.EpollServerSocketChannel; 6 | import io.netty.channel.epoll.EpollSocketChannel; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 9 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 10 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 11 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 12 | import registry.Endpoint; 13 | import io.netty.bootstrap.Bootstrap; 14 | import io.netty.channel.nio.NioEventLoopGroup; 15 | import io.netty.channel.socket.SocketChannel; 16 | import io.netty.channel.socket.nio.NioSocketChannel; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import registry.IRegistry; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Random; 24 | 25 | /** 26 | * Created by IntelliJ IDEA. 27 | * User: yangyuming 28 | * Date: 2018/5/24 29 | * Time: 下午9:54 30 | */ 31 | 32 | public class ProviderAgentClient { 33 | 34 | private Logger logger = LoggerFactory.getLogger(ProviderAgentClient.class); 35 | 36 | private Bootstrap bootstrap; 37 | 38 | private Random random = new Random(); 39 | 40 | private List providerChannelList = new ArrayList<>(); 41 | 42 | public ProviderAgentClient(IRegistry registry) throws Exception { 43 | 44 | this.bootstrap = new Bootstrap(); 45 | 46 | 47 | String os = System.getProperty("os.name"); 48 | if (os.equals("Mac OS X")) { 49 | bootstrap.group(new NioEventLoopGroup()); 50 | bootstrap.channel(NioSocketChannel.class); 51 | } else { 52 | bootstrap.group(new EpollEventLoopGroup()); 53 | bootstrap.channel(EpollSocketChannel.class); 54 | } 55 | 56 | 57 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true) 58 | .option(ChannelOption.TCP_NODELAY, true) 59 | .handler(new ChannelInitializer() { 60 | @Override 61 | public void initChannel(SocketChannel ch) throws Exception { 62 | ChannelPipeline pipeline = ch.pipeline(); 63 | 64 | // Decoders 65 | pipeline.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); 66 | pipeline.addLast("protobufDecoder", new ProtobufDecoder(MessageProtos.Response.getDefaultInstance())); 67 | pipeline.addLast(new ProviderAgentClientHandler()); 68 | 69 | // Encoder 70 | pipeline.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); 71 | pipeline.addLast("protobufEncoder", new ProtobufEncoder()); 72 | } 73 | }); 74 | 75 | List providerEndpointList = registry.find("com.alibaba.dubbo.performance.demo.provider.IHelloService"); 76 | 77 | logger.info(String.valueOf(providerEndpointList.size())); 78 | 79 | for (Endpoint endpoint : providerEndpointList) { 80 | int weight = endpoint.getWeight(); 81 | 82 | 83 | ChannelFuture f = bootstrap.connect(endpoint.getHost(), endpoint.getPort()); 84 | f.addListener(future -> { 85 | Channel channel = ((ChannelFuture) future).channel(); 86 | for (int i = 0; i < weight; i++) 87 | providerChannelList.add(channel); 88 | }); 89 | 90 | // for (int i = 0; i < weight; i++) { 91 | // ChannelFuture f = bootstrap.connect(endpoint.getHost(), endpoint.getPort()); 92 | // f.addListener(future -> { 93 | // Channel channel = ((ChannelFuture) future).channel(); 94 | // providerChannelList.add(channel); 95 | // }); 96 | // } 97 | } 98 | } 99 | 100 | 101 | public Channel getChannel() throws Exception { 102 | return providerChannelList.get(random.nextInt(providerChannelList.size())); 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/communication/ProviderAgentClientHandler.java: -------------------------------------------------------------------------------- 1 | package communication; 2 | 3 | import io.netty.channel.ChannelInboundHandlerAdapter; 4 | import io.netty.util.ReferenceCountUtil; 5 | import server.ConsumerAgentServer; 6 | import io.netty.buffer.Unpooled; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.SimpleChannelInboundHandler; 10 | import io.netty.handler.codec.http.*; 11 | 12 | 13 | public class ProviderAgentClientHandler extends ChannelInboundHandlerAdapter { 14 | 15 | @Override 16 | public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception { 17 | 18 | MessageProtos.Response response = (MessageProtos.Response) msg; 19 | 20 | Long requestId = response.getRequestId(); 21 | Channel channel = ConsumerAgentServer.channelMap.get(requestId); 22 | if (channel == null) { 23 | throw new Exception("request channel is null"); 24 | } 25 | ConsumerAgentServer.channelMap.remove(requestId); 26 | 27 | FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 28 | HttpResponseStatus.OK, 29 | Unpooled.wrappedBuffer(response.getContent().getBytes())); 30 | resp.headers().set(HttpHeaderNames.CONTENT_LENGTH, resp.content().readableBytes()); 31 | resp.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); 32 | channel.writeAndFlush(resp); 33 | 34 | ReferenceCountUtil.release(msg); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package communication; 4 | 5 | option java_package = "communication"; 6 | option java_outer_classname = "MessageProtos"; 7 | 8 | message Request { 9 | int64 requestId = 1; 10 | string interface = 2; 11 | string parameterTypesString = 3; 12 | string method = 4; 13 | string parameter = 5; 14 | } 15 | 16 | message Response { 17 | int64 requestId = 1; 18 | string content = 2; 19 | } -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/registry/Endpoint.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | public class Endpoint { 4 | private final String host; 5 | private final int port; 6 | private final String type; 7 | private final int weight; 8 | private final String url; 9 | 10 | 11 | 12 | Endpoint(String host, int port, String type){ 13 | this.host = host; 14 | this.port = port; 15 | this.type = type; 16 | 17 | switch(type){ 18 | case "provider-small" : 19 | this.weight = 1; 20 | break; 21 | case "provider-medium" : 22 | this.weight = 2; 23 | break; 24 | case "provider-large": 25 | this.weight = 2; 26 | break; 27 | default : 28 | this.weight = 0; 29 | } 30 | 31 | this.url = "http://" + this.host + ":" + this.port; 32 | } 33 | 34 | public String getUrl() { 35 | return url; 36 | } 37 | 38 | public String getHost() { 39 | return host; 40 | 41 | } 42 | 43 | public int getWeight() { 44 | return weight; 45 | } 46 | 47 | public String getType() { 48 | return type; 49 | } 50 | 51 | public int getPort() { 52 | return port; 53 | } 54 | 55 | public String toString(){ 56 | return host + ":" + port; 57 | } 58 | 59 | public boolean equals(Object o){ 60 | if (!(o instanceof Endpoint)){ 61 | return false; 62 | } 63 | Endpoint other = (Endpoint) o; 64 | return other.host.equals(this.host) && other.port == this.port; 65 | } 66 | 67 | public int hashCode(){ 68 | return host.hashCode() + port; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/registry/EtcdRegistry.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import com.coreos.jetcd.Client; 4 | import com.coreos.jetcd.KV; 5 | import com.coreos.jetcd.Lease; 6 | import com.coreos.jetcd.data.ByteSequence; 7 | import com.coreos.jetcd.kv.GetResponse; 8 | import com.coreos.jetcd.options.GetOption; 9 | import com.coreos.jetcd.options.PutOption; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.text.MessageFormat; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.concurrent.Executors; 17 | 18 | public class EtcdRegistry implements IRegistry{ 19 | private Logger logger = LoggerFactory.getLogger(EtcdRegistry.class); 20 | // 该EtcdRegistry没有使用etcd的Watch机制来监听etcd的事件 21 | // 添加watch,在本地内存缓存地址列表,可减少网络调用的次数 22 | // 使用的是简单的随机负载均衡,如果provider性能不一致,随机策略会影响性能 23 | 24 | private final String rootPath = "dubbomesh"; 25 | private Lease lease; 26 | private KV kv; 27 | private long leaseId; 28 | 29 | public EtcdRegistry(String registryAddress) { 30 | Client client = Client.builder().endpoints(registryAddress).build(); 31 | this.lease = client.getLeaseClient(); 32 | this.kv = client.getKVClient(); 33 | try { 34 | this.leaseId = lease.grant(30).get().getID(); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | 39 | String os = System.getProperty("os.name"); 40 | if (!os.equals("Mac OS X")) 41 | keepAlive(); 42 | 43 | String type = System.getProperty("type"); // 获取type参数 44 | if (!( "consumer".equals(type))){ 45 | // 如果是provider,去etcd注册服务 46 | try { 47 | int port = Integer.valueOf(System.getProperty("server.port")); 48 | register("com.alibaba.dubbo.performance.demo.provider.IHelloService", port, type); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | } 54 | 55 | // 向ETCD中注册服务 56 | public void register(String serviceName,int port, String type) throws Exception { 57 | // 服务注册的key为: /dubbomesh/com.some.package.IHelloService/192.168.100.100:2000 58 | String strKey = MessageFormat.format("/{0}/{1}/{2}:{3}",rootPath,serviceName,IpHelper.getHostIp(),String.valueOf(port)); 59 | ByteSequence key = ByteSequence.fromString(strKey); 60 | ByteSequence val = ByteSequence.fromString(type); // 目前只需要创建这个key,对应的value暂不使用,先留空 61 | kv.put(key,val, PutOption.newBuilder().withLeaseId(leaseId).build()).get(); 62 | logger.info("Register a new service at:" + strKey); 63 | } 64 | 65 | // 发送心跳到ETCD,表明该host是活着的 66 | private void keepAlive(){ 67 | Executors.newSingleThreadExecutor().submit( 68 | () -> { 69 | try { 70 | Lease.KeepAliveListener listener = lease.keepAlive(leaseId); 71 | listener.listen(); 72 | logger.info("KeepAlive lease:" + leaseId + "; Hex format:" + Long.toHexString(leaseId)); 73 | } catch (Exception e) { e.printStackTrace(); } 74 | } 75 | ); 76 | } 77 | 78 | public List find(String serviceName) throws Exception { 79 | 80 | String strKey = MessageFormat.format("/{0}/{1}",rootPath,serviceName); 81 | ByteSequence key = ByteSequence.fromString(strKey); 82 | GetResponse response = kv.get(key, GetOption.newBuilder().withPrefix(key).build()).get(); 83 | 84 | List endpoints = new ArrayList<>(); 85 | 86 | for (com.coreos.jetcd.data.KeyValue kv : response.getKvs()){ 87 | String s = kv.getKey().toStringUtf8(); 88 | String type = kv.getValue().toStringUtf8(); 89 | int index = s.lastIndexOf("/"); 90 | String endpointStr = s.substring(index + 1,s.length()); 91 | 92 | String host = endpointStr.split(":")[0]; 93 | int port = Integer.valueOf(endpointStr.split(":")[1]); 94 | 95 | endpoints.add(new Endpoint(host,port, type)); 96 | } 97 | return endpoints; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/registry/IRegistry.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import java.util.List; 4 | 5 | public interface IRegistry { 6 | 7 | // 注册服务 8 | void register(String serviceName, int port, String type) throws Exception; 9 | 10 | List find(String serviceName) throws Exception; 11 | } 12 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/registry/IpHelper.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import java.net.InetAddress; 4 | 5 | public class IpHelper { 6 | 7 | public static String getHostIp() throws Exception { 8 | 9 | String ip = InetAddress.getLocalHost().getHostAddress(); 10 | return ip; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/server/ConsumerAgentHttpServerHandler.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import com.google.protobuf.Message; 4 | import communication.MessageProtos; 5 | import communication.ProviderAgentClient; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandler.Sharable; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.ChannelInboundHandlerAdapter; 10 | import io.netty.handler.codec.http.FullHttpRequest; 11 | import io.netty.handler.codec.http.multipart.Attribute; 12 | import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; 13 | import io.netty.handler.codec.http.multipart.InterfaceHttpData; 14 | import io.netty.util.ReferenceCountUtil; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.io.IOException; 19 | import java.text.MessageFormat; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.concurrent.atomic.AtomicLong; 24 | 25 | 26 | /** 27 | * Created with IntelliJ IDEA. 28 | * Description: 29 | * User: chenyifan 30 | * Date: 2018-05-23 31 | * Time: 下午3:49 32 | */ 33 | 34 | @Sharable 35 | public class ConsumerAgentHttpServerHandler extends ChannelInboundHandlerAdapter { 36 | 37 | private Logger logger = LoggerFactory.getLogger(ConsumerAgentHttpServerHandler.class); 38 | 39 | private static AtomicLong requestId = new AtomicLong(); 40 | 41 | private ProviderAgentClient client; 42 | 43 | private Channel targetChannel; 44 | 45 | // private static AtomicLong constructorId = new AtomicLong(); 46 | // private static AtomicLong activeId = new AtomicLong(); 47 | 48 | ConsumerAgentHttpServerHandler(ProviderAgentClient client) { 49 | this.client = client; 50 | // Long id = constructorId.incrementAndGet(); 51 | // if (id % 100 == 0) 52 | // logger.info(MessageFormat.format("ConsumerAgentHttpServerHandler Constuctor: {0}", id.toString())); 53 | } 54 | 55 | @Override 56 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 57 | 58 | Map pMap = parse((FullHttpRequest) msg); 59 | 60 | Long id = requestId.incrementAndGet(); 61 | ConsumerAgentServer.channelMap.put(id, ctx.channel()); 62 | 63 | String interfaceName = pMap.get("interface"); 64 | String parameterTypesString = pMap.get("parameterTypesString"); 65 | String method = pMap.get("method"); 66 | String parameter = pMap.getOrDefault("parameter", ""); 67 | 68 | Message request = MessageProtos.Request.newBuilder() 69 | .setRequestId(id) 70 | .setInterface(interfaceName) 71 | .setParameterTypesString(parameterTypesString) 72 | .setMethod(method) 73 | .setParameter(parameter) 74 | .build(); 75 | 76 | // targetChannel = client.getChannel(); 77 | targetChannel.writeAndFlush(request); 78 | 79 | ReferenceCountUtil.release(msg); 80 | } 81 | 82 | @Override 83 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 84 | targetChannel = client.getChannel(); 85 | 86 | // Long id = activeId.incrementAndGet(); 87 | // if (id % 100 == 0) 88 | // logger.info(MessageFormat.format("ConsumerAgentServerHandler channelActive: {0}", id.toString())); 89 | } 90 | 91 | 92 | private Map parse(FullHttpRequest fullReq) throws IOException { 93 | 94 | Map parmMap = new HashMap<>(); 95 | 96 | HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(fullReq); 97 | decoder.offer(fullReq); 98 | 99 | List parmList = decoder.getBodyHttpDatas(); 100 | 101 | for (InterfaceHttpData parm : parmList) { 102 | Attribute data = (Attribute) parm; 103 | parmMap.put(data.getName(), data.getValue()); 104 | } 105 | return parmMap; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /agent/consumer-agent-netty/src/main/java/server/ConsumerAgentServer.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import communication.ProviderAgentClient; 4 | import io.netty.bootstrap.ServerBootstrap; 5 | import io.netty.buffer.PooledByteBufAllocator; 6 | import io.netty.channel.*; 7 | import io.netty.channel.epoll.EpollEventLoopGroup; 8 | import io.netty.channel.epoll.EpollServerSocketChannel; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.SocketChannel; 11 | import io.netty.channel.socket.nio.NioServerSocketChannel; 12 | import io.netty.handler.codec.http.HttpObjectAggregator; 13 | import io.netty.handler.codec.http.HttpServerCodec; 14 | import registry.EtcdRegistry; 15 | import registry.IRegistry; 16 | 17 | import java.util.concurrent.ConcurrentHashMap; 18 | 19 | /** 20 | * Created by IntelliJ IDEA. 21 | * User: yangyuming 22 | * Date: 2018/5/23 23 | * Time: 下午9:53 24 | */ 25 | 26 | public class ConsumerAgentServer { 27 | 28 | private int port; 29 | private IRegistry registry; 30 | private String os; 31 | 32 | public static ConcurrentHashMap channelMap = new ConcurrentHashMap<>(); 33 | 34 | private ConsumerAgentServer(int port) { 35 | this.port = port; 36 | this.os = System.getProperty("os.name"); 37 | registry = new EtcdRegistry(System.getProperty("etcd.url")); 38 | } 39 | 40 | private void run() throws Exception { 41 | 42 | ServerBootstrap bootstrap = new ServerBootstrap(); 43 | 44 | if (os.equals("Mac OS X")) { 45 | bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()); 46 | bootstrap.channel(NioServerSocketChannel.class); 47 | } else { 48 | bootstrap.group(new EpollEventLoopGroup(), new EpollEventLoopGroup()); 49 | bootstrap.channel(EpollServerSocketChannel.class); 50 | } 51 | 52 | ProviderAgentClient providerAgentClient = new ProviderAgentClient(registry); 53 | // ConsumerAgentHttpServerHandler consumerAgentServerHandler = new ConsumerAgentHttpServerHandler(providerAgentClient); 54 | 55 | bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true) 56 | .childOption(ChannelOption.TCP_NODELAY, true) 57 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 58 | .childHandler(new ChannelInitializer() { 59 | @Override 60 | protected void initChannel(SocketChannel ch) throws Exception { 61 | ch.pipeline().addLast(new HttpServerCodec()); 62 | ch.pipeline().addLast(new HttpObjectAggregator(65536)); 63 | ch.pipeline().addLast(new ConsumerAgentHttpServerHandler(providerAgentClient)); 64 | } 65 | }); 66 | 67 | 68 | try { 69 | ChannelFuture future = bootstrap.bind(port); 70 | future.channel().closeFuture().sync(); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | } finally { 74 | bootstrap.config().group().shutdownGracefully(); 75 | bootstrap.config().childGroup().shutdownGracefully(); 76 | } 77 | } 78 | 79 | 80 | public static void main(String[] args) throws Exception { 81 | int port = Integer.valueOf(System.getProperty("server.port")); 82 | new ConsumerAgentServer(port).run(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /agent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | dubbo-mesh 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | provider-agent-netty 13 | consumer-agent-netty 14 | 15 | 16 | 17 | 18 | 4.0.35.Final 19 | 1.5.7.RELEASE 20 | 4.12 21 | 22 | 1.0-SNAPSHOT 23 | UTF-8 24 | 1.8 25 | ${java.version} 26 | ${java.version} 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-dependencies 35 | ${springboot.version} 36 | pom 37 | import 38 | 39 | 40 | 41 | io.netty 42 | netty-all 43 | ${netty4.version} 44 | 45 | 46 | junit 47 | junit 48 | ${junit.version} 49 | test 50 | 51 | 52 | com.alibaba 53 | fastjson 54 | 1.2.46 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-configuration-processor 67 | true 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dubbo-mesh 5 | com.alibaba 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | me.yangym 10 | provider-agent-netty 11 | 1.0 12 | 13 | 14 | 15 | maven-shade-plugin 16 | 2.1 17 | 18 | 19 | package 20 | 21 | shade 22 | 23 | 24 | 25 | 26 | ProviderAgent 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | junit 38 | junit 39 | 4.12 40 | test 41 | 42 | 43 | hamcrest-core 44 | org.hamcrest 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dubbo-mesh 7 | com.alibaba 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | me.yangym 13 | provider-agent-netty 14 | 1.0 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-web 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-tomcat 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-undertow 32 | 33 | 34 | 35 | io.netty 36 | netty-all 37 | 4.1.12.Final 38 | 39 | 40 | com.alibaba 41 | fastjson 42 | 43 | 44 | log4j 45 | log4j 46 | 1.2.17 47 | 48 | 49 | 50 | junit 51 | junit 52 | test 53 | 54 | 55 | org.apache.httpcomponents 56 | httpclient 57 | 58 | 59 | com.squareup.okhttp3 60 | okhttp 61 | 3.10.0 62 | 63 | 64 | com.coreos 65 | jetcd-core 66 | 0.0.1 67 | 68 | 69 | io.netty 70 | netty-codec-http2 71 | 72 | 73 | io.netty 74 | netty-handler-proxy 75 | 76 | 77 | 78 | 79 | com.google.protobuf 80 | protobuf-java 81 | 3.5.1 82 | 83 | 84 | 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-shade-plugin 90 | 2.1 91 | 92 | 93 | package 94 | 95 | shade 96 | 97 | 98 | 99 | 101 | ProviderAgent 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/HashServerHandler.java: -------------------------------------------------------------------------------- 1 | import com.google.protobuf.Message; 2 | import communication.MessageProtos; 3 | import dubbo.RpcClient; 4 | import io.netty.channel.*; 5 | import io.netty.util.ReferenceCountUtil; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import registry.EtcdRegistry; 9 | import registry.IRegistry; 10 | 11 | import java.net.InetAddress; 12 | import java.text.MessageFormat; 13 | import java.util.Date; 14 | import java.util.concurrent.atomic.AtomicLong; 15 | 16 | /** 17 | * Created by yangyuming on 2018/5/23. 18 | */ 19 | public class HashServerHandler extends ChannelInboundHandlerAdapter { 20 | 21 | private Logger logger = LoggerFactory.getLogger(HashServerHandler.class); 22 | 23 | private RpcClient rpcClient = null; 24 | 25 | private static AtomicLong activeId = new AtomicLong(); 26 | 27 | 28 | @Override 29 | public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception { 30 | 31 | MessageProtos.Request request = (MessageProtos.Request) msg; 32 | Long requestId = request.getRequestId(); 33 | String interfaceName = request.getInterface(); 34 | String method = request.getMethod(); 35 | String parameterTypesString = request.getParameterTypesString(); 36 | String parameter = request.getParameter(); 37 | 38 | ChannelFuture future = rpcClient.write(requestId, interfaceName, method, parameterTypesString, parameter); 39 | 40 | ReferenceCountUtil.release(msg); 41 | } 42 | 43 | @Override 44 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 45 | Long id = activeId.incrementAndGet(); 46 | logger.info(MessageFormat.format("ProviderAgentServerHandler channelActive: {0}", id.toString())); 47 | rpcClient = new RpcClient(ctx.channel()); 48 | } 49 | 50 | @Override 51 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 52 | cause.printStackTrace(); 53 | ctx.close(); 54 | } 55 | 56 | // 模拟provider用于测试 57 | private int hash(String str) throws Exception { 58 | int hashCode = str.hashCode(); 59 | sleep(); 60 | return hashCode; 61 | } 62 | 63 | private void sleep() throws Exception { 64 | Thread.sleep((long) 50); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/ProviderAgent.java: -------------------------------------------------------------------------------- 1 | import communication.MessageProtos; 2 | import dubbo.RpcClient; 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.buffer.PooledByteBufAllocator; 5 | import io.netty.channel.*; 6 | import io.netty.channel.epoll.EpollEventLoopGroup; 7 | import io.netty.channel.epoll.EpollServerSocketChannel; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.codec.LineBasedFrameDecoder; 12 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 13 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 14 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 15 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 16 | import io.netty.handler.codec.string.LineEncoder; 17 | import io.netty.handler.codec.string.LineSeparator; 18 | import io.netty.handler.codec.string.StringDecoder; 19 | import io.netty.handler.codec.string.StringEncoder; 20 | import io.netty.util.CharsetUtil; 21 | import registry.EtcdRegistry; 22 | import registry.IRegistry; 23 | 24 | /** 25 | * Created by IntelliJ IDEA. 26 | * User: yangyuming 27 | * Date: 2018/5/23 28 | * Time: 下午9:54 29 | */ 30 | 31 | public class ProviderAgent { 32 | 33 | private int port; 34 | private IRegistry registry; 35 | private RpcClient rpcClient; 36 | private String os; 37 | 38 | public ProviderAgent(int port) { 39 | this.port = port; 40 | this.os = System.getProperty("os.name"); 41 | registry = new EtcdRegistry(System.getProperty("etcd.url")); 42 | } 43 | 44 | private void run() throws Exception { 45 | 46 | ServerBootstrap b = new ServerBootstrap(); 47 | 48 | if (os.equals("Mac OS X")) { 49 | b.group(new NioEventLoopGroup(), new NioEventLoopGroup()); 50 | b.channel(NioServerSocketChannel.class); 51 | } else { 52 | b.group(new EpollEventLoopGroup(), new EpollEventLoopGroup()); 53 | b.channel(EpollServerSocketChannel.class); 54 | } 55 | 56 | b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 57 | .childOption(ChannelOption.TCP_NODELAY, true) 58 | .childOption(ChannelOption.SO_KEEPALIVE, true) 59 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 60 | .childHandler(new ChannelInitializer() { // (4) 61 | 62 | @Override 63 | public void initChannel(SocketChannel ch) throws Exception { 64 | ChannelPipeline pipeline = ch.pipeline(); 65 | // Decoders 66 | pipeline.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); 67 | pipeline.addLast("protobufDecoder", new ProtobufDecoder(MessageProtos.Request.getDefaultInstance())); 68 | 69 | // Encoder 70 | pipeline.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); 71 | pipeline.addLast("protobufEncoder", new ProtobufEncoder()); 72 | 73 | pipeline.addLast(new HashServerHandler()); 74 | } 75 | }); 76 | 77 | try { 78 | // Bind and start to accept incoming connections. 79 | ChannelFuture f = b.bind(port).sync(); 80 | f.channel().closeFuture().sync(); 81 | } finally { 82 | b.config().group().shutdownGracefully(); 83 | b.config().childGroup().shutdownGracefully(); 84 | } 85 | } 86 | 87 | public static void main(String[] args) throws Exception { 88 | int port = Integer.valueOf(System.getProperty("server.port")); 89 | new ProviderAgent(port).run(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/DubboRpcDecoder.java: -------------------------------------------------------------------------------- 1 | package dubbo; 2 | 3 | import dubbo.model.Bytes; 4 | import dubbo.model.RpcResponse; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.ByteToMessageDecoder; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | public class DubboRpcDecoder extends ByteToMessageDecoder { 13 | // header length. 14 | protected static final int HEADER_LENGTH = 16; 15 | 16 | protected static final byte FLAG_EVENT = (byte) 0x20; 17 | 18 | @Override 19 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { 20 | 21 | try { 22 | do { 23 | int savedReaderIndex = byteBuf.readerIndex(); 24 | Object msg = null; 25 | try { 26 | msg = decode2(byteBuf); 27 | } catch (Exception e) { 28 | throw e; 29 | } 30 | if (msg == DecodeResult.NEED_MORE_INPUT) { 31 | byteBuf.readerIndex(savedReaderIndex); 32 | break; 33 | } 34 | 35 | list.add(msg); 36 | } while (byteBuf.isReadable()); 37 | } finally { 38 | if (byteBuf.isReadable()) { 39 | byteBuf.discardReadBytes(); 40 | } 41 | } 42 | 43 | 44 | //list.add(decode2(byteBuf)); 45 | } 46 | 47 | enum DecodeResult { 48 | NEED_MORE_INPUT, SKIP_INPUT 49 | } 50 | 51 | /** 52 | * Demo为简单起见,直接从特定字节位开始读取了的返回值,demo未做: 53 | * 1. 请求头判断 54 | * 2. 返回值类型判断 55 | * 56 | * @param byteBuf 57 | * @return 58 | */ 59 | private Object decode2(ByteBuf byteBuf){ 60 | 61 | int savedReaderIndex = byteBuf.readerIndex(); 62 | int readable = byteBuf.readableBytes(); 63 | 64 | if (readable < HEADER_LENGTH) { 65 | return DecodeResult.NEED_MORE_INPUT; 66 | } 67 | 68 | byte[] header = new byte[HEADER_LENGTH]; 69 | byteBuf.readBytes(header); 70 | byte[] dataLen = Arrays.copyOfRange(header,12,16); 71 | int len = Bytes.bytes2int(dataLen); 72 | int tt = len + HEADER_LENGTH; 73 | if (readable < tt) { 74 | return DecodeResult.NEED_MORE_INPUT; 75 | } 76 | 77 | byteBuf.readerIndex(savedReaderIndex); 78 | byte[] data = new byte[tt]; 79 | byteBuf.readBytes(data); 80 | 81 | 82 | 83 | //byte[] data = new byte[byteBuf.readableBytes()]; 84 | //byteBuf.readBytes(data); 85 | 86 | // HEADER_LENGTH + 1,忽略header & Response value type的读取,直接读取实际Return value 87 | // dubbo返回的body中,前后各有一个换行,去掉 88 | byte[] subArray = Arrays.copyOfRange(data,HEADER_LENGTH + 2, data.length -1 ); 89 | 90 | String s = new String(subArray); 91 | 92 | byte[] requestIdBytes = Arrays.copyOfRange(data,4,12); 93 | long requestId = Bytes.bytes2long(requestIdBytes,0); 94 | 95 | RpcResponse response = new RpcResponse(); 96 | response.setRequestId(String.valueOf(requestId)); 97 | response.setBytes(subArray); 98 | return response; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/DubboRpcEncoder.java: -------------------------------------------------------------------------------- 1 | package dubbo; 2 | 3 | 4 | import dubbo.model.Bytes; 5 | import dubbo.model.JsonUtils; 6 | import dubbo.model.Request; 7 | import dubbo.model.RpcInvocation; 8 | 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import io.netty.handler.codec.MessageToByteEncoder; 12 | 13 | import java.io.ByteArrayOutputStream; 14 | import java.io.OutputStream; 15 | import java.io.OutputStreamWriter; 16 | import java.io.PrintWriter; 17 | 18 | public class DubboRpcEncoder extends MessageToByteEncoder{ 19 | // header length. 20 | protected static final int HEADER_LENGTH = 16; 21 | // magic header. 22 | protected static final short MAGIC = (short) 0xdabb; 23 | // message flag. 24 | protected static final byte FLAG_REQUEST = (byte) 0x80; 25 | protected static final byte FLAG_TWOWAY = (byte) 0x40; 26 | protected static final byte FLAG_EVENT = (byte) 0x20; 27 | 28 | @Override 29 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf buffer) throws Exception { 30 | Request req = (Request)msg; 31 | 32 | // header. 33 | byte[] header = new byte[HEADER_LENGTH]; 34 | // set magic number. 35 | Bytes.short2bytes(MAGIC, header); 36 | 37 | // set request and serialization flag. 38 | header[2] = (byte) (FLAG_REQUEST | 6); 39 | 40 | if (req.isTwoWay()) header[2] |= FLAG_TWOWAY; 41 | if (req.isEvent()) header[2] |= FLAG_EVENT; 42 | 43 | // set request id. 44 | Bytes.long2bytes(req.getId(), header, 4); 45 | 46 | // encode request data. 47 | int savedWriteIndex = buffer.writerIndex(); 48 | buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); 49 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 50 | encodeRequestData(bos, req.getData()); 51 | 52 | int len = bos.size(); 53 | buffer.writeBytes(bos.toByteArray()); 54 | Bytes.int2bytes(len, header, 12); 55 | 56 | // write 57 | buffer.writerIndex(savedWriteIndex); 58 | buffer.writeBytes(header); // write header. 59 | buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); 60 | } 61 | 62 | public void encodeRequestData(OutputStream out, Object data) throws Exception { 63 | RpcInvocation inv = (RpcInvocation)data; 64 | 65 | PrintWriter writer = new PrintWriter(new OutputStreamWriter(out)); 66 | 67 | JsonUtils.writeObject(inv.getAttachment("dubbo", "2.0.1"), writer); 68 | JsonUtils.writeObject(inv.getAttachment("path"), writer); 69 | JsonUtils.writeObject(inv.getAttachment("version"), writer); 70 | JsonUtils.writeObject(inv.getMethodName(), writer); 71 | JsonUtils.writeObject(inv.getParameterTypes(), writer); 72 | 73 | JsonUtils.writeBytes(inv.getArguments(), writer); 74 | JsonUtils.writeObject(inv.getAttachments(), writer); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/RpcClient.java: -------------------------------------------------------------------------------- 1 | package dubbo; 2 | 3 | import dubbo.model.*; 4 | import io.netty.bootstrap.Bootstrap; 5 | import io.netty.buffer.PooledByteBufAllocator; 6 | import io.netty.channel.*; 7 | import io.netty.channel.epoll.EpollEventLoopGroup; 8 | import io.netty.channel.epoll.EpollServerSocketChannel; 9 | import io.netty.channel.epoll.EpollSocketChannel; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.SocketChannel; 12 | import io.netty.channel.socket.nio.NioServerSocketChannel; 13 | import io.netty.channel.socket.nio.NioSocketChannel; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.OutputStreamWriter; 19 | import java.io.PrintWriter; 20 | 21 | public class RpcClient { 22 | private Logger logger = LoggerFactory.getLogger(RpcClient.class); 23 | 24 | private Channel channel; 25 | 26 | public RpcClient(Channel sourceChannel) { 27 | 28 | Bootstrap bootstrap = new Bootstrap() 29 | .group(sourceChannel.eventLoop()) 30 | .option(ChannelOption.SO_KEEPALIVE, true) 31 | .option(ChannelOption.TCP_NODELAY, true) 32 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) 33 | .handler(new ChannelInitializer() { 34 | @Override 35 | public void initChannel(SocketChannel ch) throws Exception { 36 | ChannelPipeline pipeline = ch.pipeline(); 37 | pipeline.addLast(new DubboRpcEncoder()); 38 | pipeline.addLast(new DubboRpcDecoder()); 39 | pipeline.addLast(new RpcClientHandler(sourceChannel)); 40 | } 41 | }); 42 | 43 | String os = System.getProperty("os.name"); 44 | if (os.equals("Mac OS X")) { 45 | bootstrap.channel(NioSocketChannel.class); 46 | } else { 47 | bootstrap.channel(EpollSocketChannel.class); 48 | } 49 | 50 | ChannelFuture f = bootstrap.connect("127.0.0.1", Integer.valueOf(System.getProperty("dubbo.protocol.port"))); 51 | 52 | f.addListener(future -> channel = ((ChannelFuture) future).channel()); 53 | } 54 | 55 | public ChannelFuture write(Long requestId, String interfaceName, String method, String parameterTypesString, String parameter) throws Exception { 56 | 57 | RpcInvocation invocation = new RpcInvocation(); 58 | invocation.setMethodName(method); 59 | invocation.setAttachment("path", interfaceName); 60 | invocation.setParameterTypes(parameterTypesString); // Dubbo内部用"Ljava/lang/String"来表示参数类型是String 61 | 62 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 63 | PrintWriter writer = new PrintWriter(new OutputStreamWriter(out)); 64 | JsonUtils.writeObject(parameter, writer); 65 | invocation.setArguments(out.toByteArray()); 66 | 67 | Request request = new Request(); 68 | request.setId(requestId); 69 | request.setVersion("2.0.0"); 70 | request.setTwoWay(true); 71 | request.setData(invocation); 72 | 73 | return channel.writeAndFlush(request); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/RpcClientHandler.java: -------------------------------------------------------------------------------- 1 | package dubbo; 2 | 3 | import com.google.protobuf.Message; 4 | import communication.MessageProtos; 5 | import dubbo.model.RpcResponse; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.SimpleChannelInboundHandler; 9 | import io.netty.util.ReferenceCountUtil; 10 | 11 | public class RpcClientHandler extends SimpleChannelInboundHandler { 12 | 13 | private Channel sourceChannel; 14 | 15 | RpcClientHandler(Channel sourceChannel) { 16 | this.sourceChannel = sourceChannel; 17 | } 18 | 19 | @Override 20 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse rpcResponse) { 21 | String requestId = rpcResponse.getRequestId(); 22 | String content = new String(rpcResponse.getBytes()); 23 | 24 | Message response = MessageProtos.Response.newBuilder() 25 | .setRequestId(Integer.valueOf(requestId)) 26 | .setContent(content) 27 | .build(); 28 | 29 | // 考虑不flush 30 | sourceChannel.writeAndFlush(response); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/Bytes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package dubbo.model; 18 | 19 | 20 | /** 21 | * CodecUtils. 22 | */ 23 | 24 | public class Bytes { 25 | 26 | private Bytes() { 27 | } 28 | 29 | /** 30 | * to byte array. 31 | * 32 | * @param v value. 33 | * @param b byte array. 34 | */ 35 | public static void short2bytes(short v, byte[] b) { 36 | short2bytes(v, b, 0); 37 | } 38 | 39 | /** 40 | * to byte array. 41 | * 42 | * @param v value. 43 | * @param b byte array. 44 | */ 45 | public static void short2bytes(short v, byte[] b, int off) { 46 | b[off + 1] = (byte) v; 47 | b[off + 0] = (byte) (v >>> 8); 48 | } 49 | 50 | /** 51 | * to byte array. 52 | * 53 | * @param v value. 54 | * @param b byte array. 55 | * @param off array offset. 56 | */ 57 | public static void int2bytes(int v, byte[] b, int off) { 58 | b[off + 3] = (byte) v; 59 | b[off + 2] = (byte) (v >>> 8); 60 | b[off + 1] = (byte) (v >>> 16); 61 | b[off + 0] = (byte) (v >>> 24); 62 | } 63 | 64 | /** 65 | * to byte array. 66 | * 67 | * @param v value. 68 | * @param b byte array. 69 | * @param off array offset. 70 | */ 71 | public static void long2bytes(long v, byte[] b, int off) { 72 | b[off + 7] = (byte) v; 73 | b[off + 6] = (byte) (v >>> 8); 74 | b[off + 5] = (byte) (v >>> 16); 75 | b[off + 4] = (byte) (v >>> 24); 76 | b[off + 3] = (byte) (v >>> 32); 77 | b[off + 2] = (byte) (v >>> 40); 78 | b[off + 1] = (byte) (v >>> 48); 79 | b[off + 0] = (byte) (v >>> 56); 80 | } 81 | 82 | /** 83 | * to long. 84 | * 85 | * @param b byte array. 86 | * @param off offset. 87 | * @return long. 88 | */ 89 | public static long bytes2long(byte[] b, int off) { 90 | return ((b[off + 7] & 0xFFL) << 0) + 91 | ((b[off + 6] & 0xFFL) << 8) + 92 | ((b[off + 5] & 0xFFL) << 16) + 93 | ((b[off + 4] & 0xFFL) << 24) + 94 | ((b[off + 3] & 0xFFL) << 32) + 95 | ((b[off + 2] & 0xFFL) << 40) + 96 | ((b[off + 1] & 0xFFL) << 48) + 97 | (((long) b[off + 0]) << 56); 98 | } 99 | 100 | public static int bytes2int(byte[] b, int off) 101 | { 102 | return ((b[off + 3] & 0xFF) << 0) + 103 | ((b[off + 2] & 0xFF) << 8) + 104 | ((b[off + 1] & 0xFF) << 16) + 105 | ((b[off + 0]) << 24); 106 | } 107 | 108 | public static int bytes2int(byte[] b) 109 | { 110 | return bytes2int(b, 0); 111 | } 112 | } -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package dubbo.model; 2 | 3 | import com.alibaba.fastjson.serializer.JSONSerializer; 4 | import com.alibaba.fastjson.serializer.SerializeWriter; 5 | import com.alibaba.fastjson.serializer.SerializerFeature; 6 | 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | 10 | /** 11 | * @author ken.lj 12 | * @date 02/04/2018 13 | */ 14 | public class JsonUtils { 15 | 16 | public static void writeObject(Object obj, PrintWriter writer) throws IOException { 17 | SerializeWriter out = new SerializeWriter(); 18 | JSONSerializer serializer = new JSONSerializer(out); 19 | serializer.config(SerializerFeature.WriteEnumUsingToString, true); 20 | serializer.write(obj); 21 | out.writeTo(writer); 22 | out.close(); // for reuse SerializeWriter buf 23 | writer.println(); 24 | writer.flush(); 25 | } 26 | 27 | public static void writeBytes(byte[] b, PrintWriter writer) { 28 | writer.print(new String(b)); 29 | writer.flush(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/Request.java: -------------------------------------------------------------------------------- 1 | package dubbo.model; 2 | 3 | 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | public class Request { 7 | private long id; 8 | private String interfaceName = "com.alibaba.dubbo.performance.demo.provider.IHelloService"; 9 | private String methodName = "hash"; 10 | private String dubboVersion = "2.6.0"; 11 | private String version = "0.0.0"; 12 | private String parameterTypesString = "Ljava/lang/String;"; 13 | private Object[] args; 14 | private boolean twoWay = true; 15 | private boolean event = false; 16 | 17 | private Object mData; 18 | 19 | public long getId() { 20 | return id; 21 | } 22 | 23 | public void setId(long id) { 24 | this.id = id; 25 | } 26 | 27 | public String getInterfaceName() { 28 | return interfaceName; 29 | } 30 | 31 | public void setInterfaceName(String interfaceName) { 32 | this.interfaceName = interfaceName; 33 | } 34 | 35 | public String getDubboVersion() { 36 | return dubboVersion; 37 | } 38 | 39 | public void setDubboVersion(String dubboVersion) { 40 | this.dubboVersion = dubboVersion; 41 | } 42 | 43 | public String getVersion() { 44 | return version; 45 | } 46 | 47 | public void setVersion(String version) { 48 | this.version = version; 49 | } 50 | 51 | public String getParameterTypesString() { 52 | return parameterTypesString; 53 | } 54 | 55 | public void setParameterTypesString(String parameterTypesString) { 56 | this.parameterTypesString = parameterTypesString; 57 | } 58 | 59 | public Object[] getArgs() { 60 | return args; 61 | } 62 | 63 | public void setArgs(Object[] args) { 64 | this.args = args; 65 | } 66 | 67 | public boolean isTwoWay() { 68 | return twoWay; 69 | } 70 | 71 | public void setTwoWay(boolean twoWay) { 72 | this.twoWay = twoWay; 73 | } 74 | 75 | public boolean isEvent() { 76 | return event; 77 | } 78 | 79 | public void setEvent(boolean event) { 80 | this.event = event; 81 | } 82 | 83 | public String getMethodName() { 84 | return methodName; 85 | } 86 | 87 | public void setMethodName(String methodName) { 88 | this.methodName = methodName; 89 | } 90 | 91 | public Object getData() { 92 | return mData; 93 | } 94 | 95 | public void setData(Object msg) { 96 | mData = msg; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/RpcFuture.java: -------------------------------------------------------------------------------- 1 | package dubbo.model; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.concurrent.Future; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public class RpcFuture implements Future { 8 | private CountDownLatch latch = new CountDownLatch(1); 9 | 10 | private RpcResponse response; 11 | 12 | @Override 13 | public boolean cancel(boolean mayInterruptIfRunning) { 14 | return false; 15 | } 16 | 17 | @Override 18 | public boolean isCancelled() { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean isDone() { 24 | return false; 25 | } 26 | 27 | @Override 28 | public Object get() throws InterruptedException { 29 | //boolean b = latch.await(100, TimeUnit.MICROSECONDS); 30 | latch.await(); 31 | try { 32 | return response.getBytes(); 33 | }catch (Exception e){ 34 | e.printStackTrace(); 35 | } 36 | return "Error"; 37 | } 38 | 39 | @Override 40 | public Object get(long timeout, TimeUnit unit) throws InterruptedException { 41 | boolean b = latch.await(timeout,unit); 42 | return response.getBytes(); 43 | } 44 | 45 | public void done(RpcResponse response){ 46 | this.response = response; 47 | latch.countDown(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/RpcInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package dubbo.model; 18 | 19 | 20 | import java.io.Serializable; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * RPC Invocation. 26 | * 27 | * @serial Don't change the class name and properties. 28 | */ 29 | public class RpcInvocation implements Serializable { 30 | 31 | private static final long serialVersionUID = -4355285085441097045L; 32 | 33 | private String methodName; 34 | 35 | private String parameterTypes; 36 | 37 | private byte[] arguments; 38 | 39 | private Map attachments; 40 | 41 | public RpcInvocation() { 42 | } 43 | 44 | public String getMethodName() { 45 | return methodName; 46 | } 47 | 48 | public void setMethodName(String methodName) { 49 | this.methodName = methodName; 50 | } 51 | 52 | public String getParameterTypes() { 53 | return parameterTypes; 54 | } 55 | 56 | public void setParameterTypes(String parameterTypes) { 57 | this.parameterTypes = parameterTypes; 58 | } 59 | 60 | public byte[] getArguments() { 61 | return arguments; 62 | } 63 | 64 | public void setArguments(byte[] arguments) { 65 | this.arguments = arguments; 66 | } 67 | 68 | 69 | public void setAttachment(String key, String value) { 70 | if (attachments == null) { 71 | attachments = new HashMap<>(); 72 | } 73 | attachments.put(key, value); 74 | } 75 | 76 | public String getAttachment(String key, String defaultValue) { 77 | if (attachments == null) { 78 | return defaultValue; 79 | } 80 | String value = attachments.get(key); 81 | if (value == null || value.length() == 0) { 82 | return defaultValue; 83 | } 84 | return value; 85 | } 86 | 87 | public String getAttachment(String key) { 88 | if (attachments == null) { 89 | return null; 90 | } 91 | return attachments.get(key); 92 | } 93 | 94 | public Map getAttachments() { 95 | return attachments; 96 | } 97 | } -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/RpcRequestHolder.java: -------------------------------------------------------------------------------- 1 | package dubbo.model; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | public class RpcRequestHolder { 6 | 7 | // key: requestId value: RpcFuture 8 | private static ConcurrentHashMap processingRpc = new ConcurrentHashMap<>(); 9 | 10 | public static void put(String requestId,RpcFuture rpcFuture){ 11 | processingRpc.put(requestId,rpcFuture); 12 | } 13 | 14 | public static RpcFuture get(String requestId){ 15 | return processingRpc.get(requestId); 16 | } 17 | 18 | public static void remove(String requestId){ 19 | processingRpc.remove(requestId); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/dubbo/model/RpcResponse.java: -------------------------------------------------------------------------------- 1 | package dubbo.model; 2 | 3 | public class RpcResponse { 4 | 5 | private String requestId; 6 | private byte[] bytes; 7 | 8 | public String getRequestId() { 9 | return requestId; 10 | } 11 | 12 | public void setRequestId(String requestId) { 13 | this.requestId = requestId; 14 | } 15 | 16 | public byte[] getBytes() { 17 | return bytes; 18 | } 19 | 20 | public void setBytes(byte[] bytes) { 21 | this.bytes = bytes; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package communication; 4 | 5 | option java_package = "communication"; 6 | option java_outer_classname = "MessageProtos"; 7 | 8 | message Request { 9 | int64 requestId = 1; 10 | string interface = 2; 11 | string parameterTypesString = 3; 12 | string method = 4; 13 | string parameter = 5; 14 | } 15 | 16 | message Response { 17 | int64 requestId = 1; 18 | string content = 2; 19 | } -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/registry/Endpoint.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | public class Endpoint { 4 | private final String host; 5 | private final int port; 6 | private final String type; 7 | private final int weight; 8 | private final String url; 9 | 10 | 11 | 12 | public Endpoint(String host,int port, String type){ 13 | this.host = host; 14 | this.port = port; 15 | this.type = type; 16 | 17 | switch(type){ 18 | case "provider-small" : 19 | this.weight = 5; 20 | break; 21 | case "provider-medium" : 22 | this.weight = 8; 23 | break; 24 | case "provider-large": 25 | this.weight = 11; 26 | break; 27 | default : 28 | this.weight = 0; 29 | } 30 | 31 | this.url = "http://" + this.host + ":" + this.port; 32 | } 33 | 34 | public String getUrl() { 35 | return url; 36 | } 37 | 38 | public String getHost() { 39 | return host; 40 | 41 | } 42 | 43 | public int getWeight() { 44 | return weight; 45 | } 46 | 47 | public String getType() { 48 | return type; 49 | } 50 | 51 | public int getPort() { 52 | return port; 53 | } 54 | 55 | public String toString(){ 56 | return host + ":" + port; 57 | } 58 | 59 | public boolean equals(Object o){ 60 | if (!(o instanceof Endpoint)){ 61 | return false; 62 | } 63 | Endpoint other = (Endpoint) o; 64 | return other.host.equals(this.host) && other.port == this.port; 65 | } 66 | 67 | public int hashCode(){ 68 | return host.hashCode() + port; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/registry/EtcdRegistry.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import com.coreos.jetcd.Client; 4 | import com.coreos.jetcd.KV; 5 | import com.coreos.jetcd.Lease; 6 | import com.coreos.jetcd.data.ByteSequence; 7 | import com.coreos.jetcd.kv.GetResponse; 8 | import com.coreos.jetcd.options.GetOption; 9 | import com.coreos.jetcd.options.PutOption; 10 | import io.netty.channel.epoll.EpollEventLoopGroup; 11 | import io.netty.channel.epoll.EpollSocketChannel; 12 | import io.netty.channel.nio.NioEventLoopGroup; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.text.MessageFormat; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.concurrent.Executors; 20 | 21 | public class EtcdRegistry implements IRegistry { 22 | private Logger logger = LoggerFactory.getLogger(EtcdRegistry.class); 23 | // 该EtcdRegistry没有使用etcd的Watch机制来监听etcd的事件 24 | // 添加watch,在本地内存缓存地址列表,可减少网络调用的次数 25 | // 使用的是简单的随机负载均衡,如果provider性能不一致,随机策略会影响性能 26 | 27 | private final String rootPath = "dubbomesh"; 28 | private Lease lease; 29 | private KV kv; 30 | private long leaseId; 31 | 32 | public EtcdRegistry(String registryAddress) { 33 | Client client = Client.builder().endpoints(registryAddress).build(); 34 | this.lease = client.getLeaseClient(); 35 | this.kv = client.getKVClient(); 36 | try { 37 | this.leaseId = lease.grant(30).get().getID(); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | 42 | String os = System.getProperty("os.name"); 43 | if (!os.equals("Mac OS X")) 44 | keepAlive(); 45 | 46 | String type = System.getProperty("type"); // 获取type参数 47 | if (!("consumer".equals(type))) { 48 | // 如果是provider,去etcd注册服务 49 | 50 | try { 51 | int port = Integer.valueOf(System.getProperty("server.port")); 52 | register("com.alibaba.dubbo.performance.demo.provider.IHelloService", port, type); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | 59 | // 向ETCD中注册服务 60 | public void register(String serviceName, int port, String type) throws Exception { 61 | // 服务注册的key为: /dubbomesh/com.some.package.IHelloService/192.168.100.100:2000 62 | String strKey = MessageFormat.format("/{0}/{1}/{2}:{3}", rootPath, serviceName, IpHelper.getHostIp(), String.valueOf(port)); 63 | ByteSequence key = ByteSequence.fromString(strKey); 64 | ByteSequence val = ByteSequence.fromString(type); // 目前只需要创建这个key,对应的value暂不使用,先留空 65 | kv.put(key, val, PutOption.newBuilder().withLeaseId(leaseId).build()).get(); 66 | logger.info("Register a new service at:" + strKey); 67 | } 68 | 69 | // 发送心跳到ETCD,表明该host是活着的 70 | private void keepAlive() { 71 | Executors.newSingleThreadExecutor().submit( 72 | () -> { 73 | try { 74 | Lease.KeepAliveListener listener = lease.keepAlive(leaseId); 75 | listener.listen(); 76 | logger.info("KeepAlive lease:" + leaseId + "; Hex format:" + Long.toHexString(leaseId)); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/registry/IRegistry.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import java.util.List; 4 | 5 | public interface IRegistry { 6 | 7 | // 注册服务 8 | void register(String serviceName, int port, String type) throws Exception; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /agent/provider-agent-netty/src/main/java/registry/IpHelper.java: -------------------------------------------------------------------------------- 1 | package registry; 2 | 3 | import java.net.InetAddress; 4 | 5 | public class IpHelper { 6 | 7 | public static String getHostIp() throws Exception { 8 | 9 | String ip = InetAddress.getLocalHost().getHostAddress(); 10 | return ip; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /agent/start-agent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ETCD_HOST=etcd 4 | ETCD_PORT=2379 5 | ETCD_URL=http://$ETCD_HOST:$ETCD_PORT 6 | 7 | echo ETCD_URL = $ETCD_URL 8 | 9 | if [[ "$1" == "consumer" ]]; then 10 | echo "Starting consumer agent..." 11 | java -jar \ 12 | -Xms1536M \ 13 | -Xmx1536M \ 14 | -Dtype=consumer \ 15 | -Dserver.port=20000 \ 16 | -Detcd.url=$ETCD_URL \ 17 | -Dlogs.dir=/root/logs \ 18 | /root/dists/consumer-agent.jar 19 | elif [[ "$1" == "provider-small" ]]; then 20 | echo "Starting small provider agent..." 21 | java -jar \ 22 | -Xms512M \ 23 | -Xmx512M \ 24 | -Dtype=provider-small \ 25 | -Ddubbo.protocol.port=20880 \ 26 | -Dserver.port=30000 \ 27 | -Detcd.url=$ETCD_URL \ 28 | -Dlogs.dir=/root/logs \ 29 | /root/dists/provider-agent.jar 30 | elif [[ "$1" == "provider-medium" ]]; then 31 | echo "Starting medium provider agent..." 32 | java -jar \ 33 | -Xms1536M \ 34 | -Xmx1536M \ 35 | -Dtype=provider-medium \ 36 | -Ddubbo.protocol.port=20880 \ 37 | -Dserver.port=30000 \ 38 | -Detcd.url=$ETCD_URL \ 39 | -Dlogs.dir=/root/logs \ 40 | /root/dists/provider-agent.jar 41 | elif [[ "$1" == "provider-large" ]]; then 42 | echo "Starting large provider agent..." 43 | java -jar \ 44 | -Xms2560M \ 45 | -Xmx2560M \ 46 | -Dtype=provider-large \ 47 | -Ddubbo.protocol.port=20880 \ 48 | -Dserver.port=30000 \ 49 | -Detcd.url=$ETCD_URL \ 50 | -Dlogs.dir=/root/logs \ 51 | /root/dists/provider-agent.jar 52 | else 53 | echo "Unrecognized arguments, exit." 54 | exit 1 55 | fi 56 | -------------------------------------------------------------------------------- /agent/start-agent.sh.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ETCD_HOST=$(ip addr show docker0 | grep 'inet\b' | awk '{print $2}' | cut -d '/' -f 1) 4 | ETCD_PORT=2379 5 | ETCD_URL=http://$ETCD_HOST:$ETCD_PORT 6 | 7 | echo ETCD_URL = $ETCD_URL 8 | 9 | if [[ "$1" == "consumer" ]]; then 10 | echo "Starting consumer agent..." 11 | # Your command to start consumer agent 12 | elif [[ "$1" == "provider-small" ]]; then 13 | echo "Starting small provider agent..." 14 | # Your command to start provider agent 15 | elif [[ "$1" == "provider-medium" ]]; then 16 | echo "Starting medium provider agent..." 17 | # Your command to start provider agent 18 | elif [[ "$1" == "provider-large" ]]; then 19 | echo "Starting large provider agent..." 20 | # Your command to start provider agent 21 | else 22 | echo "Unrecognized arguments, exit." 23 | exit 1 24 | fi 25 | -------------------------------------------------------------------------------- /benchmarker/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | bootstrap.conf 4 | -------------------------------------------------------------------------------- /benchmarker/README.md: -------------------------------------------------------------------------------- 1 | # 第四界阿里中间件性能挑战赛评测环境搭建指南 2 | 3 | ## 一、前期准备 4 | 5 | 搭建此评测环境,需要准备两台主机,一台用作施压机,另一台用作被压机。假设施压机的主机名为 `g1.tianchi001.test`,然后修改 `/etc/hosts` 文件将被压机可访问的域名修改为 `.g1.tianchi001.test`,`prefix` 是任何合法的域名前缀。另外需要生成一组密钥对,使得可以从施压机以免密码的形式 `ssh` 到被压机。 6 | 7 | ### 1.1、准备施压机(以 mscOS 为例) 8 | 9 | #### 1.1.1、安装 [Homebrew](https://brew.sh/) 10 | 11 | ```bash 12 | $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 13 | ``` 14 | 15 | #### 1.1.2、安装 Python 3 16 | 17 | ```bash 18 | $ brew install python 19 | ``` 20 | 21 | **注:最新版的 Homebrew 运行 `brew install python` 命令会默认安装 Python 3。** 22 | 23 | #### 1.1.3、安装 [Pipenv](https://docs.pipenv.org/) 24 | 25 | ```bash 26 | $ brew install pipenv 27 | ``` 28 | 29 | #### 1.1.4、克隆本代码仓库 30 | 31 | ```bash 32 | $ git clone https://code.aliyun.com/middlewarerace2018/benchmarker.git ~/benchmarker 33 | ``` 34 | 35 | #### 1.1.5、创建 Python 运行环境 36 | 37 | ```bash 38 | $ cd ~/benchmarker/workflow 39 | $ pipenv install 40 | ``` 41 | 42 | #### 1.1.6、安装 wrk 43 | 44 | ```bash 45 | $ brew install wrk 46 | ``` 47 | 48 | ### 1.2、准备被压机(以 CentOS 为例) 49 | 50 | #### 1.2.1、安装 Docker 51 | 52 | 请参考官方文档 [Get Docker CE for CentOS](https://docs.docker.com/install/linux/docker-ce/centos/)。 53 | 54 | 虽然 Docker 可以以非 root 身份运行,但是本脚本并没有采用这样的运行方式,因此需要使用 `sudo` 运行 `docker` 命令。且我们默认执行 `sudo` 命令的时候是需要输入密码的,因此要在当前用户的 `home` 目录下创建一个 `.passwd` 文件,里面包含 `sudo` 命令所需要使用的密码,例如: 55 | 56 | ``` 57 | !@#qweASD 58 | <此处应有一个空行> 59 | ``` 60 | 61 | **注:密码后面需要跟随一个回车换行,详细说明请参考 `man sudo`。** 62 | 63 | ### 1.3、修改 Mock Server 64 | 65 | 打开 `~/benchmarker/mock/server.py` 修改 `do_POST` 方法中返回的数据,主要关注 `data` 字段,根据实际情况修改即可。 66 | 67 | | 字段名 | 说明 | 68 | | ----- | ---- | 69 | | teamId | 团队 ID,该字段在测试环境可以为任意数字 | 70 | | taskid | 任务 ID,该字段在测试环境可以为任意数字 | 71 | | gitpath | 项目源代码的 git 仓库地址,评测时不使用该字段,仅在代码评审的时候使用。代码仓库请使用阿里云提供的服务 http://code.aliyun.com | 72 | | imagepath | Docker 镜像地址,注意填写外网地址,且无需添加版本号。镜像仓库请使用阿里云提供的服务 http://cr.console.aliyun.com | 73 | | imagerepouser | 登录 Docker 镜像仓库的用户名,该用户名就是登录阿里云的用户名 | 74 | | imagerepopassword | 登录 Docker 镜像仓库的密码,镜像仓库的密码是在镜像仓库服务中设置的密码,不同于登录阿里云的密码 | 75 | 76 | 77 | ### 1.4、修改配置文件 78 | 79 | 1. 将 `~/benchmarker/workflow/bootstrap_samples.conf` 文件改名为 `bootstrap.conf`。 80 | 2. 将 `Host` 参数修改为 mock server 的地址,默认是 `http://localhost:3000`。 81 | 3. Token 参数可以随便取值。 82 | 4. RemoteHostUser 参数修改为被压机的登录用户(需要确保该用户能以免密码的形式 `ssh` 到被压机)。 83 | 84 | ## 二、运行 85 | 86 | ### 2.1、运行 mock server 87 | 88 | ```bash 89 | $ cd ~/benchmarker/mock 90 | $ ./server.py 91 | ``` 92 | 93 | ### 2.2、运行压测脚本 94 | 95 | ```bash 96 | $ cd ~/benchmarker/workflow 97 | $ pipenv run python bootstrap.py -p 98 | ``` 99 | 100 | **注:prefix 参数即为被压机的 hostname 前缀。** 101 | -------------------------------------------------------------------------------- /benchmarker/mock/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from http.server import BaseHTTPRequestHandler, HTTPServer 4 | 5 | 6 | class Server(BaseHTTPRequestHandler): 7 | def _set_headers(self, content_type='text/html'): 8 | self.send_response(200) 9 | self.send_header('Content-Type', content_type) 10 | self.end_headers() 11 | 12 | def do_HEAD(self): 13 | self._set_headers() 14 | 15 | def do_GET(self): 16 | self._set_headers() 17 | self.wfile.write( 18 | bytes('

hi!

', 'utf-8')) 19 | 20 | def do_POST(self): 21 | self._set_headers(content_type='application/json') 22 | self.wfile.write(bytes(""" 23 | { 24 | "errCode": 0, 25 | "errName": null, 26 | "errMsg": "success", 27 | "wrapped": true, 28 | "data": { 29 | "teamId": 1000, 30 | "taskid": 2000, 31 | "gitpath": "https://code.aliyun.com/middlewarerace2018/agent-demo.git", 32 | "imagepath": "registry.cn-hangzhou.aliyuncs.com/yym/middleware-race", 33 | "imagerepouser": "yangym@zju.edu.cn", 34 | "imagerepopassword": "yang@!#!2018" 35 | } 36 | } 37 | """, 'utf-8')) 38 | 39 | 40 | def run(server_class=HTTPServer, handler_class=Server, port=3000): 41 | server_address = ('', port) 42 | httpd = server_class(server_address, handler_class) 43 | print('Starting httpd...') 44 | httpd.serve_forever() 45 | 46 | 47 | if __name__ == "__main__": 48 | from sys import argv 49 | 50 | if len(argv) == 2: 51 | run(port=int(argv[1])) 52 | else: 53 | run() 54 | -------------------------------------------------------------------------------- /benchmarker/process.yml: -------------------------------------------------------------------------------- 1 | # Process config for PM2 2 | 3 | apps: 4 | - script: ./bootstrap.sh 5 | args: shuke 6 | cwd: scripts 7 | name: shuke 8 | restart_delay: 90000 9 | - script: ./bootstrap.sh 10 | args: beita 11 | cwd: scripts 12 | name: beita 13 | restart_delay: 90000 14 | -------------------------------------------------------------------------------- /benchmarker/scripts/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -z $1 ]]; then 6 | echo 7 | echo "Missing required arguments." 8 | echo 9 | echo " Usage: bootstrap.sh " 10 | echo 11 | exit 1 12 | fi 13 | 14 | PREFIX=$1 15 | 16 | echo "Runing benchmarker..." 17 | mkdir -p ~/workspace/$PREFIX 18 | cd ~/benchmarker/workflow 19 | pipenv run python bootstrap.py -p $PREFIX > ~/workspace/$PREFIX/benchmark.log 2>&1 20 | echo " [Done]" 21 | 22 | echo "Uploading logs..." 23 | cd ~/workspace/$PREFIX 24 | if [[ -f logs.tar.gz ]]; then 25 | gunzip logs.tar.gz 26 | tar -uf logs.tar benchmark.log 27 | gzip -f logs.tar 28 | ossutil cp -f logs.tar.gz oss://middlewarerace2018/$(cat .osspath)/logs.tar.gz 29 | echo " [Done]" 30 | fi 31 | 32 | echo "Cleaning up..." 33 | rm -f benchmark.log 34 | rm -f logs.tar.gz 35 | rm -f .osspath 36 | echo " [Done]" 37 | -------------------------------------------------------------------------------- /benchmarker/workflow/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | requests = "*" 8 | pyyaml = "*" 9 | 10 | [dev-packages] 11 | 12 | [requires] 13 | python_version = "3.6" 14 | -------------------------------------------------------------------------------- /benchmarker/workflow/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "6372dd0784e1a86c265e7637a5603fb909580c39c06d8066531bc8123648c4c1" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.6" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.python.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "certifi": { 20 | "hashes": [ 21 | "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296", 22 | "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d" 23 | ], 24 | "version": "==2018.1.18" 25 | }, 26 | "chardet": { 27 | "hashes": [ 28 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 29 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 30 | ], 31 | "version": "==3.0.4" 32 | }, 33 | "idna": { 34 | "hashes": [ 35 | "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", 36 | "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" 37 | ], 38 | "version": "==2.6" 39 | }, 40 | "pyyaml": { 41 | "hashes": [ 42 | "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", 43 | "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", 44 | "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", 45 | "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", 46 | "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", 47 | "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", 48 | "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7", 49 | "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", 50 | "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", 51 | "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", 52 | "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", 53 | "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", 54 | "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", 55 | "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269" 56 | ], 57 | "index": "pypi", 58 | "version": "==3.12" 59 | }, 60 | "requests": { 61 | "hashes": [ 62 | "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", 63 | "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" 64 | ], 65 | "index": "pypi", 66 | "version": "==2.18.4" 67 | }, 68 | "urllib3": { 69 | "hashes": [ 70 | "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", 71 | "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" 72 | ], 73 | "version": "==1.22" 74 | } 75 | }, 76 | "develop": {} 77 | } 78 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/configuration.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | 3 | DEFAULT_SECTION = 'Default' 4 | TIANCHI_SECTION = 'Tianchi' 5 | WORKSPACE_SECTION = 'Workspace' 6 | SERVICES_SECTION = 'Services' 7 | WRK_SECTION = 'Wrk' 8 | DOCKER_SECTION = 'Docker' 9 | 10 | 11 | class Configuration(): 12 | 13 | def __init__(self, prefix, config_file): 14 | self.prefix = prefix 15 | self.config = configparser.ConfigParser(allow_no_value=True) 16 | self.config.read_file(config_file) 17 | 18 | def __get_value(self, key, section=DEFAULT_SECTION): 19 | return self.config[section][key] 20 | 21 | @property 22 | def consumer_app_sha256(self): 23 | return self.__get_value('ConsumerAppSha256') 24 | 25 | @property 26 | def provider_app_sha256(self): 27 | return self.__get_value('ProviderAppSha256') 28 | 29 | @property 30 | def entrypoint_script_sha256(self): 31 | return self.__get_value('EntrypointScriptSha256') 32 | 33 | @property 34 | def access_token(self): 35 | return self.__get_value('Token', TIANCHI_SECTION) 36 | 37 | @property 38 | def race_id(self): 39 | return self.__get_value('RaceId', TIANCHI_SECTION) 40 | 41 | @property 42 | def task_fetch_url(self): 43 | tianchi_host = self.__get_value('Host', TIANCHI_SECTION) 44 | task_fetch_path = self.__get_value('TaskFetchPath', TIANCHI_SECTION) 45 | return '{}{}'.format(tianchi_host, task_fetch_path) 46 | 47 | @property 48 | def task_update_url(self): 49 | tianchi_host = self.__get_value('Host', TIANCHI_SECTION) 50 | task_update_path = self.__get_value('TaskUpdatePath', 'Tianchi') 51 | return '{}{}'.format(tianchi_host, task_update_path) 52 | 53 | @property 54 | def workspace_home(self): 55 | return self.__get_value('Home', WORKSPACE_SECTION) 56 | 57 | @property 58 | def remote_host_user(self): 59 | return self.__get_value('RemoteHostUser', WORKSPACE_SECTION) 60 | 61 | @property 62 | def remote_host_prefix(self): 63 | return self.prefix 64 | 65 | @property 66 | def max_attempts(self): 67 | return self.__get_value('MaxAttempts', SERVICES_SECTION) 68 | 69 | @property 70 | def sleep_interval(self): 71 | return self.__get_value('SleepInterval', SERVICES_SECTION) 72 | 73 | @property 74 | def wrk_threads(self): 75 | return self.__get_value('Threads', WRK_SECTION) 76 | 77 | @property 78 | def wrk_timeout(self): 79 | return self.__get_value('Timeout', WRK_SECTION) 80 | 81 | @property 82 | def warmup_duration(self): 83 | return self.__get_value('WarmupDuration', WRK_SECTION) 84 | 85 | @property 86 | def pressure_duration(self): 87 | return self.__get_value('PressureDuration', WRK_SECTION) 88 | 89 | @property 90 | def small_scale(self): 91 | return self.__get_value('SmallScale', WRK_SECTION) 92 | 93 | @property 94 | def medium_scale(self): 95 | return self.__get_value('MediumScale', WRK_SECTION) 96 | 97 | @property 98 | def large_scale(self): 99 | return self.__get_value('LargeScale', WRK_SECTION) 100 | 101 | @property 102 | def cpu_period(self): 103 | return self.__get_value('CpuPeriod', DOCKER_SECTION) 104 | 105 | @property 106 | def etcd_cpu_quota(self): 107 | return self.__get_value('EtcdCpuQuota', DOCKER_SECTION) 108 | 109 | @property 110 | def etcd_memory(self): 111 | return self.__get_value('EtcdMemory', DOCKER_SECTION) 112 | 113 | @property 114 | def small_provider_cpu_quota(self): 115 | return self.__get_value('SmallProviderCpuQuota', DOCKER_SECTION) 116 | 117 | @property 118 | def small_provider_memory(self): 119 | return self.__get_value('SmallProviderMemory', DOCKER_SECTION) 120 | 121 | @property 122 | def medium_provider_cpu_quota(self): 123 | return self.__get_value('MediumProviderCpuQuota', DOCKER_SECTION) 124 | 125 | @property 126 | def medium_provider_memory(self): 127 | return self.__get_value('MediumProviderMemory', DOCKER_SECTION) 128 | 129 | @property 130 | def large_provider_cpu_quota(self): 131 | return self.__get_value('LargeProviderCpuQuota', DOCKER_SECTION) 132 | 133 | @property 134 | def large_provider_memory(self): 135 | return self.__get_value('LargeProviderMemory', DOCKER_SECTION) 136 | 137 | @property 138 | def consumer_cpu_quota(self): 139 | return self.__get_value('ConsumerCpuQuota', DOCKER_SECTION) 140 | 141 | @property 142 | def consumer_memory(self): 143 | return self.__get_value('ConsumerMemory', DOCKER_SECTION) 144 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/model/task.py: -------------------------------------------------------------------------------- 1 | class Task(): 2 | 3 | def __init__(self, dict): 4 | self.team_id = dict['teamId'] 5 | self.task_id = dict['taskid'] 6 | self.code_path = dict['gitpath'] 7 | self.image_path = dict['imagepath'] 8 | self.docker_host = self.image_path.split('/')[0] 9 | self.docker_username = dict['imagerepouser'] 10 | self.docker_password = dict['imagerepopassword'] 11 | 12 | def __repr__(self): 13 | data = [] 14 | for k, v in self.__dict__.items(): 15 | if k == 'docker_password': 16 | v = v[:3] + '******' + v[-2:] 17 | data.append('{}={}'.format(k, v)) 18 | return '{}({})'.format(self.__class__.__name__, ', '.join(data)) 19 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/model/workspace.py: -------------------------------------------------------------------------------- 1 | import os 2 | import socket 3 | 4 | 5 | class Workspace(): 6 | 7 | def __init__(self, config, task): 8 | prefix = config.remote_host_prefix 9 | 10 | self.local = LocalHost(config, prefix, task) 11 | self.remote = RemoteHost(config, prefix, task) 12 | 13 | 14 | class LocalHost(): 15 | 16 | def __init__(self, config, prefix, task, expanduser=True): 17 | self.hostname = socket.gethostname() 18 | 19 | self.home = '{}/{}'.format(config.workspace_home, prefix) 20 | self.home = os.path.expanduser(self.home) 21 | 22 | self.lock_file = '{}/{}'.format(self.home, '.lock') 23 | self.dockerpwd_file = '{}/{}'.format(self.home, '.dockerpwd') 24 | 25 | def __repr__(self): 26 | s = ', '.join(['{}={}'.format(k, v) for k, v in self.__dict__.items()]) 27 | return '{}({})'.format(self.__class__.__name__, s) 28 | 29 | 30 | class RemoteHost(): 31 | 32 | def __init__(self, config, prefix, task): 33 | self.hostname = '{}.{}'.format(prefix, socket.gethostname()) 34 | self.user = config.remote_host_user 35 | 36 | self.home = '{}/{}'.format(config.workspace_home, prefix) 37 | self.team_home = '{}/{}'.format(self.home, task.team_id) 38 | self.task_home = '{}/{}'.format(self.team_home, task.task_id) 39 | 40 | self.lock_file = '{}/{}'.format(self.task_home, '.lock') 41 | self.dockerpwd_file = '{}/{}'.format(self.task_home, '.dockerpwd') 42 | 43 | def __repr__(self): 44 | s = ', '.join(['{}={}'.format(k, v) for k, v in self.__dict__.items()]) 45 | return '{}({})'.format(self.__class__.__name__, s) 46 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/task_agent.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import socket 3 | 4 | from benchmark.model.task import Task 5 | from benchmark.utils import rand_string 6 | from logging import getLogger 7 | 8 | 9 | class TaskAgent(): 10 | 11 | def __init__(self, config): 12 | self.config = config 13 | self.logger = getLogger(__name__) 14 | self.daemon_id = self.__get_daemon_id() 15 | 16 | def fetch_task(self): 17 | self.logger.info('>>> Fetch task.') 18 | 19 | url = self.config.task_fetch_url 20 | payload = self.__create_fetch_task_payload() 21 | try: 22 | response = self.__send_request(url, payload) 23 | 24 | if response['errCode'] != 0: 25 | self.logger.error( 26 | 'Failed to fetch task. %s', response['errMsg']) 27 | return None 28 | 29 | data = response['data'] 30 | if data is None: 31 | self.logger.info('No task fetched.') 32 | return None 33 | 34 | return Task(data) 35 | except requests.exceptions.RequestException as err: 36 | self.logger.exception('Failed to fetch task.') 37 | return None 38 | 39 | def update_task(self, task, data): 40 | self.logger.info('>>> Update task.') 41 | 42 | url = self.config.task_update_url 43 | payload = self.__create_update_task_payload(task, data) 44 | try: 45 | self.__send_request(url, payload) 46 | except requests.exceptions.RequestException as err: 47 | self.logger.exception('Failed to update task.') 48 | 49 | def __get_daemon_id(self): 50 | return '{}[{}]'.format(socket.gethostname(), rand_string(7)) 51 | 52 | def __create_fetch_task_payload(self): 53 | payload = {} 54 | payload['token'] = self.config.access_token 55 | payload['raceId'] = self.config.race_id 56 | payload['daemonid'] = self.daemon_id 57 | return payload 58 | 59 | def __create_update_task_payload(self, task, data): 60 | payload = {} 61 | payload['token'] = self.config.access_token 62 | payload['taskid'] = task.task_id 63 | payload['daemonid'] = self.daemon_id 64 | 65 | payload['status'] = data.get('status') 66 | payload['isvalid'] = data.get('is_valid') 67 | payload['message'] = data.get('message') 68 | payload['rank'] = data.get('rank') 69 | payload['scoreJson'] = data.get('scoreJson') 70 | return payload 71 | 72 | def __send_request(self, url, payload): 73 | self.logger.debug('fetch task url = %s', url) 74 | masked_payload = {**payload} 75 | masked_payload['token'] = '******' 76 | self.logger.debug('request data = %s', masked_payload) 77 | 78 | r = requests.post(url, json=payload, timeout=60) 79 | r.raise_for_status() 80 | return r.json() 81 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import socket 3 | import string 4 | 5 | 6 | def rand_string(digits, chars=string.ascii_letters + string.digits): 7 | return ''.join(random.choice(chars) for _ in range(digits)) 8 | 9 | 10 | def is_port_bound(port): 11 | port = int(port) 12 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 | try: 14 | # Try to bind to all IP addresses, this port 15 | s.bind(("", port)) 16 | # If we get here, we were able to bind successfully, 17 | # which means the port is free. 18 | except socket.error: 19 | # If we get an exception, it might be because the port is still bound 20 | # which would be bad, or maybe it is a privileged port (<1024) and we 21 | # are not running as root, or maybe the server is gone, but sockets are 22 | # still in TIME_WAIT (SO_REUSEADDR). To determine which scenario, try 23 | # to connect. 24 | try: 25 | s.connect(("127.0.0.1", port)) 26 | # If we get here, we were able to connect to something, which means 27 | # that the port is still bound. 28 | return True 29 | except socket.error: 30 | # An exception means that we couldn't connect, so a server probably 31 | # isn't still running on the port. 32 | pass 33 | finally: 34 | s.close() 35 | 36 | return False 37 | -------------------------------------------------------------------------------- /benchmarker/workflow/benchmark/wrk.lua: -------------------------------------------------------------------------------- 1 | done = function(summary, latency, requests) 2 | 3 | io.write("--------------------------\n") 4 | local durations=summary.duration / 1000000 -- 执行时间,单位是秒 5 | local errors=summary.errors.status -- http status不是200,300开头的 6 | local requests=summary.requests -- 总的请求数 7 | local valid=requests-errors -- 有效请求数=总请求数-error请求数 8 | 9 | 10 | io.write("Durations: "..string.format("%.2f",durations).."s".."\n") 11 | io.write("Requests: "..summary.requests.."\n") 12 | io.write("Avg RT: "..string.format("%.2f",latency.mean / 1000).."ms".."\n") 13 | io.write("Max RT: "..(latency.max / 1000).."ms".."\n") 14 | io.write("Min RT: "..(latency.min / 1000).."ms".."\n") 15 | io.write("Error requests: "..errors.."\n") 16 | io.write("Valid requests: "..valid.."\n") 17 | io.write("QPS: "..string.format("%.2f",valid / durations).."\n") 18 | io.write("--------------------------\n") 19 | 20 | end 21 | -------------------------------------------------------------------------------- /benchmarker/workflow/bootstrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3 2 | 3 | import argparse 4 | import logging 5 | import logging.config 6 | import yaml 7 | import sys 8 | 9 | from benchmark.configuration import Configuration 10 | from benchmark.task_agent import TaskAgent 11 | from benchmark.workflow import Workflow 12 | 13 | 14 | def bootstrap(): 15 | config = init_config() 16 | task_agent = TaskAgent(config) 17 | 18 | task = task_agent.fetch_task() 19 | logging.info('task = %s', task) 20 | if task is None: 21 | logging.info('No task to execute, exit.') 22 | sys.exit(0) 23 | 24 | workflow = Workflow(config, task) 25 | result = workflow.run() 26 | 27 | task_agent.update_task(task, result) 28 | 29 | 30 | def init_config(): 31 | parser = argparse.ArgumentParser( 32 | description='Fetch the benchmark task then deploy and run.') 33 | parser.add_argument( 34 | '-c', 35 | '--config-file', 36 | help='configuration file', 37 | default='bootstrap.conf', 38 | type=argparse.FileType('r')) 39 | parser.add_argument( 40 | '-p', 41 | '--prefix', 42 | required=True, 43 | help='remote host prefix') 44 | argv = parser.parse_args() 45 | 46 | return Configuration(argv.prefix, argv.config_file) 47 | 48 | 49 | if __name__ == '__main__': 50 | logging.config.dictConfig(yaml.load(open('logging.yml'))) 51 | bootstrap() 52 | -------------------------------------------------------------------------------- /benchmarker/workflow/logging.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | formatters: 3 | simple: 4 | format: '[%(levelname)s] %(message)s' 5 | handlers: 6 | console: 7 | class: logging.StreamHandler 8 | level: DEBUG 9 | formatter: simple 10 | stream: ext://sys.stdout 11 | root: 12 | level: DEBUG 13 | handlers: [console] 14 | -------------------------------------------------------------------------------- /services/.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | !.mvn/wrapper/* 5 | *.war 6 | *.zip 7 | *.tar 8 | *.tar.gz 9 | 10 | # eclipse ignore 11 | .settings/ 12 | .project 13 | .classpath 14 | 15 | # idea ignore 16 | .idea/ 17 | *.ipr 18 | *.iml 19 | *.iws 20 | 21 | # temp ignore 22 | *.log 23 | *.cache 24 | *.diff 25 | *.patch 26 | *.tmp 27 | 28 | # system ignore 29 | .DS_Store 30 | Thumbs.db 31 | -------------------------------------------------------------------------------- /services/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-hangzhou.aliyuncs.com/aliware2018/debian-jdk8-devel 2 | 3 | COPY . /root/workspace/services 4 | 5 | WORKDIR /root/workspace/services 6 | RUN set -ex && mvn clean package 7 | 8 | COPY docker-entrypoint.sh /usr/local/bin 9 | -------------------------------------------------------------------------------- /services/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelloYym/mesh-agent/846bc419703bb70aff36b4791a2cbb31137266fc/services/README.md -------------------------------------------------------------------------------- /services/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! -x "$(command -v start-agent.sh)" ]]; then 4 | echo "[ERROR] start-agent.sh is not executable." 5 | exit 1 6 | fi 7 | 8 | if [[ "$1" == "consumer" ]]; then 9 | echo "Starting consumer service..." 10 | nohup java -jar \ 11 | -Xms2G \ 12 | -Xmx2G \ 13 | -Dlogs.dir=/root/logs \ 14 | /root/dists/mesh-consumer.jar \ 15 | > /dev/null 2>&1 & 16 | elif [[ "$1" == "provider-small" ]]; then 17 | echo "Starting small provider service..." 18 | nohup java -jar \ 19 | -Xms1G \ 20 | -Xmx1G \ 21 | -Dlogs.dir=/root/logs \ 22 | /root/dists/mesh-provider.jar \ 23 | > /dev/null 2>&1 & 24 | elif [[ "$1" == "provider-medium" ]]; then 25 | echo "Starting medium provider service..." 26 | nohup java -jar \ 27 | -Xms2G \ 28 | -Xmx2G \ 29 | -Dlogs.dir=/root/logs \ 30 | /root/dists/mesh-provider.jar \ 31 | > /dev/null 2>&1 & 32 | elif [[ "$1" == "provider-large" ]]; then 33 | echo "Starting large provider service..." 34 | nohup java -jar \ 35 | -Xms3G \ 36 | -Xmx3G \ 37 | -Dlogs.dir=/root/logs \ 38 | /root/dists/mesh-provider.jar \ 39 | > /dev/null 2>&1 & 40 | else 41 | echo "[ERROR] Unrecognized arguments, exit." 42 | exit 1 43 | fi 44 | 45 | start-agent.sh "$@" 46 | -------------------------------------------------------------------------------- /services/mesh-consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dubbo-mesh 7 | com.alibaba 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mesh-consumer 13 | 1.0-SNAPSHOT 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-web 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-tomcat 23 | 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-undertow 30 | 31 | 32 | 33 | org.apache.commons 34 | commons-lang3 35 | 3.7 36 | 37 | 38 | 39 | org.asynchttpclient 40 | async-http-client 41 | 2.4.7 42 | 43 | 44 | 45 | junit 46 | junit 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-maven-plugin 58 | 59 | 60 | 61 | repackage 62 | 63 | 64 | 65 | 66 | true 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /services/mesh-consumer/src/main/java/com/alibaba/dubbo/performance/demo/consumer/ConsumerApp.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.consumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @SpringBootApplication 9 | public class ConsumerApp { 10 | // 启动时请添加JVM参数: 11 | // -Dlogs.dir=/path/to/your/logs/dir 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(ConsumerApp.class,args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /services/mesh-consumer/src/main/java/com/alibaba/dubbo/performance/demo/consumer/HelloController.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.consumer; 2 | 3 | import org.apache.commons.lang3.RandomStringUtils; 4 | import org.asynchttpclient.AsyncHttpClient; 5 | import org.asynchttpclient.ListenableFuture; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.context.request.async.DeferredResult; 11 | 12 | import java.util.Random; 13 | 14 | @RestController 15 | public class HelloController { 16 | 17 | private AsyncHttpClient asyncHttpClient = org.asynchttpclient.Dsl.asyncHttpClient(); 18 | 19 | private ResponseEntity ok = new ResponseEntity("OK", HttpStatus.OK); 20 | private ResponseEntity error = new ResponseEntity("ERROR", HttpStatus.INTERNAL_SERVER_ERROR); 21 | 22 | Random r = new Random(1); 23 | 24 | @RequestMapping(value = "/invoke") 25 | public DeferredResult invoke() { 26 | 27 | String str = RandomStringUtils.random(r.nextInt(1024), true, true); 28 | 29 | String url = "http://127.0.0.1:20000"; 30 | 31 | 32 | DeferredResult result = new DeferredResult<>(); 33 | 34 | org.asynchttpclient.Request request = org.asynchttpclient.Dsl.post(url) 35 | .addFormParam("interface", "com.alibaba.dubbo.performance.demo.provider.IHelloService") 36 | .addFormParam("method", "hash") 37 | .addFormParam("parameterTypesString", "Ljava/lang/String;") 38 | .addFormParam("parameter", str) 39 | .build(); 40 | 41 | ListenableFuture responseFuture = asyncHttpClient.executeRequest(request); 42 | 43 | Runnable callback = () -> { 44 | try { 45 | // 检查返回值是否正确,如果不正确返回500。有以下原因可能导致返回值不对: 46 | // 1. agent解析dubbo返回数据不对 47 | // 2. agent没有把request和dubbo的response对应起来 48 | String value = responseFuture.get().getResponseBody(); 49 | if (String.valueOf(str.hashCode()).equals(value)){ 50 | result.setResult(ok); 51 | } else { 52 | result.setResult(error); 53 | } 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | }; 58 | responseFuture.addListener(callback, null); 59 | 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /services/mesh-consumer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8087 2 | 3 | # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 4 | server.undertow.io-threads=4 5 | # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 6 | server.undertow.worker-threads=256 7 | # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 8 | # 每块buffer的空间大小,越小的空间被利用越充分 9 | server.undertow.buffer-size=1024 10 | # 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region 11 | server.undertow.buffers-per-region=1024 12 | # 是否分配的直接内存 13 | server.undertow.direct-buffers=true -------------------------------------------------------------------------------- /services/mesh-consumer/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 10 | 11 | 12 | 13 | 14 | ${LOG_HOME}/consumer.log 15 | true 16 | 17 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /services/mesh-provider/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | dubbo-mesh 7 | com.alibaba 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mesh-provider 13 | 1.0-SNAPSHOT 14 | 15 | 16 | 17 | com.alibaba 18 | dubbo 19 | 20 | 21 | com.github.sgroschupf 22 | zkclient 23 | 24 | 25 | 26 | io.netty 27 | netty-all 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-logging 33 | 34 | 35 | 36 | log4j 37 | log4j 38 | 1.2.17 39 | 40 | 41 | com.alibaba 42 | fastjson 43 | 1.2.31 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | 56 | repackage 57 | 58 | 59 | 60 | 61 | true 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/java/com/alibaba/dubbo/performance/demo/provider/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.provider; 2 | 3 | import org.springframework.context.annotation.ImportResource; 4 | 5 | @org.springframework.context.annotation.Configuration 6 | @ImportResource(locations={"classpath*:dubbo-provider.xml"}) 7 | public class Configuration { 8 | } 9 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/java/com/alibaba/dubbo/performance/demo/provider/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.provider; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Random; 8 | 9 | public class HelloService implements IHelloService { 10 | 11 | private long count; 12 | 13 | private Logger logger = LoggerFactory.getLogger(HelloService.class); 14 | 15 | public HelloService() { 16 | 17 | } 18 | 19 | @Override 20 | public int hash(String str) throws Exception { 21 | int hashCode = str.hashCode(); 22 | logger.info(++count + "_" + hashCode); 23 | sleep(50); 24 | 25 | return hashCode; 26 | } 27 | 28 | private void sleep(long duration) throws Exception { 29 | Thread.sleep(duration); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/java/com/alibaba/dubbo/performance/demo/provider/IHelloService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.provider; 2 | 3 | public interface IHelloService { 4 | int hash(String str) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/java/com/alibaba/dubbo/performance/demo/provider/ProviderApp.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dubbo.performance.demo.provider; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | @SpringBootApplication 10 | public class ProviderApp { 11 | // 启动时请添加JVM参数: 12 | // -Ddubbo.protocol.port=20889 -Ddubbo.application.qos.enable=false -Dlogs.dir=/path/to/your/logs/dir 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ProviderApp.class,args); 16 | 17 | // 不让应用在docker中退出 18 | Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> System.out.println("do something..."),1000,5, TimeUnit.SECONDS); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #server.port=8085 -------------------------------------------------------------------------------- /services/mesh-provider/src/main/resources/dubbo-provider.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /services/mesh-provider/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 10 | 11 | 12 | 13 | 14 | ${LOG_HOME}/provider.log 15 | true 16 | 17 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /services/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.alibaba 8 | dubbo-mesh 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | mesh-consumer 13 | mesh-provider 14 | 15 | 16 | 17 | 18 | 2.6.1 19 | 0.1 20 | 4.0.35.Final 21 | 1.5.7.RELEASE 22 | 4.12 23 | 24 | 1.0-SNAPSHOT 25 | UTF-8 26 | 1.8 27 | ${java.version} 28 | ${java.version} 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-dependencies 37 | ${springboot.version} 38 | pom 39 | import 40 | 41 | 42 | 43 | com.alibaba 44 | dubbo 45 | ${dubbo.version} 46 | 47 | 48 | com.github.sgroschupf 49 | zkclient 50 | ${zkclient.version} 51 | 52 | 53 | io.netty 54 | netty-all 55 | ${netty4.version} 56 | 57 | 58 | 59 | junit 60 | junit 61 | ${junit.version} 62 | test 63 | 64 | 65 | org.javassist 66 | javassist 67 | 3.20.0-GA 68 | 69 | 70 | com.alibaba 71 | fastjson 72 | 1.2.46 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-starter 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-configuration-processor 85 | true 86 | 87 | 88 | 89 | --------------------------------------------------------------------------------