├── .gitattributes ├── .gitignore ├── README.md ├── dynamic-sharding.yml ├── go.mod ├── go.sum ├── images ├── dynamic-sharding架构图.jpg ├── log.jpg ├── pgw_miss.png └── pgw_miss2.png ├── makefile └── pkg ├── config └── config.go ├── consistent └── consistent.go ├── main.go ├── sd ├── rings.go └── sd.go └── web ├── controller └── pushgateway │ ├── pgw_controller.go │ └── pgw_route.go └── gin.go /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-language=golang -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | bin/* 3 | out/ 4 | *.swp 5 | *.swo 6 | *.tar.gz 7 | docs/_site 8 | .idea/ 9 | package_cache_tmp/ 10 | /.idea 11 | *DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # k8s零基础入门运维课程 2 | - [k8s零基础入门运维课程,计算存储网络和常见的集群相关操作](https://ke.qq.com/course/5829699) 3 | 4 | # k8s纯源码解读教程(3个课程内容合成一个大课程) 5 | - [k8s底层原理和源码讲解之精华篇](https://ke.qq.com/course/4093533) 6 | - [k8s底层原理和源码讲解之进阶篇](https://ke.qq.com/course/4236389) 7 | - [k8s纯源码解读课程,助力你变成k8s专家](https://ke.qq.com/course/4697341) 8 | 9 | 10 | # k8s运维进阶调优课程 11 | - [k8s运维大师课程](https://ke.qq.com/course/5586848) 12 | 13 | # k8s管理运维平台实战 14 | - [k8s管理运维平台实战前端vue后端golang](https://ke.qq.com/course/5856444) 15 | 16 | 17 | # k8s二次开发课程 18 | - [k8s二次开发之基于真实负载的调度器](https://ke.qq.com/course/5814034) 19 | - [k8s-operator和crd实战开发 助你成为k8s专家](https://ke.qq.com/course/5458555) 20 | 21 | # cicd 课程 22 | - [tekton全流水线实战和pipeline运行原理源码解读](https://ke.qq.com/course/5467720) 23 | 24 | 25 | # prometheus全组件的教程 26 | - [01_prometheus零基础入门,grafana基础操作,主流exporter采集配置](https://ke.qq.com/course/5826832) 27 | - [02_prometheus全组件配置使用、底层原理解析、高可用实战](https://ke.qq.com/course/3549215) 28 | - [03_prometheus-thanos使用和源码解读](https://ke.qq.com/course/3883439) 29 | - [04_kube-prometheus和prometheus-operator实战和原理介绍](https://ke.qq.com/course/3912017) 30 | - [05_prometheus源码讲解和二次开发](https://ke.qq.com/course/4236995) 31 | - [06_prometheus监控k8s的实战配置和原理讲解,写go项目暴露业务指标](https://ke.qq.com/course/5837369) 32 | 33 | # go语言课程 34 | - [golang基础课程](https://ke.qq.com/course/4334898) 35 | - [golang实战课,一天编写一个任务执行系统,客户端和服务端架构](https://ke.qq.com/course/3550865) 36 | - [golang运维开发项目之k8s网络探测实战](https://ke.qq.com/course/5860635) 37 | - [golang运维平台实战,服务树,日志监控,任务执行,分布式探测](https://ke.qq.com/course/4334675) 38 | - [golang运维开发实战课程之k8s巡检平台](https://ke.qq.com/course/5818923) 39 | 40 | # 直播答疑sre职业发展规划 41 | - [k8s-prometheus课程答疑和运维开发职业发展规划](https://ke.qq.com/course/5506477) 42 | 43 | 44 | # k8s从零基础入门到专家到运维大师 45 | 46 | | 学习方向 | 分析进阶视频 | 教程地址 | 备注 | 47 | |--------------------------|---------|------------|-----| 48 | | 01_k8s零基础入门实战 | [地址](https://www.bilibili.com/video/BV1Mt4y1P7bL/) | [地址](https://ke.qq.com/course/5829699) | | 49 | | 02_k8s纯源码解读课程,助力你变成k8s专家 | [地址](https://www.bilibili.com/video/BV1or4y1877p/) | [地址](https://ke.qq.com/course/4697341) | | 50 | | 03_k8s底层原理和源码讲解之精华篇 | [地址](https://www.bilibili.com/video/BV1T34y127gU/) | [地址](https://ke.qq.com/course/4093533) | | 51 | | 04_k8s底层原理和源码讲解之进阶篇 | [地址](https://www.bilibili.com/video/BV1si4y1f7Xo/) | [地址](https://ke.qq.com/course/4236389) | | 52 | 53 | 54 | # 01 新手课程 55 | - k8s零基础买这个课,只需有linux基础就能学。玩转k8s集群常用的监控/日志/控制台等组件 https://ke.qq.com/course/5829699 56 | - k8s中的prometheus监控实战和底层原理讲解 https://ke.qq.com/course/5837369 57 | # 02 源码解读课程 58 | - k8s源码解读看这3个课,合在一起是个大课,没有顺序 59 | - https://ke.qq.com/course/4697341 60 | - https://ke.qq.com/course/4093533 61 | - https://ke.qq.com/course/4236389 62 | # 03 进阶二开课程 63 | - 偏k8s二次开发 k8s-operator和crd实战开发 https://ke.qq.com/course/5458555 64 | - k8s运维大师课程是 真实高并发k8s集群调优,疑难杂症解决和一些工具的开发 https://ke.qq.com/course/5586848 65 | - k8s二次开发之基于真实负载的调度器 https://ke.qq.com/course/5814034 66 | 67 | # k8s 开发篇 68 | 69 | 70 | | 学习方向 | 分析进阶视频 | 教程地址 | 备注 | 71 | |-----------------------------------|---------|------------|-----| 72 | | 01_k8s运维大师课程 | [地址](https://www.bilibili.com/video/BV11B4y1k7LB/) | [地址](https://ke.qq.com/course/5586848) | | 73 | | 02_k8s-operator和crd实战开发 助你成为k8s专家 | [地址](https://www.bilibili.com/video/BV1cv4y1371X/) | [地址](https://ke.qq.com/course/5458555) | | 74 | | 02_k8s二次开发之基于真实负载的调度器 | [地址](https://www.bilibili.com/video/BV1qB4y1G7Kf/) | [地址](https://ke.qq.com/course/5814034) | | 75 | 76 | 77 | 78 | # prometheus监控从入门到专家之路 79 | 80 | | 学习方向 | 分析进阶视频 | 教程地址 | 备注 | 81 | |------------------------------------------------|---------|------------|-----| 82 | | 01_prometheus零基础入门,grafana基础操作,主流exporter采集配置 | [地址](https://www.bilibili.com/video/BV1814y1e73y/) | [地址](https://ke.qq.com/course/5826832) | | 83 | | 02_prometheus全组件配置使用、底层原理解析、高可用实战 | [地址](https://www.bilibili.com/video/BV1oZ4y1f7au/) | [地址](https://ke.qq.com/course/3549215) | | 84 | | 03_kube-prometheus和prometheus-operator实战和原理介绍 | [地址](https://www.bilibili.com/video/BV1LR4y1L7jV/) | [地址](https://ke.qq.com/course/3912017) | | 85 | | 04_prometheus-thanos使用和源码解读 | [地址](https://www.bilibili.com/video/BV1814y1e73y/) | [地址](https://ke.qq.com/course/3883439) | | 86 | | 05_prometheus源码讲解和二次开发 | [地址](https://www.bilibili.com/video/BV1hS4y1m73Q/) | [地址](https://ke.qq.com/course/4236995) | | 87 | 88 | 89 | # golang运维开发之从0基础到运维平台 90 | 91 | | 学习方向 | 分析进阶视频 | 教程地址 | 备注 | 92 | |------------------------------------------------|---------|------------|-----| 93 | | 01_golang基础课程 | [地址](https://www.bilibili.com/video/BV1WT411M7Gh/) | [地址](https://ke.qq.com/course/4334898) | | 94 | | 02_golang运维平台实战,服务树,日志监控,任务执行,分布式探测 | [地址](https://www.bilibili.com/video/BV14T4y1k7oo) | [地址](https://ke.qq.com/course/4334675) | | 95 | | 03_golang运维开发实战课程之k8s巡检平台] | [地址](https://www.bilibili.com/video/BV1Ad4y1r7C4/) | [地址](https://ke.qq.com/course/5818923) | | 96 | 97 | 98 | # cicd实战 99 | 100 | | 学习方向 | 分析进阶视频 | 教程地址 | 备注 | 101 | |------------------------------------------------|---------|------------|-----| 102 | | 01_tekton全流水线实战和pipeline运行原理源码解读 | [地址](https://www.bilibili.com/video/BV13P4y1Z7Xv/) | [地址](https://ke.qq.com/course/5458555) | | 103 | 104 | 105 | 106 | 107 | # 直播答疑sre职业发展规划 108 | - [k8s-prometheus课程答疑和运维开发职业发展规划](https://ke.qq.com/course/5506477) 109 | 110 | 111 | # 关于白嫖和付费 112 | - 白嫖当然没关系,我已经贡献了很多文章和开源项目,当然还有免费的视频 113 | - 但是客观的讲,如果你能力超强是可以一直白嫖的,可以看源码。什么问题都可以解决 114 | - 看似免费的资料很多,但大部分都是边角料,核心的东西不会免费,更不会有大神给你答疑 115 | - thanos和kube-prometheus如果你对prometheus源码把控很好的话,再加上k8s知识的话就觉得不难了 116 | 117 | # 架构图 118 | ![image](./images/dynamic-sharding架构图.jpg) 119 | # pgw是什么 120 | [项目介绍](https://github.com/prometheus/pushgateway) 121 | 122 | ## pgw打点特点 123 | 124 | - 没有使用grouping对应的接口uri为 125 | ``` 126 | http://pushgateway_addr/metrics/job/ 127 | ``` 128 | - 使用grouping对应的接口uri为 129 | ``` 130 | http://pushgateway_addr/metrics/job/// 131 | ``` 132 | - put/post方法区别在于 put只替换metrics和job相同的 post替换label全部相同的 133 | # pgw单点问题 134 | ## 如果简单把pgw挂在lb后面的问题 135 | - lb后面rr轮询:如果不加控制的让push数据随机打到多个pushgateway实例上,prometheus无差别scrape会导致数据错乱,表现如下 136 | 137 | ![image](./images/pgw_miss.png) 138 | ![image](./images/pgw_miss2.png) 139 | - 根本原因是在t1时刻 指标的值为10 t2时刻 值为20 140 | - t1时刻轮询打点到了pgw-a上 t2时刻打点到了pgw-b上 141 | - 而promethues采集的时候两边全都采集导致本应该一直上升的值呈锯齿状 142 | ## 如果对uri做静态一致性哈希+prome静态配置pgw 143 | - 假设有3个pgw,前面lb根据request_uri做一致性哈希 144 | - promethues scrape时静态配置3个pgw实例 145 | ``` 146 | - job_name: pushgateway 147 | honor_labels: true 148 | honor_timestamps: true 149 | scrape_interval: 5s 150 | scrape_timeout: 4s 151 | metrics_path: /metrics 152 | scheme: http 153 | static_configs: 154 | - targets: 155 | - pgw-a:9091 156 | - pgw-b:9091 157 | 158 | ``` 159 | - 结果是可以做到哈希分流,但无法解决某个pgw实例挂掉,哈希到这个实例上面的请求失败问题 160 | 161 | ## 解决方案是: 动态一致性哈希分流+consul service_check 162 | ![image](./images/log.jpg) 163 | - dynamic-sharding服务启动会根据配置文件注册pgw服务到consul中 164 | - 由consul定时对pgw server做http check 165 | - push请求会根据请求path做一致性哈希分离,eg: 166 | ``` 167 | # 仅job不同 168 | - http://pushgateway_addr/metrics/job/job_a 169 | - http://pushgateway_addr/metrics/job/job_b 170 | - http://pushgateway_addr/metrics/job/job_c 171 | # label不同 172 | - http://pushgateway_addr/metrics/job/job_a/tag_a/value_a 173 | - http://pushgateway_addr/metrics/job/job_a/tag_a/value_b 174 | ``` 175 | - 当多个pgw中实例oom或异常重启,consul check service会将bad实例标记为down 176 | ~~- dynamic-sharding轮询检查实例数量变化~~ 177 | - dynamic-sharding 会`Watch` pgw节点数量变化 178 | - 重新生成哈希环,rehash将job分流 179 | - 同时promethues使用consul服务发现的pgw实例列表,无需手动变更 180 | - 采用redirect而不处理请求,简单高效 181 | - dynamic-sharding本身无状态,可启动多个实例作为流量接入层和pgw server之间 182 | - 扩容时同时也需要重启所有存量pgw服务 183 | - 不足:没有解决promethues单点问题和分片问题 184 | 项目地址: [https://github.com/ning1875/dynamic-sharding](https://github.com/ning1875/dynamic-sharding) 185 | 186 | ## 使用指南 187 | 188 | > 编译或下载 189 | ```shell script 190 | # 编译build 191 | $ git clone https://github.com/ning1875/dynamic-sharding.git 192 | $ cd dynamic-sharding && make 193 | # 下载 :releases中直接下载tag包 194 | # 如https://github.com/ning1875/dynamic-sharding/releases/download/v2.0/dynamic-sharding-2.0.linux-amd64.tar.gz 195 | ``` 196 | 197 | > 修改配置 198 | ```shell script 199 | # 修改配置文件 200 | # 补充dynamic-sharding.yml中的信息: 201 | ``` 202 | 203 | > 启动dynamic-sharding服务 204 | 205 | ```shell script 206 | ./dynamic-sharding --config.file=dynamic-sharding.yml 207 | ``` 208 | 209 | > 和promtheus集成 210 | > Add the following text to your promtheus.yaml's scrape_configs section 211 | ```yaml 212 | scrape_configs: 213 | - job_name: pushgateway 214 | consul_sd_configs: 215 | - server: $cousul_api 216 | services: 217 | - pushgateway 218 | relabel_configs: 219 | - source_labels: ["__meta_consul_dc"] 220 | target_label: "dc" 221 | 222 | ``` 223 | > 调用方调用 dynamic-sharding接口即可 eg: http://localhost:9292/ 224 | 225 | ## 运维指南 226 | 227 | ### pgw节点故障 (无需关心) 228 | > eg: 启动了4个pgw实例,其中一个宕机了,则流量从4->3,以此类推 229 | 230 | 231 | ### pgw节点恢复 232 | > eg: 启动了4个pgw实例,其中一个宕机了,过一会儿恢复了,那么它会被consul unregister掉 233 | > 避免出现和扩容一样的case: 再次rehash的job 会持续在原有pgw被prome scrap,而且value不会更新 234 | 235 | 236 | 237 | ### 扩容 238 | > 修改yml配置文件将pgw servers 调整到扩容后的数量,重启服务dynamic-sharding 239 | > 注意 同时也要重启所有存量pgw服务,不然rehash的job 会持续在原有pgw被prome scrap,而且value不会更新 240 | 241 | 242 | 243 | ### 缩容 244 | 245 | ```shell script 246 | # 方法一 247 | ## 调用cousul api 248 | curl -vvv --request PUT 'http://$cousul_api/v1/agent/service/deregister/$pgw_addr_$pgw_port' 249 | eg: curl -vvv --request PUT 'http://localhost:8500/v1/agent/service/deregister/1.1.1.1_9091' 250 | 251 | ## 修改yml配置文件将pgw servers 调整到缩容后的数量,避免服务重启时再次注册缩容节点 252 | 253 | # 方法二 254 | ## 停止缩容节点服务,consul会将服务踢出,然后再注销 255 | 256 | ``` 257 | 258 | 259 | 260 | 261 | ### 使用python sdk时遇到的 urllib2.HTTPError: HTTP Error 307: Temporary Redirect 问题 262 | #### 原因 263 | - 查看代码得知python sdk在构造pgw实例时使用默认的handler方法,而其没有`follow_redirect`导致的 264 | 265 | ```python 266 | def push_to_gateway(gateway, job, registry, grouping_key=None, timeout=30,handler=default_handler): 267 | ``` 268 | 269 | #### 解决方法 270 | 271 | - 使用requests库自定义一个handler,初始化的时候指定 272 | 273 | ```python 274 | def custom_handle(url, method, timeout, headers, data): 275 | def handle(): 276 | h = {} 277 | for k, v in headers: 278 | h[k] = v 279 | if method == 'PUT': 280 | resp = requests.put(url, data=data, headers=h, timeout=timeout) 281 | elif method == 'POST': 282 | resp = requests.post(url, data=data, headers=h, timeout=timeout) 283 | elif method == 'DELETE': 284 | resp = requests.delete(url, data=data, headers=h, timeout=timeout) 285 | else: 286 | return 287 | if resp.status_code >= 400: 288 | raise IOError("error talking to pushgateway: {0} {1}".format(resp.status_code, resp.text)) 289 | return handle 290 | 291 | # push_to_gateway(push_addr, job='some_job', registry=r1, handler=custom_handle) 292 | ``` 293 | 294 | 295 | -------------------------------------------------------------------------------- /dynamic-sharding.yml: -------------------------------------------------------------------------------- 1 | consul_server: 2 | # consul api 地址 3 | addr: localhost:8500 4 | username: 5 | password: 6 | # promethues中consul sd中pgw service name 7 | register_service_name: pushgateway 8 | # 服务web addr 9 | http_listen_addr: :9292 10 | # pushgateway 信息 11 | pushgateway: 12 | # 端口号 13 | port: 9091 14 | # pushgateway ip列表 15 | servers: 16 | - 1.1.1.1 17 | - 1.1.1.2 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module dynamic-sharding 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.0 7 | github.com/go-kit/kit v0.10.0 8 | github.com/hashicorp/consul/api v1.3.0 9 | github.com/oklog/run v1.1.0 10 | github.com/prometheus/common v0.10.0 11 | github.com/spaolacci/murmur3 v1.1.0 12 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 13 | gopkg.in/yaml.v2 v2.2.8 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 5 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 6 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 7 | github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= 8 | github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= 9 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 10 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 11 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 12 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 13 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= 14 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 15 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 16 | github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 17 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 18 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= 19 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 20 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 21 | github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= 22 | github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= 23 | github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 24 | github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= 25 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 26 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 27 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 28 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 29 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 30 | github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= 31 | github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 32 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 33 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 34 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 35 | github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 36 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 37 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= 38 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= 39 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 40 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 41 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 42 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 43 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 44 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 45 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 46 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 47 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 48 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 49 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 50 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 51 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 52 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 53 | github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 54 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 55 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 56 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 57 | github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= 58 | github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= 59 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 60 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 61 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 62 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 63 | github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= 64 | github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 65 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 66 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 67 | github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= 68 | github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= 69 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 70 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 71 | github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= 72 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 73 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 74 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 75 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 76 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 77 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 78 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 79 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 80 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 81 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 82 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 83 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 84 | github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= 85 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 86 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 87 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 88 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 89 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 90 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 91 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 92 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 93 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 94 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 95 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 96 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 97 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 98 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 99 | github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 100 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 101 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 102 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 103 | github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= 104 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 105 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 106 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 107 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 108 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 109 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 110 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 111 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 112 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 113 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 114 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 115 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 116 | github.com/hashicorp/consul/api v1.3.0 h1:HXNYlRkkM/t+Y/Yhxtwcy02dlYwIaoxzvxPnS+cqy78= 117 | github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= 118 | github.com/hashicorp/consul/sdk v0.3.0 h1:UOxjlb4xVNF93jak1mzzoBatyFju9nrkxpVwIp/QqxQ= 119 | github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= 120 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 121 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 122 | github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= 123 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 124 | github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= 125 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 126 | github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= 127 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 128 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 129 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 130 | github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= 131 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 132 | github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= 133 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 134 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 135 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 136 | github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= 137 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 138 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 139 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 140 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 141 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 142 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 143 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 144 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= 145 | github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= 146 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 147 | github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= 148 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= 149 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 150 | github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= 151 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 152 | github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= 153 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 154 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 155 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 156 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 157 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 158 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 159 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 160 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 161 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 162 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 163 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 164 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 165 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 166 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 167 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 168 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 169 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 170 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 171 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 172 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 173 | github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= 174 | github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= 175 | github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= 176 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 177 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 178 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 179 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 180 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 181 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 182 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 183 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 184 | github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= 185 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 186 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 187 | github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= 188 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 189 | github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= 190 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 191 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 192 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= 193 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 194 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 195 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 196 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 197 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 198 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 199 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 200 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 201 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 202 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 203 | github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= 204 | github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= 205 | github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= 206 | github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= 207 | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 208 | github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 209 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 210 | github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= 211 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 212 | github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= 213 | github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= 214 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 215 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 216 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 217 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 218 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 219 | github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= 220 | github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= 221 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 222 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 223 | github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= 224 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 225 | github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= 226 | github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= 227 | github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= 228 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= 229 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 230 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 231 | github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= 232 | github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= 233 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 234 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 235 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 236 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 237 | github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= 238 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 239 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 240 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 241 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 242 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 243 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 244 | github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= 245 | github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= 246 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 247 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 248 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 249 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 250 | github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 251 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 252 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 253 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 254 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 255 | github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= 256 | github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= 257 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 258 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 259 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 260 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 261 | github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= 262 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 263 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 264 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 265 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 266 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 267 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 268 | github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= 269 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= 270 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 271 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 272 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 273 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 274 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 275 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 276 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 277 | github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= 278 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 279 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 280 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 281 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 282 | github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 283 | github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 284 | github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= 285 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 286 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 287 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 288 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 289 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 290 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 291 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 292 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 293 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 294 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 295 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 296 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 297 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 298 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 299 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 300 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= 301 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 302 | go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 303 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 304 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 305 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 306 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 307 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 308 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 309 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 310 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 311 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 312 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 313 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 314 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 315 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 316 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 317 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 318 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 319 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 320 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 321 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 322 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 323 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 324 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 325 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 326 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 327 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 328 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 329 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 330 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 331 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 332 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 333 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 334 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 335 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 336 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 337 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 338 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 339 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 340 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 341 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 342 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= 343 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 344 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 345 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 346 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 347 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 348 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 349 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 350 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 351 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 352 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 353 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 354 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 355 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 356 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 357 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 358 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 359 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 360 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 361 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 362 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 364 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 365 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 366 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 367 | golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 368 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 369 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 370 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 371 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 372 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 373 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 374 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 375 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 376 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 377 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 378 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 379 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 380 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 381 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 382 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 383 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 384 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 385 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 386 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 387 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 388 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 389 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 390 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 391 | google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 392 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 393 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 394 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 395 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 396 | google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 397 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 398 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 399 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 400 | google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 401 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 402 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 403 | google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 404 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 405 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 406 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 407 | gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 408 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 409 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 410 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 411 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 412 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 413 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 414 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 415 | gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= 416 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 417 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 418 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 419 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 420 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 421 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 422 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 423 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 424 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 425 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 426 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 427 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 428 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 429 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 430 | sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= 431 | -------------------------------------------------------------------------------- /images/dynamic-sharding架构图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ning1875/dynamic-sharding/05a4a319aadf6de4ac453173fdc014080f99cb41/images/dynamic-sharding架构图.jpg -------------------------------------------------------------------------------- /images/log.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ning1875/dynamic-sharding/05a4a319aadf6de4ac453173fdc014080f99cb41/images/log.jpg -------------------------------------------------------------------------------- /images/pgw_miss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ning1875/dynamic-sharding/05a4a319aadf6de4ac453173fdc014080f99cb41/images/pgw_miss.png -------------------------------------------------------------------------------- /images/pgw_miss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ning1875/dynamic-sharding/05a4a319aadf6de4ac453173fdc014080f99cb41/images/pgw_miss2.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | GOCMD=go 2 | GOBUILD=${GOCMD} build 3 | GOCLEAN=${GOCMD} clean 4 | GOTEST=${GOCMD} test 5 | GOGET=${GOCMD} get 6 | VERSION=1.0 7 | DATE= `date +%FT%T%z` 8 | 9 | 10 | BINARY_NAME="dynamic-sharding" 11 | BINARY_LINUX=${BINARY_NAME}_linux 12 | BUILDUSER="ning1875" 13 | LDFLAGES=" -X 'github.com/prometheus/common/version.BuildUser=${BUILDUSER}' -X 'github.com/prometheus/common/version.BuildDate=`date`' " 14 | all: deps build 15 | deps: 16 | export GOPROXY=http://goproxy.io 17 | export GO111MODULE=on 18 | build: 19 | ${GOBUILD} -v -ldflags ${LDFLAGES} -o ${BINARY_NAME} pkg/main.go 20 | test: 21 | ${GOTEST} -v ./... 22 | clean: 23 | ${GOCLEAN} 24 | rm -f ${BINARY_NAME} 25 | rm -f ${BINARY_LINUX} 26 | run: 27 | ${GOBUILD} -o ${BINARY_NAME} -v ./... 28 | ./${BINARY_NAME} 29 | 30 | 31 | build-linux: 32 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ${BUILDTOOL} 33 | 34 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io/ioutil" 5 | 6 | "gopkg.in/yaml.v2" 7 | "github.com/go-kit/kit/log/level" 8 | "github.com/go-kit/kit/log" 9 | ) 10 | 11 | type Config struct { 12 | ConsulServer *ConsulServerConfig `yaml:"consul_server"` 13 | HttpListenAddr string `yaml:"http_listen_addr"` 14 | PGW *PushGateWayConfig `yaml:"pushgateway"` 15 | } 16 | 17 | type ConsulServerConfig struct { 18 | Addr string `yaml:"addr,omitempty"` 19 | Username string `yaml:"username,omitempty"` 20 | Password string `yaml:"password,omitempty"` 21 | RegisterServiceName string `yaml:"register_service_name,omitempty"` 22 | } 23 | 24 | type PushGateWayConfig struct { 25 | Servers []string `yaml:"servers"` 26 | Port int `yaml:"port"` 27 | } 28 | 29 | func Load(s string) (*Config, error) { 30 | cfg := &Config{} 31 | 32 | err := yaml.UnmarshalStrict([]byte(s), cfg) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return cfg, nil 37 | } 38 | 39 | func LoadFile(filename string, logger log.Logger) (*Config, error) { 40 | content, err := ioutil.ReadFile(filename) 41 | if err != nil { 42 | return nil, err 43 | } 44 | cfg, err := Load(string(content)) 45 | if err != nil { 46 | level.Error(logger).Log("msg", "parsing YAML file errr...", "error", err) 47 | } 48 | 49 | return cfg, nil 50 | } 51 | -------------------------------------------------------------------------------- /pkg/consistent/consistent.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 Numerotron Inc. 2 | // Use of this source code is governed by an MIT-style license 3 | // that can be found in the LICENSE file. 4 | 5 | // Package consistent provides a consistent hashing function. 6 | // 7 | // Consistent hashing is often used to distribute requests to a changing set of servers. For example, 8 | // say you have some cache servers cacheA, cacheB, and cacheC. You want to decide which cache server 9 | // to use to look up information on a user. 10 | // 11 | // You could use a typical hash table and hash the user id 12 | // to one of cacheA, cacheB, or cacheC. But with a typical hash table, if you add or remove a server, 13 | // almost all keys will get remapped to different results, which basically could bring your service 14 | // to a grinding halt while the caches get rebuilt. 15 | // 16 | // With a consistent hash, adding or removing a server drastically reduces the number of keys that 17 | // get remapped. 18 | // 19 | // Read more about consistent hashing on wikipedia: http://en.wikipedia.org/wiki/Consistent_hashing 20 | // 21 | package consistent 22 | 23 | import ( 24 | "errors" 25 | "sort" 26 | "strconv" 27 | "sync" 28 | 29 | "github.com/spaolacci/murmur3" 30 | ) 31 | 32 | type uints []uint32 33 | 34 | // Len returns the length of the uints array. 35 | func (x uints) Len() int { return len(x) } 36 | 37 | // Less returns true if element i is less than element j. 38 | func (x uints) Less(i, j int) bool { return x[i] < x[j] } 39 | 40 | // Swap exchanges elements i and j. 41 | func (x uints) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 42 | 43 | // ErrEmptyCircle is the error returned when trying to get an element when nothing has been added to hash. 44 | var ErrEmptyCircle = errors.New("empty circle") 45 | 46 | // Consistent holds the information about the members of the consistent hash circle. 47 | type Consistent struct { 48 | circle map[uint32]string 49 | members map[string]bool 50 | sortedHashes uints 51 | NumberOfReplicas int 52 | count int64 53 | scratch [64]byte 54 | sync.RWMutex 55 | } 56 | 57 | // New creates a new Consistent object with a default setting of 20 replicas for each entry. 58 | // 59 | // To change the number of replicas, set NumberOfReplicas before adding entries. 60 | func New() *Consistent { 61 | c := new(Consistent) 62 | c.NumberOfReplicas = 20 63 | c.circle = make(map[uint32]string) 64 | c.members = make(map[string]bool) 65 | return c 66 | } 67 | 68 | // eltKey generates a string key for an element with an index. 69 | func (c *Consistent) eltKey(elt string, idx int) string { 70 | // return elt + "|" + strconv.Itoa(idx) 71 | return strconv.Itoa(idx) + elt 72 | } 73 | 74 | // Add inserts a string element in the consistent hash. 75 | func (c *Consistent) Add(elt string) { 76 | c.Lock() 77 | defer c.Unlock() 78 | c.add(elt) 79 | } 80 | 81 | // need c.Lock() before calling 82 | func (c *Consistent) add(elt string) { 83 | for i := 0; i < c.NumberOfReplicas; i++ { 84 | c.circle[c.hashKey(c.eltKey(elt, i))] = elt 85 | } 86 | c.members[elt] = true 87 | c.updateSortedHashes() 88 | c.count++ 89 | } 90 | 91 | // Remove removes an element from the hash. 92 | func (c *Consistent) Remove(elt string) { 93 | c.Lock() 94 | defer c.Unlock() 95 | c.remove(elt) 96 | } 97 | 98 | // need c.Lock() before calling 99 | func (c *Consistent) remove(elt string) { 100 | for i := 0; i < c.NumberOfReplicas; i++ { 101 | delete(c.circle, c.hashKey(c.eltKey(elt, i))) 102 | } 103 | delete(c.members, elt) 104 | c.updateSortedHashes() 105 | c.count-- 106 | } 107 | 108 | // Set sets all the elements in the hash. If there are existing elements not 109 | // present in elts, they will be removed. 110 | func (c *Consistent) Set(elts []string) { 111 | c.Lock() 112 | defer c.Unlock() 113 | for k := range c.members { 114 | found := false 115 | for _, v := range elts { 116 | if k == v { 117 | found = true 118 | break 119 | } 120 | } 121 | if !found { 122 | c.remove(k) 123 | } 124 | } 125 | for _, v := range elts { 126 | _, exists := c.members[v] 127 | if exists { 128 | continue 129 | } 130 | c.add(v) 131 | } 132 | } 133 | 134 | func (c *Consistent) Members() []string { 135 | c.RLock() 136 | defer c.RUnlock() 137 | var m []string 138 | for k := range c.members { 139 | m = append(m, k) 140 | } 141 | return m 142 | } 143 | 144 | // Get returns an element close to where name hashes to in the circle. 145 | func (c *Consistent) Get(name string) (string, error) { 146 | c.RLock() 147 | defer c.RUnlock() 148 | if len(c.circle) == 0 { 149 | return "", ErrEmptyCircle 150 | } 151 | key := c.hashKey(name) 152 | i := c.search(key) 153 | return c.circle[c.sortedHashes[i]], nil 154 | } 155 | 156 | func (c *Consistent) search(key uint32) (i int) { 157 | f := func(x int) bool { 158 | return c.sortedHashes[x] > key 159 | } 160 | i = sort.Search(len(c.sortedHashes), f) 161 | if i >= len(c.sortedHashes) { 162 | i = 0 163 | } 164 | return 165 | } 166 | 167 | // GetTwo returns the two closest distinct elements to the name input in the circle. 168 | func (c *Consistent) GetTwo(name string) (string, string, error) { 169 | c.RLock() 170 | defer c.RUnlock() 171 | if len(c.circle) == 0 { 172 | return "", "", ErrEmptyCircle 173 | } 174 | key := c.hashKey(name) 175 | i := c.search(key) 176 | a := c.circle[c.sortedHashes[i]] 177 | 178 | if c.count == 1 { 179 | return a, "", nil 180 | } 181 | 182 | start := i 183 | var b string 184 | for i = start + 1; i != start; i++ { 185 | if i >= len(c.sortedHashes) { 186 | i = 0 187 | } 188 | b = c.circle[c.sortedHashes[i]] 189 | if b != a { 190 | break 191 | } 192 | } 193 | return a, b, nil 194 | } 195 | 196 | // GetN returns the N closest distinct elements to the name input in the circle. 197 | func (c *Consistent) GetN(name string, n int) ([]string, error) { 198 | c.RLock() 199 | defer c.RUnlock() 200 | 201 | if len(c.circle) == 0 { 202 | return nil, ErrEmptyCircle 203 | } 204 | 205 | if c.count < int64(n) { 206 | n = int(c.count) 207 | } 208 | 209 | var ( 210 | key = c.hashKey(name) 211 | i = c.search(key) 212 | start = i 213 | res = make([]string, 0, n) 214 | elem = c.circle[c.sortedHashes[i]] 215 | ) 216 | 217 | res = append(res, elem) 218 | 219 | if len(res) == n { 220 | return res, nil 221 | } 222 | 223 | for i = start + 1; i != start; i++ { 224 | if i >= len(c.sortedHashes) { 225 | i = 0 226 | } 227 | elem = c.circle[c.sortedHashes[i]] 228 | if !sliceContainsMember(res, elem) { 229 | res = append(res, elem) 230 | } 231 | if len(res) == n { 232 | break 233 | } 234 | } 235 | 236 | return res, nil 237 | } 238 | 239 | func (c *Consistent) hashKey(key string) uint32 { 240 | if len(key) < 64 { 241 | var scratch [64]byte 242 | copy(scratch[:], key) 243 | //return crc32.ChecksumIEEE(scratch[:len(key)]) 244 | return murmur3.Sum32(scratch[:len(key)]) 245 | } 246 | //return crc32.ChecksumIEEE([]byte(key)) 247 | return murmur3.Sum32([]byte(key)) 248 | } 249 | 250 | func (c *Consistent) updateSortedHashes() { 251 | hashes := c.sortedHashes[:0] 252 | //reallocate if we're holding on to too much (1/4th) 253 | if cap(c.sortedHashes)/(c.NumberOfReplicas*4) > len(c.circle) { 254 | hashes = nil 255 | } 256 | for k := range c.circle { 257 | hashes = append(hashes, k) 258 | } 259 | sort.Sort(hashes) 260 | c.sortedHashes = hashes 261 | } 262 | 263 | func sliceContainsMember(set []string, member string) bool { 264 | for _, m := range set { 265 | if m == member { 266 | return true 267 | } 268 | } 269 | return false 270 | } 271 | -------------------------------------------------------------------------------- /pkg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "context" 8 | "os" 9 | "os/signal" 10 | "path/filepath" 11 | "syscall" 12 | 13 | "github.com/gin-gonic/gin" 14 | "github.com/go-kit/kit/log" 15 | "github.com/go-kit/kit/log/level" 16 | "github.com/oklog/run" 17 | "github.com/prometheus/common/promlog" 18 | promlogflag "github.com/prometheus/common/promlog/flag" 19 | "github.com/prometheus/common/version" 20 | "gopkg.in/alecthomas/kingpin.v2" 21 | 22 | "dynamic-sharding/pkg/config" 23 | "dynamic-sharding/pkg/sd" 24 | "dynamic-sharding/pkg/web" 25 | ) 26 | 27 | func main() { 28 | 29 | var ( 30 | app = kingpin.New(filepath.Base(os.Args[0]), "The dynamic-sharding") 31 | //configFile = kingpin.Flag("config.file", "docker-mon configuration file path.").Default("docker-mon.yml").String() 32 | configFile = app.Flag("config.file", "docker-mon configuration file path.").Default("dynamic-sharding.yml").String() 33 | ) 34 | promlogConfig := promlog.Config{} 35 | 36 | app.Version(version.Print("dynamic-sharding")) 37 | app.HelpFlag.Short('h') 38 | promlogflag.AddFlags(app, &promlogConfig) 39 | kingpin.MustParse(app.Parse(os.Args[1:])) 40 | 41 | var logger log.Logger 42 | logger = func(config *promlog.Config) log.Logger { 43 | var ( 44 | l log.Logger 45 | le level.Option 46 | ) 47 | if config.Format.String() == "logfmt" { 48 | l = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) 49 | } else { 50 | l = log.NewJSONLogger(log.NewSyncWriter(os.Stderr)) 51 | } 52 | 53 | switch config.Level.String() { 54 | case "debug": 55 | le = level.AllowDebug() 56 | case "info": 57 | le = level.AllowInfo() 58 | case "warn": 59 | le = level.AllowWarn() 60 | case "error": 61 | le = level.AllowError() 62 | } 63 | l = level.NewFilter(l, le) 64 | l = log.With(l, "ts", log.TimestampFormat( 65 | func() time.Time { return time.Now().Local() }, 66 | "2006-01-02T15:04:05.000Z07:00", 67 | ), "caller", log.DefaultCaller) 68 | return l 69 | }(&promlogConfig) 70 | 71 | // new grpc manager 72 | ctxAll, cancelAll := context.WithCancel(context.Background()) 73 | sc, err := config.LoadFile(*configFile, logger) 74 | if err != nil { 75 | level.Error(logger).Log("msg", "config.LoadFil Error, exiting ...", "error", err) 76 | return 77 | } 78 | // init consul client 79 | client, err := sd.NewConsulClient(sc.ConsulServer.Addr, logger) 80 | 81 | if err != nil || client == nil { 82 | level.Error(logger).Log("msg", "NewConsulClient Error, exiting ...", "error", err) 83 | return 84 | } 85 | 86 | // init node hash ring 87 | var ss []string 88 | for _, i := range sc.PGW.Servers { 89 | ss = append(ss, fmt.Sprintf("%s:%d", i, sc.PGW.Port)) 90 | } 91 | 92 | sd.NewConsistentHashNodesRing(ss) 93 | 94 | // register service 95 | errors := sd.RegisterFromFile(client, sc.PGW.Servers, sc.ConsulServer.RegisterServiceName, sc.PGW.Port) 96 | if len(errors) > 0 { 97 | level.Error(logger).Log("msg", "RegisterFromFile Error", "error", errors) 98 | } 99 | 100 | var g run.Group 101 | { 102 | // Termination handler. 103 | term := make(chan os.Signal, 1) 104 | signal.Notify(term, os.Interrupt, syscall.SIGTERM) 105 | cancel := make(chan struct{}) 106 | g.Add( 107 | 108 | func() error { 109 | select { 110 | case <-term: 111 | level.Warn(logger).Log("msg", "Received SIGTERM, exiting gracefully...") 112 | cancelAll() 113 | return nil 114 | //TODO clean work here 115 | case <-cancel: 116 | level.Warn(logger).Log("msg", "server finally exit...") 117 | return nil 118 | } 119 | }, 120 | func(err error) { 121 | close(cancel) 122 | 123 | }, 124 | ) 125 | } 126 | 127 | { 128 | // metrics web handler. 129 | g.Add(func() error { 130 | level.Info(logger).Log("msg", "start web service Listening on address", "address", sc.HttpListenAddr) 131 | gin.SetMode(gin.ReleaseMode) 132 | routes := gin.Default() 133 | errchan := make(chan error, 1) 134 | 135 | go func() { 136 | errchan <- web.StartGin(sc.HttpListenAddr, routes) 137 | }() 138 | select { 139 | case err := <-errchan: 140 | level.Error(logger).Log("msg", "Error starting HTTP server", "err", err) 141 | return err 142 | case <-ctxAll.Done(): 143 | level.Info(logger).Log("msg", "Web service Exit..") 144 | return nil 145 | 146 | } 147 | 148 | }, func(err error) { 149 | cancelAll() 150 | }) 151 | } 152 | 153 | { 154 | // WatchService manager. 155 | g.Add(func() error { 156 | err := client.RunRefreshServiceNode(ctxAll, sc.ConsulServer.RegisterServiceName, sc.ConsulServer.Addr) 157 | if err != nil { 158 | level.Error(logger).Log("msg", "watchService_error", "error", err) 159 | } 160 | return err 161 | }, func(err error) { 162 | cancelAll() 163 | }) 164 | } 165 | g.Run() 166 | } 167 | -------------------------------------------------------------------------------- /pkg/sd/rings.go: -------------------------------------------------------------------------------- 1 | package sd 2 | 3 | import ( 4 | "sync" 5 | "sort" 6 | "context" 7 | "strings" 8 | 9 | "github.com/go-kit/kit/log" 10 | "github.com/go-kit/kit/log/level" 11 | 12 | "dynamic-sharding/pkg/consistent" 13 | ) 14 | 15 | const numberOfReplicas = 500 16 | 17 | var ( 18 | PgwNodeRing *ConsistentHashNodeRing 19 | NodeUpdateChan = make(chan []string, 1) 20 | ) 21 | 22 | // 一致性哈希环,用于管理服务器节点. 23 | type ConsistentHashNodeRing struct { 24 | ring *consistent.Consistent 25 | sync.RWMutex 26 | } 27 | 28 | func NewConsistentHashNodesRing(nodes []string) *ConsistentHashNodeRing { 29 | ret := &ConsistentHashNodeRing{ring: consistent.New()} 30 | 31 | ret.SetNumberOfReplicas(numberOfReplicas) 32 | ret.SetNodes(nodes) 33 | PgwNodeRing = ret 34 | return ret 35 | } 36 | 37 | func (this *ConsistentHashNodeRing) ReShardRing(nodes []string) { 38 | this.Lock() 39 | defer this.Unlock() 40 | newRing := consistent.New() 41 | newRing.NumberOfReplicas = numberOfReplicas 42 | for _, node := range nodes { 43 | newRing.Add(node) 44 | } 45 | this.ring = newRing 46 | } 47 | 48 | // 根据pk,获取node节点. chash(pk) -> node 49 | func (this *ConsistentHashNodeRing) GetNode(pk string) (string, error) { 50 | this.RLock() 51 | defer this.RUnlock() 52 | 53 | return this.ring.Get(pk) 54 | } 55 | 56 | func (this *ConsistentHashNodeRing) SetNodes(nodes []string) { 57 | for _, node := range nodes { 58 | this.ring.Add(node) 59 | } 60 | } 61 | 62 | func (this *ConsistentHashNodeRing) SetNumberOfReplicas(num int32) { 63 | this.ring.NumberOfReplicas = int(num) 64 | } 65 | 66 | func StringSliceEqualBCE(a, b []string) bool { 67 | if len(a) != len(b) { 68 | return false 69 | } 70 | 71 | if (a == nil) != (b == nil) { 72 | return false 73 | } 74 | 75 | b = b[:len(a)] 76 | for i, v := range a { 77 | if v != b[i] { 78 | return false 79 | } 80 | } 81 | 82 | return true 83 | } 84 | 85 | func RunReshardHashRing(ctx context.Context, logger log.Logger) { 86 | 87 | level.Info(logger).Log("msg", "RunRefreshServiceNode start....") 88 | for { 89 | select { 90 | case nodes := <-NodeUpdateChan: 91 | 92 | 93 | oldNodes := PgwNodeRing.ring.Members() 94 | sort.Strings(nodes) 95 | sort.Strings(oldNodes) 96 | isEq := StringSliceEqualBCE(nodes, oldNodes) 97 | if isEq == false { 98 | level.Info(logger).Log("msg", "RunReshardHashRing_node_update_reshard", "old_num", len(oldNodes), "new_num", len(nodes), "oldnodes", strings.Join(oldNodes, ","), "newnodes", strings.Join(nodes, ","), ) 99 | PgwNodeRing.ReShardRing(nodes) 100 | } else { 101 | level.Info(logger).Log("msg", "RunReshardHashRing_node_same", "nodes", strings.Join(nodes, ",")) 102 | 103 | } 104 | case <-ctx.Done(): 105 | level.Info(logger).Log("msg", "RunReshardHashRingQuit") 106 | return 107 | } 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /pkg/sd/sd.go: -------------------------------------------------------------------------------- 1 | package sd 2 | 3 | import ( 4 | "fmt" 5 | "context" 6 | "strings" 7 | 8 | consul "github.com/hashicorp/consul/api" 9 | "github.com/hashicorp/consul/api/watch" 10 | "github.com/go-kit/kit/log" 11 | "github.com/go-kit/kit/log/level" 12 | ) 13 | 14 | type client struct { 15 | consul *consul.Client 16 | logger log.Logger 17 | } 18 | 19 | type Client interface { 20 | // Get a Service from consul 21 | //GetService(string, string) ([]string, error) 22 | // register a service with local agent 23 | ServiceRegister(string, string, int) error 24 | // Deregister a service with local agent 25 | DeRegister(string) error 26 | } 27 | 28 | func NewConsulClient(addr string, logger log.Logger) (*client, error) { 29 | config := consul.DefaultConfig() 30 | config.Address = addr 31 | c, err := consul.NewClient(config) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return &client{consul: c, logger: logger}, nil 36 | } 37 | 38 | // Register a service with consul local agent 39 | func (c *client) ServiceRegister(srvName, srvHost string, srvPort int) error { 40 | 41 | reg := new(consul.AgentServiceRegistration) 42 | reg.Name = srvName 43 | 44 | thisId := fmt.Sprintf("%s_%d", srvHost, srvPort) 45 | reg.ID = thisId 46 | reg.Port = srvPort 47 | reg.Address = srvHost 48 | level.Info(c.logger).Log("msg", "ServiceRegisterStart", "id", thisId) 49 | //增加check 50 | check := new(consul.AgentServiceCheck) 51 | check.HTTP = fmt.Sprintf("http://%s:%d%s", reg.Address, reg.Port, "/-/healthy") 52 | //设置超时 5s。 53 | check.Timeout = "2s" 54 | check.DeregisterCriticalServiceAfter = "5s" 55 | //设置间隔 5s。 56 | check.Interval = "5s" 57 | //注册check服务。 58 | reg.Check = check 59 | 60 | return c.consul.Agent().ServiceRegister(reg) 61 | } 62 | 63 | // DeRegister a service with consul local agent 64 | func (c *client) DeRegister(id string) error { 65 | return c.consul.Agent().ServiceDeregister(id) 66 | } 67 | 68 | //// Service return a service 69 | //func (c *client) GetService(service, tag string) ([]string, error) { 70 | // passingOnly := true 71 | // addrs, _, err := c.consul.Health().Service(service, tag, passingOnly, nil) 72 | // if len(addrs) == 0 && err == nil { 73 | // return nil, fmt.Errorf("service ( %s ) was not found", service) 74 | // } 75 | // 76 | // if err != nil { 77 | // return nil, err 78 | // } 79 | // var hs []string 80 | // 81 | // for _, a := range addrs { 82 | // 83 | // hs = append(hs, fmt.Sprintf("%s:%d", a.Service.Address, a.Service.Port)) 84 | // } 85 | // if len(hs) > 0 { 86 | // NodeUpdateChan <- hs 87 | // } 88 | // 89 | // return hs, nil 90 | //} 91 | 92 | func RegisterFromFile(c *client, servers []string, srvName string, srvPort int) (errors []error) { 93 | 94 | for _, addr := range servers { 95 | 96 | e := c.ServiceRegister(srvName, addr, srvPort) 97 | if e != nil { 98 | errors = append(errors, e) 99 | } 100 | 101 | } 102 | return 103 | } 104 | func (c *client) RunRefreshServiceNode(ctx context.Context, srvName string, consulServerAddr string) error { 105 | level.Info(c.logger).Log("msg", "RunRefreshServiceNode start....") 106 | go RunReshardHashRing(ctx, c.logger) 107 | 108 | errchan := make(chan error, 1) 109 | go func() { 110 | errchan <- c.WatchService(ctx, srvName, consulServerAddr) 111 | 112 | }() 113 | select { 114 | case <-ctx.Done(): 115 | level.Info(c.logger).Log("msg", "RunRefreshServiceNode_receive_quit_signal_and_quit") 116 | return nil 117 | case err := <-errchan: 118 | level.Error(c.logger).Log("msg", "WatchService_get_error", "err", err) 119 | return err 120 | } 121 | return nil 122 | } 123 | 124 | func (c *client) WatchService(ctx context.Context, srvName string, consulServerAddr string) error { 125 | 126 | watchConfig := make(map[string]interface{}) 127 | 128 | watchConfig["type"] = "service" 129 | watchConfig["service"] = srvName 130 | watchConfig["handler_type"] = "script" 131 | watchConfig["passingonly"] = true 132 | watchPlan, err := watch.Parse(watchConfig) 133 | if err != nil { 134 | level.Error(c.logger).Log("msg", "create_Watch_by_watch_config_error", "srv_name", srvName, "error", err) 135 | return err 136 | 137 | } 138 | 139 | watchPlan.Handler = func(lastIndex uint64, result interface{}) { 140 | if entries, ok := result.([]*consul.ServiceEntry); ok { 141 | var hs []string 142 | 143 | for _, a := range entries { 144 | 145 | hs = append(hs, fmt.Sprintf("%s:%d", a.Service.Address, a.Service.Port)) 146 | } 147 | if len(hs) > 0 { 148 | level.Info(c.logger).Log("msg", "service_node_change_by_healthy_check", "srv_name", srvName, "num", len(hs), "detail", strings.Join(hs, " ")) 149 | NodeUpdateChan <- hs 150 | } 151 | 152 | } 153 | 154 | } 155 | if err := watchPlan.Run(consulServerAddr); err != nil { 156 | level.Error(c.logger).Log("msg", "watchPlan_run_error", "srv_name", srvName, "error", err) 157 | return err 158 | } 159 | return nil 160 | 161 | } 162 | -------------------------------------------------------------------------------- /pkg/web/controller/pushgateway/pgw_controller.go: -------------------------------------------------------------------------------- 1 | package pushgateway 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | 9 | "dynamic-sharding/pkg/sd" 10 | ) 11 | 12 | func PushMetricsGetHash(c *gin.Context) { 13 | 14 | path := c.Request.URL.Path 15 | 16 | node, err := sd.PgwNodeRing.GetNode(path) 17 | if err != nil { 18 | c.String(http.StatusInternalServerError, "get_node_from_hashring_error") 19 | } 20 | 21 | nextUrl := "http://" + node + path 22 | log.Printf("[PushMetrics][request_path:%s][redirect_url:%s]", path, nextUrl) 23 | c.String(http.StatusOK, "nextUrl:"+nextUrl) 24 | 25 | } 26 | 27 | func PushMetricsRedirect(c *gin.Context) { 28 | 29 | path := c.Request.URL.Path 30 | 31 | node, err := sd.PgwNodeRing.GetNode(path) 32 | if err != nil { 33 | c.String(http.StatusInternalServerError, "get_node_from_hashring_error") 34 | } 35 | 36 | nextUrl := "http://" + node + path 37 | log.Printf("[PushMetrics][request_path:%s][redirect_url:%s]", path, nextUrl) 38 | //c.Redirect(http.StatusMovedPermanently, nextUrl) 39 | c.Redirect(http.StatusTemporaryRedirect, nextUrl) 40 | //c.Redirect(http.StatusPermanentRedirect, nextUrl) 41 | c.Abort() 42 | 43 | } 44 | -------------------------------------------------------------------------------- /pkg/web/controller/pushgateway/pgw_route.go: -------------------------------------------------------------------------------- 1 | package pushgateway 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func Routes(r *gin.Engine) { 10 | 11 | authapi := r.Group("/metrics/job") 12 | authapi.GET("/*any", PushMetricsGetHash) 13 | authapi.PUT("/*any", PushMetricsRedirect) 14 | authapi.POST("/*any", PushMetricsRedirect) 15 | 16 | tapi := r.Group("/test") 17 | tapi.GET("/v1", func(c *gin.Context) { 18 | c.String(http.StatusOK, "Hello, I'm pgw gateway+ (。A。)") 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/web/gin.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "time" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | 9 | "dynamic-sharding/pkg/web/controller/pushgateway" 10 | ) 11 | 12 | func StartGin(port string, r *gin.Engine) error { 13 | 14 | pushgateway.Routes(r) 15 | s := &http.Server{ 16 | Addr: port, 17 | Handler: r, 18 | ReadTimeout: time.Duration(5) * time.Second, 19 | WriteTimeout: time.Duration(5) * time.Second, 20 | MaxHeaderBytes: 1 << 20, 21 | } 22 | 23 | err := s.ListenAndServe() 24 | return err 25 | 26 | } 27 | --------------------------------------------------------------------------------