From a16c8e53008efff78a3b67ad5c5c3980672f0d5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A1=B9=E5=8D=87?= <xiangsheng.gh@alibaba-inc.com>
Date: Sun, 5 May 2019 22:48:35 +0800
Subject: [PATCH] Add service module

---
 README.MD                                     |  11 +++--
 assets/service-architect.png                  | Bin 0 -> 16844 bytes
 pom.xml                                       |   1 +
 service/pom.xml                               |  33 ++++++++++++++
 service/service-api/pom.xml                   |  15 ++++++
 .../com/aliware/tianchi/HashInterface.java    |  18 ++++++++
 service/service-consumer/pom.xml              |  15 ++++++
 service/service-provider/pom.xml              |  23 ++++++++++
 .../com/aliware/tianchi/HashServiceImpl.java  |  43 ++++++++++++++++++
 .../com/aliware/tianchi/HashInterface.java    |  10 ++++
 10 files changed, 165 insertions(+), 4 deletions(-)
 create mode 100644 assets/service-architect.png
 create mode 100644 service/pom.xml
 create mode 100644 service/service-api/pom.xml
 create mode 100644 service/service-api/src/main/java/com/aliware/tianchi/HashInterface.java
 create mode 100644 service/service-consumer/pom.xml
 create mode 100644 service/service-provider/pom.xml
 create mode 100644 service/service-provider/src/main/java/com/aliware/tianchi/HashServiceImpl.java
 create mode 100644 service/src/main/java/com/aliware/tianchi/HashInterface.java

diff --git a/README.MD b/README.MD
index eba640e..5214bd2 100644
--- a/README.MD
+++ b/README.MD
@@ -14,13 +14,12 @@
 
 
 ### Apache Dubbo Gateway
-
+TBD
 
 ### 题目由来
 
 传统的负载均衡场景为单调度器模式,即中心化负载均衡:调度器负责将新到的请求立即转发至多个后端服务器中的一个。随着分布式系统的发展,这种单调度器模式在扩展性和可靠性方面的问题也愈发严重。因此,设计和实现去中心化且性能优异的负载均衡是学术和工业界的共同需求。
 
-
 ## 赛题说明
 
 按照题目提供的扩展接口,实现一套自适应负载均衡机制。要求能够具备以下能力:
@@ -29,9 +28,13 @@
 2. Provider 端能自动进行服务容量评估,当请求数量超过服务能力时,允许拒绝部分请求,以保证服务不过载。
 3. 当请求速率高于所有的 Provider 服务效率之和时,允许 Gateway( Consumer ) 拒绝服务新到请求。
 
-
 ### 架构
-TBD
+![service_architect](assets/service-architect.png)
+
+- Gateway 负责将请求转发至 Provider;
+- Provider 处理请求返回响应;
+- Provider 按照 CPU 核数和内存大小分为 Small、Medium、Large 三个规格;
+- 选手需要设计实现 Gateway 选择 Provider 的 loadbalance 算法。
 
 ### 服务
 
diff --git a/assets/service-architect.png b/assets/service-architect.png
new file mode 100644
index 0000000000000000000000000000000000000000..4df4e033f24d523160ee3c606f6852076e831830
GIT binary patch
literal 16844
zcmc)yWmuHm7dDI=pp-I0NW(BR2#9n$Ftl{Hgmg#`eT&4<B8`L$-5}k!#83j#ND2ee
zUDEG`_wRZB$MOIC9>+T$_;Ag|uC@1GYn|u0CR|NL?g<_x-o1PGo+!w}HSXPe0Ka$d
zJ{is<;K^$u!_0g4VDSoYm=<DYr}arg##`^T%V(b|<6Dnp9-N1gXgpZTxevR~!1yQ{
z8~dADwhK<0*(eVu^_!2-%;k?}m3ay3N+a*p^AqrWeuNiHFEg3s_sh`4ysRPH`KBqd
zOu`vs!xl{mUKZJ^KlQbi^gb-F)%}#Q-8yx7X*}i6v~}&b;ALI0mUY>db;*SX{{QAf
zar-<~#AEX@;b-1Gs<HfGKeL%*3U1pOL`~6Heqi822SZ!cn~}IFzFXtrQ(Z$iyvb}S
z{T!b*Q`r9Ww03Ku9%FG9kYDw7D?Yj>>)ZrW6gZu4i|KE>5L~nsJ6<P_UcBt06C7$@
z|AhW`+*Z=?rfF=?`9^f_NY@w+XW!V`GZptof2X^?n4oh|W>hIOsQ8(6y}BqcnciOK
z(zTpp8h|O*R=O@D1IHN)<+k6JDf1lnv(O=?!!@_On|C|g$5Q;K({;HUx2IH3>rLVC
zpzep71-C1^lILzLN@Y5zb!1MGgQ539_rm~eBvPKodLgL2;kR_Xkb+$;Z-=#YmfHeD
z06r4gTNE~!dN#(A=|6(2QSw%0<d}lj>*|og+2oh*d!&48t8^A5e5Oymq@?O%d)sa3
z+Q0n?9B%jhyR^0c+0AfZcer{<Sry}L197tCT0QU|(Wyc%qa2guqni%nY-#oDy~)=C
zAaD_ne|$m9a&F;7D+06Kx#n~>`wE_m{+`b7`#Bz^<E04-N3tT(rI3r!_`t<40vb*$
zVpYyHJ^V)e&N{m;)Eudsj9kT;pNDJyQ3qZ{2H6nq{9e3;=LmPz)%{twpgcC9Dsy?F
z+e-xd*TuuITlZwnPvUmj0}l!YtAlpR_8ay`Ps-X0Jb$7~C^auGsUEAQ{P>eI?0^1G
z%$8=>wYj}3-4G@lqVZqjU0C42Izz6(fX&`0GP5uL=P?|6M6m5d!~QnBAid7578L)2
z_+?<5S$8oye=ERu?I7@CqTR_mX*%F{e?4D$!{Ni|vcQv_j7wXG0dMVd1+RtryxLeI
zY(j~{KSP%*4;&}b>i1f>2O3MTz-N|{7Qgh+af?SWzO)V}Gv?pd(l3W5J;Lxu{FlO=
z>&i)|R`n^Q7uqB3G4mZqo|_cTcDSUwodHrG4+sugyaRqj*9X+_GY^T|pUfHze`=G%
zjza=V`t%DVBAo30#{jEOzg0VI2UJAf7W@n867ZNg*12V8K2``j=C`5|u(n>u|MtyW
zcj4WU)0sidpF;E~M%C`Kw0qwwmEo*VXn5dF2Lq+sZ_a6D@^{?3eXSG^7dX*;m>>F_
z*`z%#Plimty6bNVHw-Da`&!FY5KMJ9FrycR1!-6?=20z?@v5RZC%ZzS7GQxWd{~!%
zBTJxaazT83_d$yV8p*mWR8F;HN&<&MQ4o<=K{&B^@xqsZ_D4I-ue)BK(sS*ny@+EF
z0r3~HJaXyqWcF@RZrsOZkPF{hHZCH9uaK+~ODsdWq}T~SHpnc#TO<!XE4dsyQfkhH
zGc#MWU3mA~fta(8@d9=S2PvHTEKYQ9zT3V_0G;U5x_lja_BgxOy6dga-dWpinsFTm
z5)OyMYUr@Q#QenGdI*yaQ4(`z=4HR-=&iZK5ns>d$0l)Fb6soWhSg4;`ANEr!7wi5
zWSe!TlQ|=)B0T{snOaRBTN7~DYEET>5IE5Ck-=uD)-#h_1RXuj*zm#4q2geAWO9k3
zWr+N8L$McmW-X}ve>?RtEO-seS&7_?nt5+dbA&5gSd2W5C4TKuRcuQN2!x~?3KwI-
z(x(*Z#|B$KSH`(|*wDml;9@E2+-D0ZAX0kd=v+F8t+Bfrv$LFzgAa{4JOaa`>OY?)
z;iJYa(3i_J2PVsH|MeCv^;EsSq^aYBrZ$A9g$iLas-})mmw(Ci^@VyOM9M}hx=0ZO
z{-lI$Vuw?s1=2R=uIGcJTX6=uC0v7~ws%S(Qfe<x8@Rk>SJ>lP${<8wF!l&J89eS%
zs+V0d%qR^yP!#SMT(V#D>sp~xr4a%h4l~L)PU&S(>>-{i!xLSdQ~@1CHEL(XS|cyv
z<{nxT3uLgae%|tKyQX7(X+HM9w%`lJR$n>%)z>>rzoKcm#1~9p_A)6CgWESefUVBR
zw5DC1qoNTN_RdJ1Sy7is29wzDhHUcJt@_GI_I9ZiSG}4$2#1G+>1pw9_Wy?X3|{2*
zfz)<<^4kZZ@Lrs(D}-x;d84n%01Fu$VG80!SQNe`;g9~49vkLM`t|{@#VbD-@m(1q
zcC5inJZNSl2A2@6C=v{@kk_r)iG-N@;dCKn7Z|e92-PY)RTv`_iihH1N2avoNT`z&
z3wJP{73XqvpkhYewSL!=jop{8pbO%lAv}|+2}a^{9(_u}n%0DMc}P2u>bKXshu^m0
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
IdK2{j0Ao0E3jhEB

literal 0
HcmV?d00001

diff --git a/pom.xml b/pom.xml
index 0542f3f..3055949 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,5 +26,6 @@
     <modules>
         <module>internal-dubbo</module>
         <module>internal-gateway</module>
+        <module>service</module>
     </modules>
 </project>
\ No newline at end of file
diff --git a/service/pom.xml b/service/pom.xml
new file mode 100644
index 0000000..851b006
--- /dev/null
+++ b/service/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>adaptive-loadbalance</artifactId>
+        <groupId>com.aliware.tianchi</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service</artifactId>
+    <packaging>pom</packaging>
+    <modules>
+        <module>service-api</module>
+        <module>service-consumer</module>
+        <module>service-provider</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.aliware.tianchi</groupId>
+            <artifactId>internal-dubbo</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliware.tianchi</groupId>
+            <artifactId>internal-gateway</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/service/service-api/pom.xml b/service/service-api/pom.xml
new file mode 100644
index 0000000..0f3df87
--- /dev/null
+++ b/service/service-api/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>service</artifactId>
+        <groupId>com.aliware.tianchi</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-api</artifactId>
+
+
+</project>
\ No newline at end of file
diff --git a/service/service-api/src/main/java/com/aliware/tianchi/HashInterface.java b/service/service-api/src/main/java/com/aliware/tianchi/HashInterface.java
new file mode 100644
index 0000000..087dfce
--- /dev/null
+++ b/service/service-api/src/main/java/com/aliware/tianchi/HashInterface.java
@@ -0,0 +1,18 @@
+package com.aliware.tianchi;
+
+/**
+ * @author guohaoice@gmail.com
+ */
+public interface HashInterface {
+
+  /**
+   * 计算给定字符串的 hash 值
+   * <li>
+   *     <ol>接口的响应时间符合负指数分布 </ol>
+   *     <ol>接口的并发度(允许同时调用的线程数)会随时间增加或减小,从而模拟生产环境可能的排队</ol>
+   * </li>
+   * @param input 要计算的字符串
+   * @return 字符串的 hash 值
+   */
+  int hash(String input);
+}
diff --git a/service/service-consumer/pom.xml b/service/service-consumer/pom.xml
new file mode 100644
index 0000000..ba938d8
--- /dev/null
+++ b/service/service-consumer/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>service</artifactId>
+        <groupId>com.aliware.tianchi</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-consumer</artifactId>
+
+
+</project>
\ No newline at end of file
diff --git a/service/service-provider/pom.xml b/service/service-provider/pom.xml
new file mode 100644
index 0000000..53c8fab
--- /dev/null
+++ b/service/service-provider/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>service</artifactId>
+        <groupId>com.aliware.tianchi</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>service-provider</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.aliware.tianchi</groupId>
+            <artifactId>service-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+
+</project>
\ No newline at end of file
diff --git a/service/service-provider/src/main/java/com/aliware/tianchi/HashServiceImpl.java b/service/service-provider/src/main/java/com/aliware/tianchi/HashServiceImpl.java
new file mode 100644
index 0000000..4df1288
--- /dev/null
+++ b/service/service-provider/src/main/java/com/aliware/tianchi/HashServiceImpl.java
@@ -0,0 +1,43 @@
+package com.aliware.tianchi;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Hash service impl
+ *
+ * @author guohaoice@gmail.com
+ */
+public class HashServiceImpl implements HashInterface {
+  private long averageRTT;
+  private int maxConcurrency;
+  private String salt;
+
+  public HashServiceImpl(long averageRTT, int maxConcurrency, String salt) {
+    this.averageRTT = averageRTT;
+    this.maxConcurrency = maxConcurrency;
+    this.salt = salt;
+  }
+
+  @Override
+  public int hash(String input) {
+    long baseRtt = nextRTT();
+    try {
+      Thread.sleep(baseRtt);
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+    }
+    return (input + salt).hashCode();
+  }
+
+  private long nextRTT() {
+    ThreadLocalRandom rng = ThreadLocalRandom.current();
+    double u = rng.nextDouble();
+    int x = 0;
+    double cdf = 0;
+    while (u >= cdf) {
+      x++;
+      cdf = 1 - Math.exp(-1.0 * 1 / averageRTT * x);
+    }
+    return x;
+  }
+}
diff --git a/service/src/main/java/com/aliware/tianchi/HashInterface.java b/service/src/main/java/com/aliware/tianchi/HashInterface.java
new file mode 100644
index 0000000..5665174
--- /dev/null
+++ b/service/src/main/java/com/aliware/tianchi/HashInterface.java
@@ -0,0 +1,10 @@
+package com.aliware.tianchi;
+
+/**
+ * @author guohaoice@gmail.com
+ */
+public interface HashInterface {
+
+    int hash(String input);
+
+}
-- 
GitLab