This is an automated email from the ASF dual-hosted git repository. github-bot pushed a commit to branch asf-site in repository https://gitbox.apache.org/repos/asf/dubbo-website.git
The following commit(s) were added to refs/heads/asf-site by this push: new 6905928 Automated deployment: Sat Mar 7 16:23:13 UTC 2020 1c41196ff38c31a49f925910510849921386112a 6905928 is described below commit 6905928fccfcd7d0d62f96010d027e09e9cb8618 Author: lovepoem <lovep...@users.noreply.github.com> AuthorDate: Sat Mar 7 16:23:13 2020 +0000 Automated deployment: Sat Mar 7 16:23:13 UTC 2020 1c41196ff38c31a49f925910510849921386112a --- build/blog.js | 2 +- .../consistent-hash-balance-model.jpg | Bin 0 -> 29205 bytes .../consistent-hash-delete-node-model.jpg | Bin 0 -> 32314 bytes .../consistenthash/consistent-hash-init-model.jpg | Bin 0 -> 29515 bytes .../consistent-hash-new-node-model.jpg | Bin 0 -> 35015 bytes .../consistent-hash-request-model.jpg | Bin 0 -> 34165 bytes .../consistent-hash-virtual-node-model.jpg | Bin 0 -> 33019 bytes md_json/blog.json | 9 ++ .../blog/dubbo-consistent-hash-implementation.html | 96 +++++++++++++++++++++ .../blog/dubbo-consistent-hash-implementation.json | 10 +++ zh-cn/blog/index.html | 2 +- 11 files changed, 117 insertions(+), 2 deletions(-) diff --git a/build/blog.js b/build/blog.js index dad8a76..c4d80e8 100644 --- a/build/blog.js +++ b/build/blog.js @@ -1,4 +1,4 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=317 [...] +!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/build/",t(t.s=317 [...] Copyright (c) 2017 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames diff --git a/img/blog/consistenthash/consistent-hash-balance-model.jpg b/img/blog/consistenthash/consistent-hash-balance-model.jpg new file mode 100644 index 0000000..9bcee0c Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-balance-model.jpg differ diff --git a/img/blog/consistenthash/consistent-hash-delete-node-model.jpg b/img/blog/consistenthash/consistent-hash-delete-node-model.jpg new file mode 100644 index 0000000..a07e294 Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-delete-node-model.jpg differ diff --git a/img/blog/consistenthash/consistent-hash-init-model.jpg b/img/blog/consistenthash/consistent-hash-init-model.jpg new file mode 100644 index 0000000..bcbbc00 Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-init-model.jpg differ diff --git a/img/blog/consistenthash/consistent-hash-new-node-model.jpg b/img/blog/consistenthash/consistent-hash-new-node-model.jpg new file mode 100644 index 0000000..1af435b Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-new-node-model.jpg differ diff --git a/img/blog/consistenthash/consistent-hash-request-model.jpg b/img/blog/consistenthash/consistent-hash-request-model.jpg new file mode 100644 index 0000000..fb5f3d4 Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-request-model.jpg differ diff --git a/img/blog/consistenthash/consistent-hash-virtual-node-model.jpg b/img/blog/consistenthash/consistent-hash-virtual-node-model.jpg new file mode 100644 index 0000000..b9de63d Binary files /dev/null and b/img/blog/consistenthash/consistent-hash-virtual-node-model.jpg differ diff --git a/md_json/blog.json b/md_json/blog.json index 861d294..8e75d14 100644 --- a/md_json/blog.json +++ b/md_json/blog.json @@ -407,6 +407,15 @@ } }, { + "filename": "dubbo-consistent-hash-implementation.md", + "link": "/zh-cn/blog/dubbo-consistent-hash-implementation.html", + "meta": { + "title": "Dubbo一致性Hash负载均衡实现剖析", + "keywords": "Dubbo, Consistent Hash,一致性Hash,一致性哈希", + "description": "本文以一般的一致性Hash实现作为引子,详细剖析了Dubbo一致性Hash负载均衡算法的实现" + } + }, + { "filename": "dubbo-context-information.md", "link": "/zh-cn/blog/dubbo-context-information.html", "meta": { diff --git a/zh-cn/blog/dubbo-consistent-hash-implementation.html b/zh-cn/blog/dubbo-consistent-hash-implementation.html new file mode 100644 index 0000000..be85f06 --- /dev/null +++ b/zh-cn/blog/dubbo-consistent-hash-implementation.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <meta name="keywords" content="Dubbo, Consistent Hash,一致性Hash,一致性哈希" /> + <meta name="description" content="本文以一般的一致性Hash实现作为引子,详细剖析了Dubbo一致性Hash负载均衡算法的实现" /> + <!-- 网页标签标题 --> + <title>Dubbo一致性Hash负载均衡实现剖析</title> + <link rel="shortcut icon" href="/img/dubbo.ico"/> + <link rel="stylesheet" href="/build/blogDetail.css" /> +</head> +<body> + <div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a h [...] +<h3>一、环形队列Hash映射模型</h3> +<p>这种方案,其基础还是基于取模运算。对2^32取模,那么,Hash值的区间为[0, 2^32-1]。接下来要做的,就包括两部分:</p> +<h4><strong>a、映射服务</strong></h4> +<p>将服务地址(ip+端口)按照一定规则构造出特定的识别码(如md5码),再用识别码对2^32取模,确定服务在Hash值区间对应的位置。假设有Node1、Node2、Node3三个服务,其映射关系如下:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-init-model.jpg" alt="Init"></p> +<h4><strong>b、映射请求、定位服务</strong></h4> +<p>在发起请求时,我们往往会带上参数,而这些参数,就可以被我们用来确定具体调用哪一个服务。假设有请求R1、R2、R3,对它们的参数也经过计算特定识别码、取余的一系列运算之后,有如下映射关系:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-request-model.jpg" alt="Request"></p> +<p>从图中,我们可以看到,R1请求映射在0-Node1中间,R2请求映射在Node1-Node2中间,R3请求映射在Node2-Node3中间。我们取<strong>服务Hash值大于请求Hash值</strong>的<strong>第一个服务</strong>作为实际的调用服务。也就是说,R1请求将调用Node1服务,R2请求将调用Node2服务,R3请求将调用Node3服务。</p> +<h4><strong>c、新增服务节点</strong></h4> +<p>假设新增服务Node4,映射在Node3之前,恰巧破坏了原来的一个映射关系:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-new-node-model.jpg" alt="New Node"></p> +<p>这样,请求R3将会实际调用服务Node4,但请求R1、R2不受影响。</p> +<h4><strong>d、删除服务节点</strong></h4> +<p>假设服务Node2宕机,那么R2请求将会映射到Node3:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-delete-node-model.jpg" alt="Delete Node"></p> +<p>原本的R1、R3请求不受影响。</p> +<blockquote> +<p>可以看出,当新增、删除服务时,受影响的请求是有限的。不至于像简单取模映射一般,服务发生变化时,需要调整全局的映射关系。</p> +</blockquote> +<h4><strong>e、平衡性与虚拟节点</strong></h4> +<p>在我们上面的假设中,我们假设Node1、Node2、Node3三个服务在经过Hash映射后所分布的位置恰巧把环切成了均等的三分,请求的分布也基本是平衡的。但是实际上计算服务Hash值的时候,是很难这么巧的。也许一不小心就映射成了这个样子:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-balance-model.jpg" alt="Balance"></p> +<p>这样,就会导致大部分请求都会被映射到Node1上。因此,引出了虚拟节点。</p> +<p>所谓虚拟节点,就是除了对服务本身地址进行Hash映射外,还通过在它地址上做些处理(比如Dubbo中,在ip+port的字符串后加上计数符1、2、3......,分别代表虚拟节点1、2、3),以达到同一服务映射多个节点的目的。通过引入虚拟节点,我们可以把上图中映射给Node1的请求进一步拆分:</p> +<p><img src="../../img/blog/consistenthash/consistent-hash-virtual-node-model.jpg" alt="Virtual Node"></p> +<p>如上图所示,若有请求落在Node3-Node1'区间,该请求应该是调用Node1'服务,但是因为Node1'是Node1的虚拟节点,所以实际调用的是Node1服务。通过引入虚拟节点,请求的分布就会比较平衡了。</p> +<h3><strong>二、Dubbo一致性Hash的使用与负载均衡策略的引入阶段</strong></h3> +<h4><strong>a、如何使用一致性Hash作为Dubbo的负载均衡策略?</strong></h4> +<p>dubbo:service、dubbo:reference、dubbo:provider、dubbo:consumer、dubbo:method这几个配置项都可以配置Dubbo的负载均衡策略,其中一致性Hash的属性值是:<strong>consistenthash</strong>。</p> +<p>以dubbo:reference为例:</p> +<p><strong>XML配置:</strong></p> +<blockquote> +<p><dubbo:reference loadbalance="consistenthash" /></p> +</blockquote> +<p><strong>Properties配置:</strong></p> +<blockquote> +<p>dubbo.reference.loadbalance=consistenthash</p> +</blockquote> +<p><strong>注解:</strong></p> +<blockquote> +<p>@Reference(loadbalance = "consistenthash")</p> +</blockquote> +<h4><strong>b、Dubbo负载均衡策略的引入阶段</strong></h4> +<p>Dubbo实现的是客户端负载均衡。关于服务接口代理类的实现,这里不做详细描述,可以参考官网:</p> +<blockquote> +<p>服务引入:<a href="http://dubbo.apache.org/zh-cn/docs/source_code_guide/refer-service.html%E3%80%82">http://dubbo.apache.org/zh-cn/docs/source_code_guide/refer-service.html。</a></p> +</blockquote> +<p>在接口代理类生成、并且装配好后,服务的调用基本是这样一个流程:proxy -> MockClusterInvoker -> 集群策略(如:FailoverClusterInvoker) -> 根据选定的负载均衡策略确定选定的远程调用对象Invoker。</p> +<p><strong>负载均衡策略的初始化</strong>是在AbstractClusterInvoker中的initLoadBalance方法中初始化的:</p> +<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">protected</span> LoadBalance <span class="hljs-title">initLoadBalance</span><span class="hljs-params">(List<Invoker<T>> invokers, Invocation invocation)</span> </span>{ + <span class="hljs-keyword">if</span> (CollectionUtils.isNotEmpty(invokers)) { + <span class="hljs-keyword">return</span> ExtensionLoader.getExtensionLoader(LoadBalance<span class="hljs-class">.<span class="hljs-keyword">class</span>).<span class="hljs-title">getExtension</span>(<span class="hljs-title">invokers</span>.<span class="hljs-title">get</span>(0).<span class="hljs-title">getUrl</span>() + .<span class="hljs-title">getMethodParameter</span>(<span class="hljs-title">RpcUtils</span>.<span class="hljs-title">getMethodName</span>(<span class="hljs-title">invocation</span>), <span class="hljs-title">LOADBALANCE_KEY</span>, <span class="hljs-title">DEFAULT_LOADBALANCE</span>))</span>; + } <span class="hljs-keyword">else</span> { + <span class="hljs-keyword">return</span> ExtensionLoader.getExtensionLoader(LoadBalance<span class="hljs-class">.<span class="hljs-keyword">class</span>).<span class="hljs-title">getExtension</span>(<span class="hljs-title">DEFAULT_LOADBALANCE</span>)</span>; + } +} +</code></pre> +<p>这部分代码逻辑分为两部分:</p> +<p>1、获取调用方法所配置的LOADBALANCE_KEY属性的值,LOADBALANCE_KEY这个常量的实际值为:loadbalance,即为我们的所配置的属性;</p> +<p>2、利用SPI机制来初始化并加载该值所代表的负载均衡策略。</p> +<p>所有的负载均衡策略都会继承LoadBalance接口。在各种集群策略中,最终都会调用AbstractClusterInvoker的select方法,而AbstractClusterInvoker会在doSelect中,<strong>调用LoadBalance的select方法,这里即开始了负载均衡策略的执行。</strong></p> +</section><footer class="footer-container"><div class="footer-body"><img src="/img/dubbo_gray.png"/><img class="apache" src="/img/apache_logo.png"/><div class="cols-container"><div class="col col-12"><h3></h3><p></p></div><div class="col col-4"><dl><dt>ASF</dt><dd><a href="http://www.apache.org" target="_self">基金会</a></dd><dd><a href="http://www.apache.org/licenses/" target="_self">证书</a></dd><dd><a href="http://www.apache.org/events/current-event" target="_self">事件</a></dd><dd><a href=" [...] + <script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script> + <script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script> + <script> + window.rootPath = ''; + </script> + <script src="/build/blogDetail.js"></script> + <!-- Global site tag (gtag.js) - Google Analytics --> + <script async src="https://www.googletagmanager.com/gtag/js?id=UA-112489517-1"></script> + <script> + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + + gtag('config', 'UA-112489517-1'); + </script> +</body> +</html> \ No newline at end of file diff --git a/zh-cn/blog/dubbo-consistent-hash-implementation.json b/zh-cn/blog/dubbo-consistent-hash-implementation.json new file mode 100644 index 0000000..4b99bfc --- /dev/null +++ b/zh-cn/blog/dubbo-consistent-hash-implementation.json @@ -0,0 +1,10 @@ +{ + "filename": "dubbo-consistent-hash-implementation.md", + "__html": "<p>需要强调的是,Dubbo的Hash映射模型与大部分网上资料描述的<strong>环形队列Hash映射模型</strong>是存在一些区别的。于我而言,环形队列Hash映射模型,不足以让我对一致性Hash有足够彻底的了解。直到看懂了Dubbo的一致性Hash的实现,才觉得豁然开朗。</p>\n<h3>一、环形队列Hash映射模型</h3>\n<p>这种方案,其基础还是基于取模运算。对2^32取模,那么,Hash值的区间为[0, 2^32-1]。接下来要做的,就包括两部分:</p>\n<h4><strong>a、映射服务</strong></h4>\n<p>将服务地址(ip+端口)按照一定规则构造出特定的识别码(如md5码),再用识别码对2^32取模,确定服务在Hash值区间对应的位置。假设有Node1、Node2、Node3三个服务,其映射关系如下:</p>\n<p><img src=\"../../img/blog/consistenthash/consistent-hash-init-model.jpg\" alt=\"Init\">< [...] + "link": "/zh-cn/blog/dubbo-consistent-hash-implementation.html", + "meta": { + "title": "Dubbo一致性Hash负载均衡实现剖析", + "keywords": "Dubbo, Consistent Hash,一致性Hash,一致性哈希", + "description": "本文以一般的一致性Hash实现作为引子,详细剖析了Dubbo一致性Hash负载均衡算法的实现" + } +} \ No newline at end of file diff --git a/zh-cn/blog/index.html b/zh-cn/blog/index.html index 0f2e582..ea6de38 100644 --- a/zh-cn/blog/index.html +++ b/zh-cn/blog/index.html @@ -12,7 +12,7 @@ <link rel="stylesheet" href="/build/blog.css" /> </head> <body> - <div id="root"><div class="blog-list-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a hre [...] + <div id="root"><div class="blog-list-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/dubbo_colorful.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a hre [...] <script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script> <script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script> <script>