<!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:TrackMoves/> <w:TrackFormatting/> <w:PunctuationKerning/> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:DoNotPromoteQF/> <w:LidThemeOther>EN-US</w:LidThemeOther> <w:LidThemeAsian>ZH-CN</w:LidThemeAsian> <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> <w:Compatibility> <w:SpaceForUL/> <w:BalanceSingleByteDoubleByteWidth/> <w:DoNotLeaveBackslashAlone/> <w:ULTrailSpace/> <w:DoNotExpandShiftReturn/> <w:AdjustLineHeightInTable/> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:SplitPgBreakAndParaMark/> <w:DontVertAlignCellWithSp/> <w:DontBreakConstrainedForcedTables/> <w:DontVertAlignInTxbx/> <w:Word11KerningPairs/> <w:CachedColBalance/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> <m:mathPr> <m:mathFont m:val="Cambria Math"/> <m:brkBin m:val="before"/> <m:brkBinSub m:val="--"/> <m:smallFrac m:val="off"/> <m:dispDef/> <m:lMargin m:val="0"/> <m:rMargin m:val="0"/> <m:defJc m:val="centerGroup"/> <m:wrapIndent m:val="1440"/> <m:intLim m:val="subSup"/> <m:naryLim m:val="undOvr"/> </m:mathPr></w:WordDocument> </xml><![endif]-->
<!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" DefSemiHidden="true" DefQFormat="false" DefPriority="99" LatentStyleCount="267"> <w:LsdException Locked="false" Priority="0" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Normal"/> <w:LsdException Locked="false" Priority="9" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> <w:LsdException Locked="false" Priority="39" Name="toc 1"/> <w:LsdException Locked="false" Priority="39" Name="toc 2"/> <w:LsdException Locked="false" Priority="39" Name="toc 3"/> <w:LsdException Locked="false" Priority="39" Name="toc 4"/> <w:LsdException Locked="false" Priority="39" Name="toc 5"/> <w:LsdException Locked="false" Priority="39" Name="toc 6"/> <w:LsdException Locked="false" Priority="39" Name="toc 7"/> <w:LsdException Locked="false" Priority="39" Name="toc 8"/> <w:LsdException Locked="false" Priority="39" Name="toc 9"/> <w:LsdException Locked="false" Priority="0" Name="header"/> <w:LsdException Locked="false" Priority="0" Name="footer"/> <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> <w:LsdException Locked="false" Priority="10" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Title"/> <w:LsdException Locked="false" Priority="0" Name="Default Paragraph Font"/> <w:LsdException Locked="false" Priority="11" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> <w:LsdException Locked="false" Priority="22" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Strong"/> <w:LsdException Locked="false" Priority="20" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> <w:LsdException Locked="false" Priority="59" SemiHidden="false" UnhideWhenUsed="false" Name="Table Grid"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> <w:LsdException Locked="false" Priority="1" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 1"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 1"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 1"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> <w:LsdException Locked="false" Priority="34" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> <w:LsdException Locked="false" Priority="29" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Quote"/> <w:LsdException Locked="false" Priority="30" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 1"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 1"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 2"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 2"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 2"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 2"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 2"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 3"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 3"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 3"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 3"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 3"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 4"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 4"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 4"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 4"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 4"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 5"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 5"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 5"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 5"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 5"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> <w:LsdException Locked="false" Priority="60" SemiHidden="false" UnhideWhenUsed="false" Name="Light Shading Accent 6"/> <w:LsdException Locked="false" Priority="61" SemiHidden="false" UnhideWhenUsed="false" Name="Light List Accent 6"/> <w:LsdException Locked="false" Priority="62" SemiHidden="false" UnhideWhenUsed="false" Name="Light Grid Accent 6"/> <w:LsdException Locked="false" Priority="63" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> <w:LsdException Locked="false" Priority="64" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> <w:LsdException Locked="false" Priority="65" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> <w:LsdException Locked="false" Priority="66" SemiHidden="false" UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> <w:LsdException Locked="false" Priority="67" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> <w:LsdException Locked="false" Priority="68" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> <w:LsdException Locked="false" Priority="69" SemiHidden="false" UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> <w:LsdException Locked="false" Priority="70" SemiHidden="false" UnhideWhenUsed="false" Name="Dark List Accent 6"/> <w:LsdException Locked="false" Priority="71" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> <w:LsdException Locked="false" Priority="72" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful List Accent 6"/> <w:LsdException Locked="false" Priority="73" SemiHidden="false" UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> <w:LsdException Locked="false" Priority="19" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> <w:LsdException Locked="false" Priority="21" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> <w:LsdException Locked="false" Priority="31" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> <w:LsdException Locked="false" Priority="32" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> <w:LsdException Locked="false" Priority="33" SemiHidden="false" UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> </w:LatentStyles> </xml><![endif]--><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman","serif";} </style> <![endif]-->
入门
(+) (#)
背景
(#)
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
· 单一应用架构
· 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。
· 此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。
· 垂直应用架构
· 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。
· 此时,用于加速前端页面开发的 Web框架(MVC) 是关键。
· 分布式服务架构
· 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
· 此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
· 流动计算架构
· 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
· 此时,用于提高机器利用率的 资源调度和治理中心(SOA) 是关键。
需求
(#)
在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。
(1) 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。
并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。
(2) 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。
(3) 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
以上是Dubbo最基本的几个需求,更多服务治理问题参见:
http://code.alibabatech.com/blog/experience_1402/service-governance-process.html
架构
(#)
节点角色说明:
· Provider: 暴露服务的服务提供方。
· Consumer: 调用远程服务的服务消费方。
· Registry: 服务注册与发现的注册中心。
· Monitor: 统计服务的调用次调和调用时间的监控中心。
· Container: 服务运行容器。
调用关系说明:
· 0. 服务容器负责启动,加载,运行服务提供者。
· 1. 服务提供者在启动时,向注册中心注册自己提供的服务。
· 2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
· 3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
· 4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
· 5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
(1) 连通性:
· 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
· 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
· 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
· 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
· 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
· 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
· 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
· 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
(2) 健状性:
· 监控中心宕掉不影响使用,只是丢失部分采样数据
· 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
· 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
· 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
· 服务提供者无状态,任意一台宕掉后,不影响使用
· 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
(3) 伸缩性:
· 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
· 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
(4) 升级性:
· 当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力:
· Deployer: 自动部署服务的本地代理。
· Repository: 仓库用于存储服务应用发布包。
· Scheduler: 调度中心基于访问压力自动增减服务提供者。
· Admin: 统一管理控制台。
用法
(#)
本地服务:(Spring配置)
local.xml
<beanid=“xxxService” class=“com.xxx.XxxServiceImpl” />
<beanid=“xxxAction” class=“com.xxx.XxxAction”> <propertyname=“xxxService” ref=“xxxService” /> </bean> |
远程服务:(Spring配置)
在本地服务的基础上,只需做简单配置,即可完成远程化:
· 将上面的local.xml配置拆分成两份,将服务定义部分放在服务提供方remote-provider.xml,将服务引用部分放在服务消费方remote-consumer.xml。
· 并在提供方增加暴露服务配置<dubbo:service>,在消费方增加引用服务配置<dubbo:reference>。
如下:
remote-provider.xml
<beanid=“xxxService” class=“com.xxx.XxxServiceImpl” /><!-- 和本地服务一样实现远程服务 -->
<dubbo:serviceinterface=“com.xxx.XxxService” ref=“xxxService” /><!-- 增加暴露远程服务配置 --> |
remote-consumer.xml
<dubbo:referenceid=“xxxService” interface=“com.xxx.XxxService” /><!-- 增加引用远程服务配置 -->
<beanid=“xxxAction” class=“com.xxx.XxxAction”><!-- 和本地服务一样使用远程服务 --> <propertyname=“xxxService” ref=“xxxService” /> </bean> |
快速启动
(+) (#)
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。 |
|
如果不想使用Spring配置,而希望通过API的方式进行调用(不推荐),请参见:API配置 (+) |
服务提供者
(#)
完整安装步骤,请参见:示例提供者安装 (+) |
定义服务接口: (该接口需单独打包,在服务提供方和消费方共享)
DemoService.java
packagecom.alibaba.dubbo.demo;
publicinterfaceDemoService {
String sayHello(String name);
} |
在服务提供方实现接口:(对服务消费方隐藏实现)
DemoServiceImpl.java
packagecom.alibaba.dubbo.demo.provider;
importcom.alibaba.dubbo.demo.DemoService;
publicclassDemoServiceImplimplementsDemoService {
publicString sayHello(String name) { return"Hello "+ name; }
} |
用Spring配置声明暴露服务:
provider.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:applicationname="hello-world-app" />
<!-- 使用multicast广播注册中心暴露服务地址 --> <dubbo:registryaddress="multicast://224.5.6.7:1234"/>
<!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocolname="dubbo"port="20880"/>
<!-- 声明需要暴露的服务接口 --> <dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoService"ref="demoService"/>
<!-- 和本地bean一样实现服务 --> <beanid="demoService"class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>
</beans> |
加载Spring配置:
Provider.java
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassProvider {
publicstaticvoidmain(String[] args)throwsException { ClassPathXmlApplicationContext context =newClassPathXmlApplicationContext(newString[] {"provider.xml"}); context.start();
System.in.read();// 按任意键退出 }
} |
服务消费者
(#)
完整安装步骤,请参见:示例消费者安装 (+) |
通过Spring配置引用远程服务:
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --> <dubbo:applicationname="consumer-of-helloworld-app" />
<!-- 使用multicast广播注册中心暴露发现服务地址 --> <dubbo:registryaddress="multicast://224.5.6.7:1234"/>
<!-- 生成远程服务代理,可以和本地bean一样使用demoService --> <dubbo:referenceid="demoService"interface="com.alibaba.dubbo.demo.DemoService"/>
</beans> |
加载Spring配置,并调用远程服务:(也可以使用IoC注入)
Consumer.java
importorg.springframework.context.support.ClassPathXmlApplicationContext; importcom.alibaba.dubbo.demo.DemoService;
publicclassConsumer {
publicstaticvoidmain(String[] args)throwsException { ClassPathXmlApplicationContext context =newClassPathXmlApplicationContext(newString[] {"consumer.xml"}); context.start();
DemoService demoService = (DemoService)context.getBean("demoService");// 获取远程服务代理 String hello = demoService.sayHello("world");// 执行远程方法
System.out.println( hello );// 显示调用结果 }
} |
依赖
(+) (#)
必需依赖
· JDK1.5+
理论上Dubbo可以只依赖JDK,不依赖于任何三方库运行,只需配置使用JDK相关实现策略。 |
缺省依赖
通过mvn dependency:tree > dep.log命令分析,Dubbo缺省依赖以下三方库:
[INFO] +- com.alibaba:dubbo:jar:2.1.2:compile [INFO] | +- log4j:log4j:jar:1.2.16:compile [INFO] | +- org.javassist:javassist:jar:3.15.0-GA:compile [INFO] | +- org.springframework:spring:jar:2.5.6.SEC03:compile [INFO] | +- commons-logging:commons-logging:jar:1.1.1:compile [INFO] | \- org.jboss.netty:netty:jar:3.2.5.Final:compile |
这里所有依赖都是换照Dubbo缺省配置选的,这些缺省值是基于稳定性和性能考虑的。
· log4j.jar和commons-logging.jar日志输出包。
· 可以直接去掉,dubbo本身的日志会自动切换为JDK的java.util.logging输出。
· 但如果其它三方库比如spring.jar间接依赖commons-logging,则不能去掉。
· javassist.jar 字节码生成。
· 如果<dubbo:provider proxy="jdk" />或<dubbo:consumer proxy="jdk" />,以及<dubbo:application compiler="jdk" />,则不需要。
· spring.jar 配置解析。
· 如果用ServiceConfig和ReferenceConfig的API调用,则不需要。
· netty.jar 网络传输。
· 如果<dubbo:protocol server="mina"/>或<dubbo:protocol server="grizzly"/>,则换成mina.jar或grizzly.jar。
· 如果<protocol name="rmi"/>,则不需要。
可选依赖
以下依赖,在主动配置使用相应实现策略时用到,需自行加入依赖。
· mina: 1.1.7
· grizzly: 2.1.4
· httpclient: 4.1.2
· hessian_lite: 3.2.1-fixed
· xstream: 1.4.1
· fastjson: 1.1.8
· zookeeper: 3.3.3
· jedis: 2.0.0
· xmemcached: 1.3.6
· jfreechart: 1.0.13
· hessian: 4.0.7
· jetty: 6.1.26
· hibernate-validator: 4.2.0.Final
· zkclient: 0.1
· curator: 1.1.10
· cxf: 2.6.1
· thrift: 0.8.0
JEE:
· servlet: 2.5
· bsf: 3.1
· validation-api: 1.0.0.GA
· jcache: 0.4
成熟度
(+) (#)
功能成熟度
(#)
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
并发控制 |
Tested |
并发控制 |
|
试用 |
|
连接控制 |
Tested |
连接数控制 |
|
试用 |
|
直连提供者 |
Tested |
点对点直连服务提供方,用于测试 |
|
测试环境使用 |
Alibaba |
分组聚合 |
Tested |
分组聚合返回值,用于菜单聚合等服务 |
特殊场景使用 |
可用于生产环境 |
|
参数验证 |
Tested |
参数验证,JSR303验证框架集成 |
对性能有影响 |
试用 |
LaiWang |
结果缓存 |
Tested |
结果缓存,用于加速请求 |
|
试用 |
|
泛化引用 |
Stable |
泛化调用,无需业务接口类进行远程调用,用于测试平台,开放网关桥接等 |
|
可用于生产环境 |
Alibaba |
泛化实现 |
Stable |
泛化实现,无需业务接口类实现任意接口,用于Mock平台 |
|
可用于生产环境 |
Alibaba |
回声测试 |
Tested |
回声测试 |
|
试用 |
|
隐式传参 |
Stable |
附加参数 |
|
可用于生产环境 |
|
异步调用 |
Tested |
不可靠异步调用 |
|
试用 |
|
本地调用 |
Tested |
本地调用 |
|
试用 |
|
参数回调 |
Tested |
参数回调 |
特殊场景使用 |
试用 |
Registry |
事件通知 |
Tested |
事件通知,在远程调用执行前后触发 |
|
试用 |
|
本地存根 |
Stable |
在客户端执行部分逻辑 |
|
可用于生产环境 |
Alibaba |
本地伪装 |
Stable |
伪造返回结果,可在失败时执行,或直接执行,用于服务降级 |
需注册中心支持 |
可用于生产环境 |
Alibaba |
延迟暴露 |
Stable |
延迟暴露服务,用于等待应用加载warmup数据,或等待spring加载完成 |
|
可用于生产环境 |
Alibaba |
延迟连接 |
Tested |
延迟建立连接,调用时建立 |
|
试用 |
Registry |
粘滞连接 |
Tested |
粘滞连接,总是向同一个提供方发起请求,除非此提供方挂掉,再切换到另一台 |
|
试用 |
Registry |
令牌验证 |
Tested |
令牌验证,用于服务授权 |
需注册中心支持 |
试用 |
|
路由规则 |
Tested |
动态决定调用关系 |
需注册中心支持 |
试用 |
|
配置规则 |
Tested |
动态下发配置,实现功能的开关 |
需注册中心支持 |
试用 |
|
访问日志 |
Tested |
访问日志,用于记录调用信息 |
本地存储,影响性能,受磁盘大小限制 |
试用 |
|
分布式事务 |
Research |
JTA/XA三阶段提交事务 |
不稳定 |
不可用 |
|
策略成熟度
(#)
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Zookeeper注册中心 |
Stable |
支持基于网络的集群方式,有广泛周边开源产品,建议使用dubbo-2.3.3以上版本(推荐使用) |
依赖于Zookeeper的稳定性 |
可用于生产环境 |
|
Redis注册中心 |
Stable |
支持基于客户端双写的集群方式,性能高 |
要求服务器时间同步,用于检查心跳过期脏数据 |
可用于生产环境 |
|
Multicast注册中心 |
Tested |
去中心化,不需要安装注册中心 |
依赖于网络拓普和路由,跨机房有风险 |
小规模应用或开发测试环境 |
|
Simple注册中心 |
Tested |
Dogfooding,注册中心本身也是一个标准的RPC服务 |
没有集群支持,可能单点故障 |
试用 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Simple监控中心 |
Stable |
支持JFreeChart统计报表 |
没有集群支持,可能单点故障,但故障后不影响RPC运行 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Dubbo协议 |
Stable |
采用NIO复用单一长连接,并使用线程池并发处理请求,减少握手和加大并发效率,性能较好(推荐使用) |
在大文件传输时,单一连接会成为瓶颈 |
可用于生产环境 |
Alibaba |
Rmi协议 |
Stable |
可与原生RMI互操作,基于TCP协议 |
偶尔会连接失败,需重建Stub |
可用于生产环境 |
Alibaba |
Hessian协议 |
Stable |
可与原生Hessian互操作,基于HTTP协议 |
需hessian.jar支持,http短连接的开销大 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Netty Transporter |
Stable |
JBoss的NIO框架,性能较好(推荐使用) |
一次请求派发两种事件,需屏蔽无用事件 |
可用于生产环境 |
Alibaba |
Mina Transporter |
Stable |
老牌NIO框架,稳定 |
待发送消息队列派发不及时,大压力下,会出现FullGC |
可用于生产环境 |
Alibaba |
Grizzly Transporter |
Tested |
Sun的NIO框架,应用于GlassFish服务器中 |
线程池不可扩展,Filter不能拦截下一Filter |
试用 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Hessian Serialization |
Stable |
性能较好,多语言支持(推荐使用) |
Hessian的各版本兼容性不好,可能和应用使用的Hessian冲突,Dubbo内嵌了hessian3.2.1的源码 |
可用于生产环境 |
Alibaba |
Dubbo Serialization |
Tested |
通过不传送POJO的类元信息,在大量POJO传输时,性能较好 |
当参数对象增加字段时,需外部文件声明 |
试用 |
|
Json Serialization |
Tested |
纯文本,可跨语言解析,缺省采用FastJson解析 |
性能较差 |
试用 |
|
Java Serialization |
Stable |
Java原生支持 |
性能较差 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Javassist ProxyFactory |
Stable |
通过字节码生成代替反射,性能比较好(推荐使用) |
依赖于javassist.jar包,占用JVM的Perm内存,Perm可能要设大一些:java -XX:PermSize=128m |
可用于生产环境 |
Alibaba |
Jdk ProxyFactory |
Stable |
JDK原生支持 |
性能较差 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Failover Cluster |
Stable |
失败自动切换,当出现失败,重试其它服务器,通常用于读操作(推荐使用) |
重试会带来更长延迟 |
可用于生产环境 |
Alibaba |
Failfast Cluster |
Stable |
快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作 |
如果有机器正在重启,可能会出现调用失败 |
可用于生产环境 |
Alibaba |
Failsafe Cluster |
Stable |
失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作 |
调用信息丢失 |
可用于生产环境 |
Monitor |
Failback Cluster |
Tested |
失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作 |
不可靠,重启丢失 |
可用于生产环境 |
Registry |
Forking Cluster |
Tested |
并行调用多个服务器,只要一个成功即返回,通常用于实时性要求较高的读操作 |
需要浪费更多服务资源 |
可用于生产环境 |
|
Broadcast Cluster |
Tested |
广播调用所有提供者,逐个调用,任意一台报错则报错,通常用于更新提供方本地状态 |
速度慢,任意一台报错则报错 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Random LoadBalance |
Stable |
随机,按权重设置随机概率(推荐使用) |
在一个截面上碰撞的概率高,重试时,可能出现瞬间压力不均 |
可用于生产环境 |
Alibaba |
RoundRobin LoadBalance |
Stable |
轮循,按公约后的权重设置轮循比率 |
存在慢的机器累积请求问题,极端情况可能产生雪崩 |
可用于生产环境 |
|
LeastActive LoadBalance |
Stable |
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差,使慢的机器收到更少请求 |
不支持权重,在容量规划时,不能通过权重把压力导向一台机器压测容量 |
可用于生产环境 |
|
ConsistentHash LoadBalance |
Stable |
一致性Hash,相同参数的请求总是发到同一提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动 |
压力分摊不均 |
可用于生产环境 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
条件路由规则 |
Stable |
基于条件表达式的路由规则,功能简单易用 |
有些复杂多分支条件情况,规则很难描述 |
可用于生产环境 |
Alibaba |
脚本路由规则 |
Tested |
基于脚本引擎的路由规则,功能强大 |
没有运行沙箱,脚本能力过于强大,可能成为后门 |
试用 |
|
Feature |
Maturity |
Strength |
Problem |
Advise |
User |
Spring Container |
Stable |
自动加载META-INF/spring目录下的所有Spring配置 |
|
可用于生产环境 |
Alibaba |
Jetty Container |
Stable |
启动一个内嵌Jetty,用于汇报状态 |
大量访问页面时,会影响服务器的线程和内存 |
可用于生产环境 |
Alibaba |
Log4j Container |
Stable |
自动配置log4j的配置,在多进程启动时,自动给日志文件按进程分目录 |
用户不能控制log4j的配置,不灵活 |
可用于生产环境 |
Alibaba |
配置
(+) (#)
Xml配置
(+) (#)
配置项说明 |
||
API使用说明 |
||
配置使用说明 |
示例:
provider.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="hello-world-app" />
<dubbo:registryaddress="multicast://224.5.6.7:1234"/>
<dubbo:protocolname="dubbo"port="20880"/>
<dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoService"ref="demoServiceLocal"/>
<dubbo:referenceid="demoServiceRemote"interface="com.alibaba.dubbo.demo.DemoService"/>
</beans> |
|
所有标签者支持自定义参数,用于不同扩展点实现的特殊配置。 |
如:
<dubbo:protocolname="jms"> <dubbo:parameterkey="queue"value="10.20.31.22"/> </dubbo:protocol> |
或:(2.1.0开始支持)
注意声明:xmlns:p="http://www.springframework.org/schema/p" |
|||
<beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xmlns:p=" http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:protocolname="jms"p:queue="10.20.31.22"/>
</beans> |
|||
Configuration Relation:
· <dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。
· <dubbo:reference/> 引用配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。
· <dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
· <dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
· <dubbo:module/> 模块配置,用于配置当前模块信息,可选。
· <dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。
· <dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。
· <dubbo:provider/> 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
· <dubbo:consumer/> 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。
· <dubbo:method/> 方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。
· <dubbo:argument/> 用于指定方法参数配置。
Configuration Override:
· 上图中以timeout为例,显示了配置的查找顺序,其它retries, loadbalance, actives等类似。
· 方法级优先,接口级次之,全局配置再次之。
· 如果级别一样,则消费方优先,提供方次之。
· 其中,服务提供方配置,通过URL经由注册中心传递给消费方。
· 建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置。
· 理论上ReferenceConfig的非服务标识配置,在ConsumerConfig,ServiceConfig, ProviderConfig均可以缺省配置。
属性配置
(+) (#)
如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个Spring容器想共享配置,可以使用dubbo.properties作为缺省配置。 |
|
Dubbo将自动加载classpath根目录下的dubbo.properties,可以通过JVM启动参数:-Ddubbo.properties.file=xxx.properties 改变缺省配置位置。 |
如果classpath根目录下存在多个dubbo.properties,比如多个jar包中有dubbo.properties,Dubbo会任意加载,并打印Error日志,后续可能改为抛异常。 |
映射规则:
· 将XML配置的标签名,加属性名,用点分隔,多个属性拆成多行:
· 比如:dubbo.application.name=foo等价于<dubbo:application name="foo" />
· 比如:dubbo.registry.address=10.20.153.10:9090等价于<dubbo:registry address="10.20.153.10:9090" />
· 如果XML有多行同名标签配置,可用id号区分,如果没有id号将对所有同名标签生效:
· 比如:dubbo.protocol.rmi.port=1234等价于<dubbo:protocol id="rmi" name="rmi" port="1099" /> (协议的id没配时,缺省使用协议名作为id)
· 比如:dubbo.registry.china.address=10.20.153.10:9090等价于<dubbo:registry id="china" address="10.20.153.10:9090" />
典型配置如:
dubbo.properties
dubbo.application.name=foo dubbo.application.owner=bar dubbo.registry.address=10.20.153.10:9090 |
覆盖策略:
· JVM启动-D参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
· XML次之,如果在XML中有配置,则dubbo.properties中的相应配置项无效。
· Properties最后,相当于缺省值,只有XML没有配置时,dubbo.properties的相应配置项才会生效,通常用于共享公共配置,比如应用名。
注解配置
(+) (#)
2.2.1以上版本支持 |
服务提供方注解:
importcom.alibaba.dubbo.config.annotation.Service;
@Service(version="1.0.0") publicclassFooServiceImplimplementsFooService {
// ......
} |
服务提供方配置:
<!-- 公共信息,也可以用dubbo.properties配置 --> <dubbo:applicationname="annotation-provider"/> <dubbo:registryaddress="127.0.0.1:4548"/>
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 --> <dubbo:annotationpackage="com.foo.bar.service"/> |
服务消费方注解:
importcom.alibaba.dubbo.config.annotation.Reference; importorg.springframework.stereotype.Component;
@Component publicclassBarAction {
@Reference(version="1.0.0") privateFooService fooService;
} |
服务消费方配置:
<!-- 公共信息,也可以用dubbo.properties配置 --> <dubbo:applicationname="annotation-consumer"/> <dubbo:registryaddress="127.0.0.1:4548"/>
<!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 --> <dubbo:annotationpackage="com.foo.bar.action"/> |
也可以使用:(等价于前面的:<dubbo:annotation package="com.foo.bar.service" />)
<dubbo:annotation/> <context:component-scanbase-package="com.foo.bar.service"> <context:include-filtertype="annotation"expression="com.alibaba.dubbo.config.annotation.Service"/> </context:component-scan> |
||
Spring2.5及以后版本支持component-scan,如果用的是Spring2.0及以前版本,需配置:
|
||
API配置
(+) (#)
API使用范围 |
|
API属性含义参考 |
(1) 服务提供者:
importcom.alibaba.dubbo.rpc.config.ApplicationConfig; importcom.alibaba.dubbo.rpc.config.RegistryConfig; importcom.alibaba.dubbo.rpc.config.ProviderConfig; importcom.alibaba.dubbo.rpc.config.ServiceConfig; importcom.xxx.XxxService; importcom.xxx.XxxServiceImpl;
// 服务实现 XxxService xxxService =newXxxServiceImpl();
// 当前应用配置 ApplicationConfig application =newApplicationConfig(); application.setName("xxx");
// 连接注册中心配置 RegistryConfig registry =newRegistryConfig(); registry.setAddress("10.20.130.230:9090"); registry.setUsername("aaa"); registry.setPassword("bbb");
// 服务提供者协议配置 ProtocolConfig protocol =newProtocolConfig(); protocol.setName("dubbo"); protocol.setPort(12345); protocol.setThreads(200);
// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口
// 服务提供者暴露服务配置 ServiceConfig<XxxService> service =newServiceConfig<XxxService>();// 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏 service.setApplication(application); service.setRegistry(registry);// 多个注册中心可以用setRegistries() service.setProtocol(protocol);// 多个协议可以用setProtocols() service.setInterface(XxxService.class); service.setRef(xxxService); service.setVersion("1.0.0");
// 暴露及注册服务 service.export(); |
(2) 服务消费者:
importcom.alibaba.dubbo.rpc.config.ApplicationConfig; importcom.alibaba.dubbo.rpc.config.RegistryConfig; importcom.alibaba.dubbo.rpc.config.ConsumerConfig; importcom.alibaba.dubbo.rpc.config.ReferenceConfig; importcom.xxx.XxxService;
// 当前应用配置 ApplicationConfig application =newApplicationConfig(); application.setName("yyy");
// 连接注册中心配置 RegistryConfig registry =newRegistryConfig(); registry.setAddress("10.20.130.230:9090"); registry.setUsername("aaa"); registry.setPassword("bbb");
// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接
// 引用远程服务 ReferenceConfig<XxxService> reference =newReferenceConfig<XxxService>();// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 reference.setApplication(application); reference.setRegistry(registry);// 多个注册中心可以用setRegistries() reference.setInterface(XxxService.class); reference.setVersion("1.0.0");
// 和本地bean一样使用xxxService XxxService xxxService = reference.get();// 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用 |
(3) 特殊场景
注:下面只列出不同的地方,其它参见上面的写法
(3.1) 方法级设置:
...
// 方法级配置 List<MethodConfig> methods =newArrayList<MethodConfig>(); MethodConfig method =newMethodConfig(); method.setName("createXxx"); method.setTimeout(10000); method.setRetries(0); methods.add(method);
// 引用远程服务 ReferenceConfig<XxxService> reference =newReferenceConfig<XxxService>();// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 ... reference.setMethods(methods);// 设置方法级配置
... |
(3.2) 点对点直连:
...
ReferenceConfig<XxxService> reference =newReferenceConfig<XxxService>();// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 // 如果点对点直连,可以用reference.setUrl()指定目标地址,设置url后将绕过注册中心, // 其中,协议对应provider.setProtocol()的值,端口对应provider.setPort()的值, // 路径对应service.setPath()的值,如果未设置path,缺省path为接口名 reference.setUrl("dubbo://10.20.130.230:20880/com.xxx.XxxService");
... |
示例
(+) (#)
想完整的运行起来,请参见:快速启动 (+),这里只列出各种场景的配置方式 |
||
以下示例全部使用基于Spring的Xml配置 (+)作为参考,如果不想使用Spring,而希望通过API的方式进行调用,请参见:API配置 (+) |
||
启动时检查
(+) (#)
Dubbo缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止Spring初始化完成,以便上线时,能及早发现问题,默认check=true。 |
|
如果你的Spring容器是懒加载的,或者通过API编程延迟引用服务,请关闭check,否则服务临时不可用时,会抛出异常,拿到null引用,如果check=false,总是会返回引用,当服务恢复时,能自动连上。 |
可以通过check="false"关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
关闭某个服务的启动时检查:(没有提供者时报错)
<dubbo:referenceinterface="com.foo.BarService"check="false"/> |
关闭所有服务的启动时检查:(没有提供者时报错)
<dubbo:consumercheck="false"/> |
关闭注册中心启动时检查:(注册订阅失败时报错)
<dubbo:registrycheck="false"/> |
也可以用dubbo.properties配置:
dubbo.properties
dubbo.reference.com.foo.BarService.check=false dubbo.reference.check=false dubbo.consumer.check=false dubbo.registry.check=false |
也可以用-D参数:
java -Ddubbo.reference.com.foo.BarService.check=false java -Ddubbo.reference.check=false java -Ddubbo.consumer.check=false java -Ddubbo.registry.check=false |
|
注意区别 · dubbo.reference.check=false,强制改变所有reference的check值,就算配置中有声明,也会被覆盖。 · dubbo.consumer.check=false,是设置check的缺省值,如果配置中有显式的声明,如:<dubbo:reference check="true"/>,不会受影响。 · dubbo.registry.check=false,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。 |
|
引用缺省是延迟初始化的,只有引用被注入到其它Bean,或被getBean()获取,才会初始化。
如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:
<dubbo:referenceinterface="com.foo.BarService"init="true"/> |
集群容错
(+) (#)
在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试。 |
各节点关系:
· 这里的Invoker是Provider的一个可调用Service的抽象,Invoker封装了Provider地址及Service接口信息。
· Directory代表多个Invoker,可以把它看成List<Invoker>,但与List不同的是,它的值可能是动态变化的,比如注册中心推送变更。
· Cluster将Directory中的多个Invoker伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个。
· Router负责从多个Invoker中按路由规则选出子集,比如读写分离,应用隔离等。
· LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。
集群容错模式:
可以自行扩展集群容错策略,参见:集群扩展
Failover Cluster
· 失败自动切换,当出现失败,重试其它服务器。(缺省)
· 通常用于读操作,但重试会带来更长延迟。
· 可通过retries="2"来设置重试次数(不含第一次)。
Failfast Cluster
· 快速失败,只发起一次调用,失败立即报错。
· 通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
· 失败安全,出现异常时,直接忽略。
· 通常用于写入审计日志等操作。
Failback Cluster
· 失败自动恢复,后台记录失败请求,定时重发。
· 通常用于消息通知操作。
Forking Cluster
· 并行调用多个服务器,只要一个成功即返回。
· 通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
· 可通过forks="2"来设置最大并行数。
Broadcast Cluster
· 广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
· 通常用于通知所有提供者更新缓存或日志等本地资源信息。
重试次数配置如:(failover集群模式生效)
<dubbo:serviceretries="2"/> |
或:
<dubbo:referenceretries="2"/> |
或:
<dubbo:reference> <dubbo:methodname="findFoo"retries="2"/> </dubbo:reference> |
集群模式配置如:
<dubbo:servicecluster="failsafe"/> |
或:
<dubbo:referencecluster="failsafe"/> |
负载均衡
(+) (#)
在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。 |
可以自行扩展负载均衡策略,参见:负载均衡扩展
Random LoadBalance
· 随机,按权重设置随机概率。
· 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
· 轮循,按公约后的权重设置轮循比率。
· 存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
· 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
· 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
· 一致性Hash,相同参数的请求总是发到同一提供者。
· 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
· 算法参见:http://en.wikipedia.org/wiki/Consistent_hashing。
· 缺省只对第一个参数Hash,如果要修改,请配置<dubbo:parameter key="hash.arguments" value="0,1" />
· 缺省用160份虚拟节点,如果要修改,请配置<dubbo:parameter key="hash.nodes" value="320" />
配置如:
<dubbo:serviceinterface="..."loadbalance="roundrobin"/> |
或:
<dubbo:referenceinterface="..."loadbalance="roundrobin"/> |
或:
<dubbo:serviceinterface="..."> <dubbo:methodname="..."loadbalance="roundrobin"/> </dubbo:service> |
或:
<dubbo:referenceinterface="..."> <dubbo:methodname="..."loadbalance="roundrobin"/> </dubbo:reference> |
线程模型
(+) (#)
事件处理线程说明 · 如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识,则直接在IO线程上处理更快,因为减少了线程池调度。 · 但如果事件处理逻辑较慢,或者需要发起新的IO请求,比如需要查询数据库,则必须派发到线程池,否则IO线程阻塞,将导致不能接收其它请求。 · 如果用IO线程处理事件,又在事件处理过程中发起新的IO请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁。 |
· Dispatcher
· all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
· direct 所有消息都不派发到线程池,全部在IO线程上直接执行。
· message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。
· execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。
· connection 在IO线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
· ThreadPool
· fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
· cached 缓存线程池,空闲一分钟自动删除,需要时重建。
· limited 可伸缩线程池,但池中的线程数只会增长不会收缩。(为避免收缩时突然来了大流量引起的性能问题)。
配置如:
<dubbo:protocolname="dubbo"dispatcher="all"threadpool="fixed"threads="100"/> |
直连提供者
(+) (#)
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,
点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,
A接口配置点对点,不影响B接口从注册中心获取列表。
(1) 如果是线上需求需要点对点,可在<dubbo:reference>中配置url指向提供者,将绕过注册中心,多个地址用分号隔开,配置如下:(1.0.6及以上版本支持)
<dubbo:reference id="xxxService"interface="com.alibaba.xxx.XxxService"url="dubbo://localhost:20890"/> |
(2) 在JVM启动参数中加入-D参数映射服务地址,如:
(key为服务名,value为服务提供者url,此配置优先级最高,1.0.15及以上版本支持)
java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890 |
||
注意 |
||
(3) 如果服务比较多,也可以用文件映射,如:
(用-Ddubbo.resolve.file指定映射文件路径,此配置优先级高于<dubbo:reference>中的配置,1.0.15及以上版本支持)
(2.0以上版本自动加载${user.home}/dubbo-resolve.properties文件,不需要配置)
java -Ddubbo.resolve.file=xxx.properties |
然后在映射文件xxx.properties中加入:
(key为服务名,value为服务提供者url)
com.alibaba.xxx.XxxService=dubbo://localhost:20890 |
||
注意 |
||
只订阅
(+) (#)
问题 |
|
解决方案 |
禁用注册配置:
<dubbo:registryaddress="10.20.153.10:9090"register="false"/> |
或者:
<dubbo:registryaddress="10.20.153.10:9090?register=false"/> |
只注册
(+) (#)
问题 |
||
解决方案 |
||
禁用订阅配置:
<dubbo:registryid="hzRegistry"address="10.20.153.10:9090"/> <dubbo:registryid="qdRegistry"address="10.20.141.150:9090"subscribe="false"/> |
或者:
<dubbo:registryid="hzRegistry"address="10.20.153.10:9090"/> <dubbo:registryid="qdRegistry"address="10.20.141.150:9090?subscribe=false"/> |
静态服务
(+) (#)
有时候希望人工管理服务提供者的上线和下线,此时需将注册中心标识为非动态管理模式。 |
|||
<dubbo:registryaddress="10.20.141.150:9090"dynamic="false"/> |
|||
或者:
<dubbo:registryaddress="10.20.141.150:9090?dynamic=false"/> |
服务提供者初次注册时为禁用状态,需人工启用,断线时,将不会被自动删除,需人工禁用。
如果是一个第三方独立提供者,比如memcached等,可以直接向注册中心写入提供者地址信息,消费者正常使用:
(通常由脚本监控中心页面等调用)
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo")); |
多协议
(+) (#)
可以自行扩展协议,参见:协议扩展
(1) 不同服务不同协议
比如:不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议。
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" /> <dubbo:registryid="registry"address="10.20.141.150:9090"username="admin"password="hello1234"/>
<!-- 多协议配置 --> <dubbo:protocolname="dubbo"port="20880"/> <dubbo:protocolname="rmi"port="1099"/>
<!-- 使用dubbo协议暴露服务 --> <dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"protocol="dubbo"/> <!-- 使用rmi协议暴露服务 --> <dubbo:serviceinterface="com.alibaba.hello.api.DemoService"version="1.0.0"ref="demoService"protocol="rmi"/>
</beans> |
(2) 多协议暴露服务
比如:需要与http客户端互操作
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" /> <dubbo:registryid="registry"address="10.20.141.150:9090"username="admin"password="hello1234"/>
<!-- 多协议配置 --> <dubbo:protocolname="dubbo"port="20880"/> <dubbo:protocolname="hessian"port="8080"/>
<!-- 使用多个协议暴露服务 --> <dubbo:serviceid="helloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"protocol="dubbo,hessian"/>
</beans> |
多注册中心
(+) (#)
可以自行扩展注册中心,参见:注册中心扩展
(1) 多注册中心注册
比如:中文站有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心。
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" />
<!-- 多注册中心配置 --> <dubbo:registryid="hangzhouRegistry"address="10.20.141.150:9090"/> <dubbo:registryid="qingdaoRegistry"address="10.20.141.151:9010"default="false"/>
<!-- 向多个注册中心注册 --> <dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"registry="hangzhouRegistry,qingdaoRegistry"/>
</beans> |
(2) 不同服务使用不同注册中心
比如:CRM有些服务是专门为国际站设计的,有些服务是专门为中文站设计的。
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" />
<!-- 多注册中心配置 --> <dubbo:registryid="chinaRegistry"address="10.20.141.150:9090"/> <dubbo:registryid="intlRegistry"address="10.20.154.177:9010"default="false"/>
<!-- 向中文站注册中心注册 --> <dubbo:serviceinterface="com.alibaba.hello.api.HelloService"version="1.0.0"ref="helloService"registry="chinaRegistry"/>
<!-- 向国际站注册中心注册 --> <dubbo:serviceinterface="com.alibaba.hello.api.DemoService"version="1.0.0"ref="demoService"registry="intlRegistry"/>
</beans> |
(3) 多注册中心引用
比如:CRM需同时调用中文站和国际站的PC2服务,PC2在中文站和国际站均有部署,接口及版本号都一样,但连的数据库不一样。
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" />
<!-- 多注册中心配置 --> <dubbo:registryid="chinaRegistry"address="10.20.141.150:9090"/> <dubbo:registryid="intlRegistry"address="10.20.154.177:9010"default="false"/>
<!-- 引用中文站服务 --> <dubbo:referenceid="chinaHelloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"registry="chinaRegistry"/>
<!-- 引用国际站站服务 --> <dubbo:referenceid="intlHelloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"registry="intlRegistry"/>
</beans> |
如果只是测试环境临时需要连接两个不同注册中心,使用竖号分隔多个不同注册中心地址:
consumer.xml
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" http://www.springframework.org/schema/beans" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo=" http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<dubbo:applicationname="world" />
<!-- 多注册中心配置,竖号分隔表示同时连接多个不同注册中心,同一注册中心的多个集群地址用逗号分隔 --> <dubbo:registryaddress="10.20.141.150:9090|10.20.154.177:9010"/>
<!-- 引用服务 --> <dubbo:referenceid="helloService"interface="com.alibaba.hello.api.HelloService"version="1.0.0"/>
</beans> |
服务分组
(+) (#)
当一个接口有多种实现时,可以用group区分。 |
|||
<dubbo:servicegroup="feedback"interface="com.xxx.IndexService"/> <dubbo:servicegroup="member"interface="com.xxx.IndexService"/> |
|||
<dubbo:referenceid="feedbackIndexService"group="feedback"interface="com.xxx.IndexService"/> <dubbo:referenceid="memberIndexService"group="member"interface="com.xxx.IndexService"/> |
任意组:(2.2.0以上版本支持,总是只调一个可用组的实现)
<dubbo:referenceid="barService"interface="com.foo.BarService"group="*"/> |
多版本
(+) (#)
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 |
· 在低压力时间段,先升级一半提供者为新版本
· 再将所有消费者升级为新版本
· 然后将剩下的一半提供者升级为新版本
<dubbo:serviceinterface="com.foo.BarService"version="1.0.0"/> |
<dubbo:serviceinterface="com.foo.BarService"version="2.0.0"/> |
<dubbo:referenceid="barService"interface="com.foo.BarService"version="1.0.0"/> |
<dubbo:referenceid="barService"interface="com.foo.BarService"version="2.0.0"/> |
不区分版本:(2.2.0以上版本支持)
<dubbo:referenceid="barService"interface="com.foo.BarService"version="*"/> |
分组聚合
(+) (#)
按组合并返回结果,比如菜单服务,接口一样,但有多种实现,用group区分,现在消费方需从每种group中调用一次返回结果,合并结果返回,这样就可以实现聚合菜单项。 |
||
从2.1.0版本开始支持 |
||
代码参见:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/merge
配置如:(搜索所有分组)
<dubbo:referenceinterface="com.xxx.MenuService"group="*"merger="true"/> |
或:(合并指定分组)
<dubbo:referenceinterface="com.xxx.MenuService"group="aaa,bbb"merger="true"/> |
或:(指定方法合并结果,其它未指定的方法,将只调用一个Group)
<dubbo:referenceinterface="com.xxx.MenuService"group="*"> <dubbo:methodname="getMenuItems"merger="true"/> </dubbo:service> |
或:(某个方法不合并结果,其它都合并结果)
<dubbo:referenceinterface="com.xxx.MenuService"group="*"merger="true"> <dubbo:methodname="getMenuItems"merger="false"/> </dubbo:service> |
或:(指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称)
参见:[合并结果扩展]
<dubbo:referenceinterface="com.xxx.MenuService"group="*"> <dubbo:methodname="getMenuItems"merger="mymerge"/> </dubbo:service> |
或:(指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身)
<dubbo:referenceinterface="com.xxx.MenuService"group="*"> <dubbo:methodname="getMenuItems"merger=".addAll"/> </dubbo:service> |
参数验证
(+) (#)
参数验证功能是基于JSR303实现的,用户只需标识JSR303标准的验证Annotation,并通过声明filter来实现验证。 |
||
2.1.0以上版本支持 |
||
完整示例代码参见:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/validation
验证方式可扩展,参见:Validation扩展点
参数标注示例:
importjava.io.Serializable; importjava.util.Date;
importjavax.validation.constraints.Future; importjavax.validation.constraints.Max; importjavax.validation.constraints.Min; importjavax.validation.constraints.NotNull; importjavax.validation.constraints.Past; importjavax.validation.constraints.Pattern; importjavax.validation.constraints.Size;
publicclassValidationParameterimplementsSerializable {
privatestaticfinallongserialVersionUID = 7158911668568000392L;
@NotNull// 不允许为空 @Size(min =1, max =20)// 长度或大小范围 privateString name;
@NotNull(groups = ValidationService.Save.class)// 保存时不允许为空,更新时允许为空 ,表示不更新该字段 @Pattern(regexp ="^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$") privateString email;
@Min(18)// 最小值 @Max(100)// 最大值 privateintage;
@Past// 必须为一个过去的时间 privateDate loginDate;
@Future// 必须为一个未来的时间 privateDate expiryDate;
publicString getName() { returnname; }
publicvoidsetName(String name) { this.name = name; }
publicString getEmail() { returnemail; }
publicvoidsetEmail(String email) { this.email = email; }
publicintgetAge() { returnage; }
publicvoidsetAge(intage) { this.age = age; }
publicDate getLoginDate() { returnloginDate; }
publicvoidsetLoginDate(Date loginDate) { this.loginDate = loginDate; }
publicDate getExpiryDate() { returnexpiryDate; }
publicvoidsetExpiryDate(Date expiryDate) { this.expiryDate = expiryDate; }
} |
分组验证示例:
publicinterfaceValidationService {// 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)
@interfaceSave{}// 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选 voidsave(ValidationParameter parameter);
voidupdate(ValidationParameter parameter);
} |
关联验证示例:
importjavax.validation.GroupSequence;
publicinterfaceValidationService {
@GroupSequence(Update.class)// 同时验证Update组规则 @interfaceSave{} voidsave(ValidationParameter parameter);
@interfaceUpdate{} voidupdate(ValidationParameter parameter);
} |
参数验证示例:
importjavax.validation.constraints.Min; importjavax.validation.constraints.NotNull;
publicinterfaceValidationService {
voidsave(@NotNullValidationParameter parameter);// 验证参数不为空
voiddelete(@Min(1)intid);// 直接对基本类型参数验证
} |
在客户端验证参数:
<dubbo:referenceid="validationService"interface="com.alibaba.dubbo.examples.validation.api.ValidationService"validation="true"/> |
在服务器端验证参数:
<dubbo:serviceinterface="com.alibaba.dubbo.examples.validation.api.ValidationService"ref="validationService"validation="true"/> |
验证异常信息:
importjavax.validation.ConstraintViolationException; importjavax.validation.ConstraintViolationException;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
importcom.alibaba.dubbo.examples.validation.api.ValidationParameter; importcom.alibaba.dubbo.examples.validation.api.ValidationService; importcom.alibaba.dubbo.rpc.RpcException;
publicclassValidationConsumer {
publicstaticvoidmain(String[] args)throwsException { String config = ValidationConsumer.class.getPackage().getName().replace('.','/') +"/validation-consumer.xml"; ClassPathXmlApplicationContext context =newClassPathXmlApplicationContext(config); context.start(); ValidationService validationService = (ValidationService)context.getBean("validationService"); // Error try{ parameter =newValidationParameter(); validationService.save(parameter); System.out.println("Validation ERROR"); }catch(RpcException e) {// 抛出的是RpcException ConstraintViolationException ve = (ConstraintViolationException) e.getCause();// 里面嵌了一个ConstraintViolationException Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();// 可以拿到一个验证错误详细信息的集合 System.out.println(violations); } }
} |
需要加入依赖:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.2.0.Final</version> </dependency> |
结果缓存
(+) (#)
结果缓存,用于加速热门数据的访问速度,Dubbo提供声明式缓存,以减少用户加缓存的工作量。 |
||
2.1.0以上版本支持 |
||
示例代码:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/cache
· lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
· threadlocal 当前线程缓存,比如一个页面渲染,用到很多portal,每个portal都要去查用户信息,通过线程缓存,可以减少这种多余访问。
· jcache 与JSR107集成,可以桥接各种缓存实现。
缓存类型可扩展,参见:CacheFactory扩展点
配置如:
<dubbo:referenceinterface="com.foo.BarService"cache="lru"/> |
或:
<dubbo:referenceinterface="com.foo.BarService"> <dubbo:methodname="findBar"cache="lru"/> </dubbo:reference> |
泛化引用
(+) (#)
泛接口调用方式主要用于客户端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过GenericService调用所有服务实现。 |
|||
<dubbo:referenceid="barService"interface="com.foo.BarService"generic="true"/> |
|||
GenericService barService = (GenericService) applicationContext.getBean("barService"); Object result = barService.$invoke("sayHello",newString[] {"java.lang.String"},newObject[] {"World"}); |
importcom.alibaba.dubbo.rpc.service.GenericService; ...
// 引用远程服务 ReferenceConfig<GenericService> reference =newReferenceConfig<GenericService>();// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 reference.setInterface("com.xxx.XxxService");// 弱类型接口名 reference.setVersion("1.0.0"); reference.setGeneric(true);// 声明为泛化接口
GenericService genericService = reference.get();// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
// 基本类型以及Date,List,Map等不需要转换,直接调用 Object result = genericService.$invoke("sayHello",newString[] {"java.lang.String"},newObject[] {"world"});
// 用Map表示POJO参数,如果返回值为POJO也将自动转成Map Map<String, Object> person =newHashMap<String, Object>(); person.put("name","xxx"); person.put("password","yyy"); Object result = genericService.$invoke("findPerson",newString[]{"com.xxx.Person"},newObject[]{person});// 如果返回POJO将自动转成Map
... |
假设存在POJO如:
packagecom.xxx; publicclassPersonImplimplementsPerson { privateString name; privateString password; publicString getName() { returnname; } publicvoidsetName(String name) { this.name = name; } publicString getPassword() { returnpassword; } publicvoidsetPassword(String password) { this.password= password; } } |
则POJO数据:
Person person =newPersonImpl(); person.setName("xxx"); person.setPassword("yyy"); |
可用下面Map表示:
Map<String, Object> map =newHashMap<String, Object>(); map.put("class","com.xxx.PersonImpl");// 注意:如果参数类型是接口,或者List等丢失泛型,可通过class属性指定类型。 map.put("name","xxx"); map.put("password","yyy"); |
泛化实现
(+) (#)
泛接口实现方式主要用于服务器端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的远程服务Mock框架,可通过实现GenericService接口处理所有服务请求。 |
|||
<beanid="genericService"class="com.foo.MyGenericService"/> <dubbo:serviceinterface="com.foo.BarService"ref="genericService"/> |
|||
packagecom.foo; publicclassMyGenericServiceimplementsGenericService {
publicObject $invoke(String methodName, String[] parameterTypes, Object[] args)throwsGenericException { if("sayHello".equals(methodName)) { return"Welcome "+ args[0]; } }
} |
... GenericService xxxService =newXxxGenericService();// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口实现
ServiceConfig<GenericService> service =newServiceConfig<GenericService>();// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 service.setInterface("com.xxx.XxxService");// 弱类型接口名 service.setVersion("1.0.0"); service.setRef(xxxService);// 指向一个通用服务实现
// 暴露及注册服务 service.export(); |
回声测试
(+) (#)
回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。 |
|
所有服务自动实现EchoService接口,只需将任意服务引用强制转型为EchoService,即可使用。 |
<dubbo:referenceid="memberService"interface="com.xxx.MemberService"/> |
MemberService memberService = ctx.getBean("memberService");// 远程服务引用
EchoService echoService = (EchoService) memberService;// 强制转型为EchoService
String status = echoService.$echo("OK");// 回声测试可用性
assert(status.equals("OK")) |
上下文信息
(+) (#)
上下文中存放的是当前调用过程中所需的环境信息。 |
||
所有配置信息都将转换为URL的参数,参见《配置项一览表》中的“对应URL参数”一列。 |
||
注意 |
(1) 服务消费方
xxxService.xxx();// 远程调用 booleanisConsumerSide = RpcContext.getContext().isConsumerSide();// 本端是否为消费端,这里会返回true String serverIP = RpcContext.getContext().getRemoteHost();// 获取最后一次调用的提供方IP地址 String application = RpcContext.getContext().getUrl().getParameter("application");// 获取当前服务配置信息,所有配置信息都将转换为URL的参数 // ... yyyService.yyy();// 注意:每发起RPC调用,上下文状态会变化 // ... |
(2) 服务提供方
publicclassXxxServiceImplimplementsXxxService {
publicvoidxxx() {// 服务方法实现 booleanisProviderSide = RpcContext.getContext().isProviderSide();// 本端是否为提供端,这里会返回true String clientIP = RpcContext.getContext().getRemoteHost();// 获取调用方IP地址 String application = RpcContext.getContext().getUrl().getParameter("application");// 获取当前服务配置信息,所有配置信息都将转换为URL的参数 // ... yyyService.yyy();// 注意:每发起RPC调用,上下文状态会变化 booleanisProviderSide = RpcContext.getContext().isProviderSide();// 此时本端变成消费端,这里会返回false // ... }
} |
隐式传参
(+) (#)
注:path,group,version,dubbo,token,timeout几个key有特殊处理,请使用其它key值。 |
(1) 服务消费方
RpcContext.getContext().setAttachment("index","1");// 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,用于框架集成,不建议常规业务使用 xxxService.xxx();// 远程调用 // ... |
【注】 setAttachment设置的KV,在完成下面一次远程调用会被清空。即多次远程调用要多次设置。
(2) 服务提供方
publicclassXxxServiceImplimplementsXxxService {
publicvoidxxx() {// 服务方法实现 String index = RpcContext.getContext().getAttachment("index");// 获取客户端隐式传入的参数,用于框架集成,不建议常规业务使用 // ... }
} |
异步调用
(+) (#)
基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。 |
||
2.0.6及其以上版本支持 |
||
配置声明:
consumer.xml
<dubbo:referenceid="fooService"interface="com.alibaba.foo.FooService"> <dubbo:methodname="findFoo"async="true"/> </dubbo:reference> <dubbo:referenceid="barService"interface="com.alibaba.bar.BarService"> <dubbo:methodname="findBar"async="true"/> </dubbo:reference> |
调用代码:
fooService.findFoo(fooId);// 此调用会立即返回null Future<Foo> fooFuture = RpcContext.getContext().getFuture();// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future。
barService.findBar(barId);// 此调用会立即返回null Future<Bar> barFuture = RpcContext.getContext().getFuture();// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future。
// 此时findFoo和findBar的请求同时在执行,客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成。
Foo foo = fooFuture.get();// 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒。 Bar bar = barFuture.get();// 同理等待bar返回。
// 如果foo需要5秒返回,bar需要6秒返回,实际只需等6秒,即可获取到foo和bar,进行接下来的处理。 |
你也可以设置是否等待消息发出:(异步总是不等待返回)
· sent="true" 等待消息发出,消息发送失败将抛出异常。
· sent="false" 不等待消息发出,将消息放入IO队列,即刻返回。
<dubbo:methodname="findFoo"async="true"sent="true"/> |
如果你只是想异步,完全忽略返回值,可以配置return="false",以减少Future对象的创建和管理成本:
<dubbo:methodname="findFoo"async="true"return="false"/> |
本地调用
(+) (#)
本地调用,使用了Injvm协议,是一个伪协议,它不开启端口,不发起远程调用,只在JVM内直接关联,但执行Dubbo的Filter链。 |
Define injvm protocol:
<dubbo:protocolname="injvm"/> |
Set default protocol:
<dubbo:providerprotocol="injvm"/> |
Set service protocol:
<dubbo:serviceprotocol="injvm"/> |
Use injvm first:
<dubbo:consumerinjvm="true".../> <dubbo:providerinjvm="true".../> |
或
<dubbo:referenceinjvm="true".../> <dubbo:serviceinjvm="true".../> |
||
注意:服务暴露与服务引用都需要声明injvm="true" |
||
自动暴露、引用本地服务
从 dubbo 2.2.0 开始,每个服务默认都会在本地暴露;在引用服务的时候,默认优先引用本地服务;如果希望引用远程服务可以使用一下配置强制引用远程服务。
... <dubbo:reference...scope="remote"/> ... |
参数回调
(+) (#)
参数回调方式与调用本地callback或listener相同,只需要在Spring的配置文件中声明哪个参数是callback类型即可,Dubbo将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。 |
||
2.0.6及其以上版本支持 |
||
代码参见:https://github.com/alibaba/dubbo/tree/master/dubbo-test/dubbo-test-examples/src/main/java/com/alibaba/dubbo/examples/callback
(1) 共享服务接口:
服务接口示例:
CallbackService.java
packagecom.callback;
publicinterfaceCallbackService { voidaddListener(String key, CallbackListener listener); } |
CallbackListener.java
packagecom.callback;
publicinterfaceCallbackListener { voidchanged(String msg); } |
(2) 服务提供者:
服务提供者接口实现示例:
CallbackServiceImpl.java
packagecom.callback.impl;
importjava.text.SimpleDateFormat; importjava.util.Date; importjava.util.Map; importjava.util.concurrent.ConcurrentHashMap;
importcom.callback.CallbackListener; importcom.callback.CallbackService;
publicclassCallbackServiceImplimplementsCallbackService {
privatefinalMap<String, CallbackListener> listeners =newConcurrentHashMap<String, CallbackListener>();
publicCallbackServiceImpl() { Thread t =newThread(newRunnable() { publicvoidrun() { while(true) { try{ for(Map.Entry<String, CallbackListener> entry : listeners.entrySet()){ try{ entry.getValue().changed(getChanged(entry.getKey())); }catch(Throwable t) { listeners.remove(entry.getKey()); } } Thread.sleep(5000);// 定时触发变更通知 }catch(Throwable t) {// 防御容错 t.printStackTrace(); } } } }); t.setDaemon(true); t.start(); }
publicvoidaddListener(String key, CallbackListener listener) { listeners.put(key, listener); listener.changed(getChanged(key));// 发送变更通知 }
privateString getChanged(String key) { return"Changed: "+newSimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(newDate()); }
} |
服务提供者配置示例:
<beanid="callbackService"class="com.callback.impl.CallbackServiceImpl"/> <dubbo:serviceinterface="com.callback.CallbackService"ref="callbackService"connections="1"callbacks="1000"> <dubbo:methodname="addListener"> <dubbo:argumentindex="1"callback="true"/> <!--也可以通过指定类型的方式--> <!--<dubbo:argument type="com.demo.CallbackListener" callback="true" />--> </dubbo:method> </dubbo:service> |
(2) 服务消费者:
服务消费者配置示例:
consumer.xml
<dubbo:referenceid="callbackService"interface="com.callback.CallbackService"/> |
服务消费者调用示例:
CallbackServiceTest.java
ClassPathXmlApplicationContext context =newClassPathXmlApplicationContext("classpath:consumer.xml"); context.start();
CallbackService callbackService = (CallbackService) context.getBean("callbackService");
callbackService.addListener("foo.bar",newCallbackListener(){ publicvoidchanged(String msg) { System.out.println("callback1:"+ msg); } }); |
事件通知
(+) (#)
在调用之前,调用之后,出现异常时,会触发oninvoke, onreturn, onthrow三个事件,可以配置当事件发生时,通知哪个类的哪个方法。 |
||
支持版本:2.0.7之后 |
||
(1) 服务提供者与消费者共享服务接口:
IDemoService.java
interfaceIDemoService { publicPerson get(intid); } |
(2) 服务提供者实现:
DemoServiceImpl.java
classNormalDemoServiceimplementsIDemoService { publicPerson get(intid) { returnnewPerson(id,"charles`son",4); } } |
(3) 服务提供者配置:
provider.xml
<dubbo:applicationname="rpc-callback-demo"/> <dubbo:registryaddress="10.20.153.186"/> <beanid="demoService"class="com.alibaba.dubbo.callback.implicit.NormalDemoService"/> <dubbo:serviceinterface="com.alibaba.dubbo.callback.implicit.IDemoService"ref="demoService"version="1.0.0"group="cn"/> |
(4) 服务消费者Callback接口及实现:
Nofify.java
interfaceNofify { publicvoidonreturn(Person msg, Integer id); publicvoidonthrow(Throwable ex, Integer id); } |
NofifyImpl.java
classNofifyImplimplementsNofify { publicMap<Integer, Person> ret =newHashMap<Integer, Person>(); publicMap<Integer, Throwable> errors =newHashMap<Integer, Throwable>(); publicvoidonreturn(Person msg, Integer id) { System.out.println("onreturn:"+ msg); ret.put(id, msg); } publicvoidonthrow(Throwable ex, Integer id) { errors.put(id, ex); } } |
(5) 服务消费者Callback接口及实现:
consumer.xml
<beanid="demoCallback"class="com.alibaba.dubbo.callback.implicit.NofifyImpl"/> <dubbo:referenceid="demoService"interface="com.alibaba.dubbo.callback.implicit.IDemoService"version="1.0.0"group="cn"> <dubbo:methodname="get"async="true"onreturn="demoCallback.onreturn"onthrow="demoCallback.onthrow"/> </dubbo:reference> |
|
注: 组合情况:(async=false 默认) |
(6) TEST CASE:
Test.java
IDemoService demoService = (IDemoService) context.getBean("demoService"); NofifyImpl notify = (NofifyImpl) context.getBean("demoCallback"); intrequestId =2; Person ret = demoService.get(requestId); Assert.assertEquals(null, ret); //for Test:只是用来说明callback正常被调用,业务具体实现自行决定. for(inti =0; i <10; i++) { if(!notify.ret.containsKey(requestId)) { Thread.sleep(200); }else{ break; } } Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); |
本地存根
(+) (#)
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做ThreadLocal缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在API中带上Stub,客户端生成Proxy实,会把Proxy通过构造函数传给Stub,然后把Stub暴露组给用户,Stub可以决定要不要去调Proxy。 |
||
Stub必须有可传入Proxy的构造函数。 |
||
<dubbo:serviceinterface="com.foo.BarService"stub="true"/> |
Or:
<dubbo:serviceinterface="com.foo.BarService"stub="com.foo.BarServiceStub"/> |
api.jar:
com.foo.BarService com.foo.BarServiceStub // 在API旁边放一个Stub实现,它实现BarService接口,并有一个传入远程BarService实例的构造函数 |
packagecom.foo publicclassBarServiceStubimplementsBarService {
privatefinalBarService barService;
// 构造函数传入真正的远程代理对象 public(BarService barService) { this.barService = barService; }
publicString sayHello(String name) { // 此代码在客户端执行 // 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等 try{ returnbarService.sayHello(name); }catch(Exception e) { // 你可以容错,可以做任何AOP拦截事项 return"容错数据"; } } } |
本地伪装
(+) (#)
Mock通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过Mock数据返回授权失败。 |
|
Mock是Stub的一个子集,便于服务提供方在客户端执行容错逻辑,因经常需要在出现RpcException(比如网络失败,超时等)时进行容错,而在出现业务异常(比如登录用户名密码错误)时不需要容错,如果用Stub,可能就需要捕获并依赖RpcException类,而用Mock就可以不依赖RpcException,因为它的约定就是只有出现RpcException时才执行。 |
<dubbo:serviceinterface="com.foo.BarService"mock="true"/> |
Or:
<dubbo:serviceinterface="com.foo.BarService"mock="com.foo.BarServiceMock"/> |
api.jar:
com.foo.BarService com.foo.BarServiceMock // 在API旁边放一个Mock实现,它实现BarService接口,并有一个无参构造函数 |
packagecom.foo publicclassBarServiceMockimplementsBarService {
publicString sayHello(String name) { // 你可以伪造容错数据,此方法只在出现RpcException时被执行 return"容错数据"; } } |
如果服务的消费方经常需要try-catch捕获异常,如:
Offer offer =null; try{ offer = offerService.findOffer(offerId); }catch(RpcException e) { logger.error(e); } |
请考虑改为Mock实现,并在Mock中return null。
如果只是想简单的忽略异常,在2.0.11以上版本可用:
<dubbo:serviceinterface="com.foo.BarService"mock="return null"/> |
延迟暴露
(+) (#)
如果你的服务需要Warmup时间,比如初始化缓存,等待相关资源就位等,可以使用delay进行延迟暴露。 |
延迟5秒暴露服务:
<dubbo:servicedelay="5000"/> |
延迟到Spring初始化完成后,再暴露服务:(基于Spring的ContextRefreshedEvent事件触发暴露)
<dubbo:servicedelay="-1"/> |
|
Spring2.x初始化死锁问题 1. 请求线程的applicationContext.getBean()调用,先同步singletonObjects判断Bean是否存在,不存在就同步beanDefinitionMap进行初始化,并再次同步singletonObjects写入Bean实例缓存。 这样就导致getBean线程,先锁singletonObjects,再锁beanDefinitionMap,再次锁singletonObjects。 |
规避办法 |
并发控制
(+) (#)
限制com.foo.BarService的每个方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:serviceinterface="com.foo.BarService"executes="10"/> |
限制com.foo.BarService的sayHello方法,服务器端并发执行(或占用线程池线程数)不能超过10个:
<dubbo:serviceinterface="com.foo.BarService"> <dubbo:methodname="sayHello"executes="10"/> </dubbo:service> |
限制com.foo.BarService的每个方法,每客户端并发执行(或占用连接的请求数)不能超过10个:
<dubbo:serviceinterface="com.foo.BarService"actives="10"/> |
Or:
<dubbo:referenceinterface="com.foo.BarService"actives="10"/> |
限制com.foo.BarService的sayHello方法,每客户端并发执行(或占用连接的请求数)不能超过10个:
<dubbo:serviceinterface="com.foo.BarService"> <dubbo:methodname="sayHello"actives="10"/> </dubbo:service> |
Or:
<dubbo:referenceinterface="com.foo.BarService"> <dubbo:methodname="sayHello"actives="10"/> </dubbo:service> |
如果<dubbo:service>和<dubbo:reference>都配了actives,<dubbo:reference>优先,参见:配置的覆盖策略。
Load Balance均衡:
配置服务的客户端的loadbalance属性为leastactive,此Loadbalance会调用并发数最小的Provider(Consumer端并发数)。
<dubbo:referenceinterface="com.foo.BarService"loadbalance="leastactive"/> |
Or:
<dubbo:serviceinterface="com.foo.BarService"loadbalance="leastactive"/> |
连接控制
(+) (#)
限制服务器端接受的连接不能超过10个:(以连接在Server上,所以配置在Provider上)
<dubbo:providerprotocol="dubbo"accepts="10"/> |
<dubbo:protocolname="dubbo"accepts="10"/> |
限制客户端服务使用连接连接数:(如果是长连接,比如Dubbo协议,connections表示该服务对每个提供者建立的长连接数)
<dubbo:referenceinterface="com.foo.BarService"connections="10"/> |
Or:
<dubbo:serviceinterface="com.foo.BarService"connections="10"/> |
如果<dubbo:service>和<dubbo:reference>都配了connections,<dubbo:reference>优先,参见:配置的覆盖策略。
延迟连接
(+) (#)
延迟连接,用于减少长连接数,当有调用发起时,再创建长连接。 |
||
只对使用长连接的dubbo协议生效。 |
||
<dubbo:protocolname="dubbo"lazy="true"/> |
粘滞连接
(+) (#)
粘滞连接用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非该提供者挂了,再连另一台。 |
||
粘滞连接将自动开启延迟连接,以减少长连接数,参见:延迟连接 (+) |
||
<dubbo:protocolname="dubbo"sticky="true"/> |
令牌验证
(+) (#)
· 防止消费者绕过注册中心访问提供者
· 在注册中心控制权限,以决定要不要下发令牌给消费者
· 注册中心可灵活改变授权方式,而不需修改或升级提供者
可以全局设置开启令牌验证:
<!--随机token令牌,使用UUID生成--> <dubbo:providerinterface="com.foo.BarService"token="true"/> |
<!--固定token令牌,相当于密码--> <dubbo:providerinterface="com.foo.BarService"token="123456"/> |
也可在服务级别设置:
<!--随机token令牌,使用UUID生成--> <dubbo:serviceinterface="com.foo.BarService"token="true"/> |
<!--固定token令牌,相当于密码--> <dubbo:serviceinterface="com.foo.BarService"token="123456"/> |
还可在协议级别设置:
<!--随机token令牌,使用UUID生成--> <dubbo:protocolname="dubbo"token="true"/> |
<!--固定token令牌,相当于密码--> <dubbo:protocolname="dubbo"token="123456"/> |
路由规则
(+) (#)
2.2.0以上版本支持 |
||
路由规则扩展点:路由扩展 |
||
向注册中心写入路由规则:(通常由监控中心或治理中心的页面完成)
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule="+ URL.encode("host = 10.20.153.10 => host = 10.20.153.11") + ")); |
其中:
· condition://
· 表示路由规则的类型,支持条件路由规则和脚本路由规则,可扩展,必填。
· 0.0.0.0
· 表示对所有IP地址生效,如果只想对某个IP的生效,请填入具体IP,必填。
· com.foo.BarService
· 表示只对指定服务生效,必填。
· category=routers
· 表示该数据为动态配置类型,必填。
· dynamic=false
· 表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填。
· enabled=true
· 覆盖规则是否生效,可不填,缺省生效。
· force=false
· 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为flase。
· runtime=false
· 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。
· 如果用了参数路由,必须设为true,需要注意设置会影响调用的性能,可不填,缺省为flase。
· priority=1
· 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为0。
· rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11")
· 表示路由规则的内容,必填。
条件路由规则
(#)
基于条件表达式的路由规则,如:
host =10.20.153.10=> host =10.20.153.11 |
规则:
· "=>"之前的为消费者匹配条件,所有参数和消费者的URL进行对比,当消费者满足匹配条件时,对该消费者执行后面的过滤规则。
· "=>"之后为提供者地址列表的过滤条件,所有参数和提供者的URL进行对比,消费者最终只拿到过滤后的地址列表。
· 如果匹配条件为空,表示对所有消费方应用,如:=> host != 10.20.153.11
· 如果过滤条件为空,表示禁止访问,如:host = 10.20.153.10 =>
表达式:
· 参数支持:
· 服务调用信息,如:method, argument 等 (暂不支持参数路由)
· URL本身的字段,如:protocol, host, port 等
· 以及URL上的所有参数,如:application, organization 等
· 条件支持:
· 等号"="表示"匹配",如:host = 10.20.153.10
· 不等号"!="表示"不匹配",如:host != 10.20.153.10
· 值支持:
· 以逗号","分隔多个值,如:host != 10.20.153.10,10.20.153.11
· 以星号"*"结尾,表示通配,如:host != 10.20.*
· 以美元符"$"开头,表示引用消费者参数,如:host = $host
示例:
1. 排除预发布机:
=> host !=172.22.3.91 |
2. 白名单:(注意:一个服务只能有一条白名单规则,否则两条规则交叉,就都被筛选掉了)
host !=10.20.153.10,10.20.153.11=> |
3. 黑名单:
host =10.20.153.10,10.20.153.11=> |
4. 服务寄宿在应用上,只暴露一部分的机器,防止整个集群挂掉:
=> host =172.22.3.1*,172.22.3.2* |
5. 为重要应用提供额外的机器:
application != kylin => host !=172.22.3.95,172.22.3.96 |
6. 读写分离:
method = find*,list*,get*,is* => host =172.22.3.94,172.22.3.95,172.22.3.96 |
method != find*,list*,get*,is* => host =172.22.3.97,172.22.3.98 |
7. 前后台分离:
application = bops => host =172.22.3.91,172.22.3.92,172.22.3.93 |
application != bops => host =172.22.3.94,172.22.3.95,172.22.3.96 |
8. 隔离不同机房网段:
host !=172.22.3.* => host !=172.22.3.* |
9. 提供者与消费者部署在同集群内,本机只访问本机的服务:
=> host = $host |
脚本路由规则
(#)
支持JDK脚本引擎的所有脚本,比如:javascript,jruby,groovy等,通过type=javascript参数设置脚本类型,缺省为javascript。 |
||
脚本没有沙箱约束,可执行任意代码,存在后门风险 |
||
"script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule="+ URL.encode("function route(invokers) { ... } (invokers)") |
基于脚本引擎的路由规则,如:
functionroute(invokers) { varresult =newjava.util.ArrayList(invokers.size()); for(i = 0; i < invokers.size(); i ++) { if("10.20.153.10".equals(invokers.get(i).getUrl().getHost())) { result.add(invokers.get(i)); } } returnresult; } (invokers);// 表示立即执行方法 |
配置规则
(+) (#)
2.2.0以上版本支持 |
向注册中心写入动态配置覆盖规则:(通常由监控中心或治理中心的页面完成)
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&timeout=1000")); |
其中:
· override://
· 表示数据采用覆盖方式,支持override和absent,可扩展,必填。
· 0.0.0.0
· 表示对所有IP地址生效,如果只想覆盖某个IP的数据,请填入具体IP,必填。
· com.foo.BarService
· 表示只对指定服务生效,必填。
· category=configurators
· 表示该数据为动态配置类型,必填。
· dynamic=false
· 表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填。
· enabled=true
· 覆盖规则是否生效,可不填,缺省生效。
· application=foo
· 表示只对指定应用生效,可不填,表示对所有应用生效。
· timeout=1000
· 表示将满足以上条件的timeout参数的值覆盖为1000。
· 如果想覆盖其它参数,直接加在override的URL参数上。
示例:
1. 禁用提供者:(通常用于临时踢除某台提供者机器,相似的,禁止消费者访问请使用路由规则)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&disbaled=true |
2. 调整权重:(通常用于容量评估,缺省权重为100)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&weight=200 |
3. 调整负载均衡策略:(缺省负载均衡策略为random)
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&loadbalance=leastactive |
4. 服务降级:(通常用于临时屏蔽某个出错的非关键服务)
override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null |
服务降级
(+) (#)
2.2.0以上版本支持 |
||
参见:配置规则 |
||
向注册中心写入动态配置覆盖规则:(通过由监控中心或治理中心的页面完成)
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null")); |
其中:
mock=force:return+null |
· 表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。
· 屏蔽不重要服务不可用时对调用方的影响。
还可以改为:
mock=fail:return+null |
· 表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。
· 容忍不重要服务不稳定时对调用方的影响。
优雅停机
(+) (#)
Dubbo是通过JDK的ShutdownHook来完成优雅停机的,所以如果用户使用"kill -9 PID"等强制关闭指令,是不会执行优雅停机的,只有通过"kill PID"时,才会执行。 |
原理:
· 服务提供方
· 停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。
· 然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
· 服务消费方
· 停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
· 然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
设置优雅停机超时时间,缺省超时时间是10秒:(超时则强制关闭)
<dubbo:application...> <dubbo:parameterkey="shutdown.timeout"value="60000"/><!-- 单位毫秒 --> </dubbo:application> |
如果ShutdownHook不能生效,可以自行调用:
ProtocolConfig.destroyAll(); |
主机绑定
(+) (#)
缺省主机IP查找顺序:
· 通过LocalHost.getLocalHost()获取本机地址。
· 如果是127.*等loopback地址,则扫描各网卡,获取网卡IP。
注册的地址如果获取不正确,比如需要注册公网地址,可以:
1. 可以在/etc/hosts中加入:机器名 公网IP,比如:
test1205.182.23.201 |
2. 在dubbo.xml中加入主机地址的配置:
<dubbo:protocolhost="205.182.23.201"> |
3. 或在dubbo.properties中加入主机地址的配置:
dubbo.protocol.host=205.182.23.201 |
缺省主机端口与协议相关:
· dubbo: 20880
· rmi: 1099
· http: 80
· hessian: 80
· webservice: 80
· memcached: 11211
· redis: 6379
主机端口配置:
1. 在dubbo.xml中加入主机地址的配置:
<dubbo:protocolname="dubbo"port="20880"> |
3. 或在dubbo.properties中加入主机地址的配置:
dubbo.protocol.dubbo.port=20880 |
日志适配
(+) (#)
2.2.1以上版本支持 |
||
扩展点:日志适配扩展 |
||
缺省自动查找:
· log4j
· slf4j
· jcl
· jdk
可以通过以下方式配置日志输出策略:
java -Ddubbo.application.logger=log4j |
dubbo.properties
dubbo.application.logger=log4j |
dubbo.xml
<dubbo:application logger="log4j"/> |
访问日志
(+) (#)
如果你想记录每一次请求信息,可开启访问日志,类似于apache的访问日志。 |
||
此日志量比较大,请注意磁盘容量。 |
||
将访问日志输出到当前应用的log4j日志:
<dubbo:protocolaccesslog="true"/> |
将访问日志输出到指定文件:
<dubbo:protocolaccesslog="foo/bar.log"/> |
服务容器
(+) (#)
服务容器是一个standalone的启动程序,因为后台服务不需要Tomcat或JBoss等Web容器的功能,如果硬要用Web容器去加载服务提供方,增加复杂性,也浪费资源。 |
||
服务容器只是一个简单的Main方法,并加载一个简单的Spring容器,用于暴露服务。 |
||
服务容器的加载内容可以扩展,内置了spring, jetty, log4j等加载,可通过Container扩展点进行扩展,参见:Container |
Spring Container
· 自动加载META-INF/spring目录下的所有Spring配置。
· 配置:(配在java命令-D参数或者dubbo.properties中)
· dubbo.spring.config=classpath*:META-INF/spring/*.xml ----配置spring配置加载位置
Jetty Container
· 启动一个内嵌Jetty,用于汇报状态。
· 配置:(配在java命令-D参数或者dubbo.properties中)
· dubbo.jetty.port=8080 ----配置jetty启动端口
· dubbo.jetty.directory=/foo/bar ----配置可通过jetty直接访问的目录,用于存放静态文件
· dubbo.jetty.page=log,status,system ----配置显示的页面,缺省加载所有页面
Log4j Container
· 自动配置log4j的配置,在多进程启动时,自动给日志文件按进程分目录。
· 配置:(配在java命令-D参数或者dubbo.properties中)
· dubbo.log4j.file=/foo/bar.log ----配置日志文件路径
· dubbo.log4j.level=WARN ----配置日志级别
· dubbo.log4j.subdirectory=20880 ----配置日志子目录,用于多进程启动,避免冲突
容器启动
如:(缺省只加载spring)
java com.alibaba.dubbo.container.Main |
或:(通过main函数参数传入要加载的容器)
java com.alibaba.dubbo.container.Main spring jetty log4j |
或:(通过JVM启动参数传入要加载的容器)
java com.alibaba.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j |
或:(通过classpath下的dubbo.properties配置传入要加载的容器)
dubbo.properties
dubbo.container=spring,jetty,log4j |
Reference Config缓存
(+) (#)
ReferenceConfig实例很重,封装了与注册中心的连接以及与提供者的连接,需要缓存,否则重复生成ReferenceConfig可能造成性能问题并且会有内存和连接泄漏。API方式编程时,容易忽略此问题。
Dubbo 2.4.0+版本,提供了简单的工具类ReferenceConfigCache用于缓存ReferenceConfig实例。
使用方式如下:
ReferenceConfig<XxxService> reference =newReferenceConfig<XxxService>(); reference.setInterface(XxxService.class); reference.setVersion("1.0.0"); ......
ReferenceConfigCache cache = ReferenceConfigCache.getCache(); XxxService xxxService = cache.get(reference);// cache.get方法中会Cache Reference对象,并且调用ReferenceConfig.get方法启动ReferenceConfig // 注意! Cache会持有ReferenceConfig,不要在外部再调用ReferenceConfig的destroy方法,导致Cache内的ReferenceConfig失效!
// 使用xxxService对象 xxxService.sayHello(); |
消除Cache中的ReferenceConfig,销毁ReferenceConfig并释放对应的资源。
ReferenceConfigCache cache = ReferenceConfigCache.getCache(); cache.destroy(reference); |
缺省ReferenceConfigCache把相同服务Group、接口、版本的ReferenceConfig认为是相同,缓存一份。即以服务Group、接口、版本为缓存的Key。
可以修改这个策略,在ReferenceConfigCache.getCache时,传一个KeyGenerator。详见ReferenceConfigCache类的方法。
KeyGenerator keyGenerator =new...
ReferenceConfigCache cache = ReferenceConfigCache.getCache(keyGenerator ); |
分布式事务
(+) (#)
基于JTA/XA规范实现。 |
||
暂未实现。 |
||
两阶段提交:
API参考手册
(+) (#)
Dubbo的常规功能,都保持零侵入,但有些功能不得不用API侵入才能实现。 |
||
Dubbo中除这里声明以外的接口或类,都是内部接口或扩展接口,普通用户请不要直接依赖,否则升级版本可能出现不兼容。 |
||
API汇总如下:
配置API
· com.alibaba.dubbo.config.ServiceConfig
· com.alibaba.dubbo.config.ReferenceConfig
· com.alibaba.dubbo.config.ProtocolConfig
· com.alibaba.dubbo.config.RegistryConfig
· com.alibaba.dubbo.config.MonitorConfig
· com.alibaba.dubbo.config.ApplicationConfig
· com.alibaba.dubbo.config.ModuleConfig
· com.alibaba.dubbo.config.ProviderConfig
· com.alibaba.dubbo.config.ConsumerConfig
· com.alibaba.dubbo.config.MethodConfig
· com.alibaba.dubbo.config.ArgumentConfig
· 参见:API配置
注解API
· com.alibaba.dubbo.config.annotation.Service
· com.alibaba.dubbo.config.annotation.Reference
· 参见:注解配置
模型API
· com.alibaba.dubbo.common.URL
· com.alibaba.dubbo.rpc.RpcException
上下文API
· com.alibaba.dubbo.rpc.RpcContext
· 参见:上下文信息 & 对方地址 & 隐式传参 & 异步调用
服务API
· com.alibaba.dubbo.rpc.service.GenericService
· com.alibaba.dubbo.rpc.service.GenericException
· 参见:泛化引用 & 泛化实现
· com.alibaba.dubbo.rpc.service.EchoService
· 参见:回声测试
配置参考手册
(+) (#)
这里以Xml配置为准,列举所有配置项,其它配置方式,请参见相应转换关系:属性配置,注解配置,API配置 |
注意:只有group,interface,version是服务的匹配条件,三者决定是不是同一个服务,其它配置项均为调优和治理参数。
所有配置项分为三大类,参见下表中的"作用"一列。
· 服务发现:表示该配置项用于服务的注册与发现,目的是让消费方找到提供方。
· 服务治理:表示该配置项用于治理服务间的关系,或为开发测试提供便利条件。
· 性能调优:表示该配置项用于调优性能,不同的选项对性能会产生影响。
所有配置最终都将转换为URL表示,并由服务提供方生成,经注册中心传递给消费方,各属性对应URL的参数,参见配置项一览表中的"对应URL参数"列。
URL格式:
protocol://username:password@host:port/path?key=value&key=value
Schema: http://code.alibabatech.com/schema/dubbo/dubbo.xsd
<dubbo:service/>
(+) (#)
服务提供者暴露服务配置:
配置类:com.alibaba.dubbo.config.ServiceConfig
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:service> |
interface |
|
class |
必填 |
|
服务发现 |
服务接口名 |
1.0.0以上版本 |
<dubbo:service> |
ref |
|
object |
必填 |
|
服务发现 |
服务对象实现引用 |
1.0.0以上版本 |
<dubbo:service> |
version |
version |
string |
可选 |
0.0.0 |
服务发现 |
服务版本,建议使用两位数字版本,如:1.0,通常在接口不兼容时版本号才需要升级 |
1.0.0以上版本 |
<dubbo:service> |
group |
group |
string |
可选 |
|
服务发现 |
服务分组,当一个接口有多个实现,可以用分组区分 |
1.0.7以上版本 |
<dubbo:service> |
path |
<path> |
string |
可选 |
缺省为接口名 |
服务发现 |
服务路径 (注意:1.0不支持自定义路径,总是使用接口名,如果有1.0调2.0,配置服务路径可能不兼容) |
1.0.12以上版本 |
<dubbo:service> |
delay |
delay |
int |
可选 |
0 |
性能调优 |
延迟注册服务时间(毫秒) ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务 |
1.0.14以上版本 |
<dubbo:service> |
timeout |
timeout |
int |
可选 |
1000 |
性能调优 |
远程服务调用超时时间(毫秒) |
2.0.0以上版本 |
<dubbo:service> |
retries |
retries |
int |
可选 |
2 |
性能调优 |
远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 |
2.0.0以上版本 |
<dubbo:service> |
connections |
connections |
int |
可选 |
100 |
性能调优 |
对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 |
2.0.0以上版本 |
<dubbo:service> |
loadbalance |
loadbalance |
string |
可选 |
random |
性能调优 |
负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮循,最少活跃调用 |
2.0.0以上版本 |
<dubbo:service> |
async |
async |
boolean |
可选 |
false |
性能调优 |
是否缺省异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 |
2.0.0以上版本 |
<dubbo:service> |
stub |
stub |
class/boolean |
可选 |
false |
服务治理 |
设为true,表示使用缺省代理类名,即:接口名 + Local后缀,服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceLocal(XxxService xxxService) |
2.0.0以上版本 |
<dubbo:service> |
mock |
mock |
class/boolean |
可选 |
false |
服务治理 |
设为true,表示使用缺省Mock类名,即:接口名 + Mock后缀,服务接口调用失败Mock实现类,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 |
2.0.0以上版本 |
<dubbo:service> |
token |
token |
string/boolean |
可选 |
false |
服务治理 |
令牌验证,为空表示不开启,如果为true,表示随机生成动态令牌,否则使用静态令牌,令牌的作用是防止消费者绕过注册中心直接访问,保证注册中心的授权功能有效,如果使用点对点调用,需关闭令牌功能 |
2.0.0以上版本 |
<dubbo:service> |
registry |
|
string |
可选 |
缺省向所有registry注册 |
配置关联 |
向指定注册中心注册,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔,如果不想将该服务注册到任何registry,可将值设为N/A |
2.0.0以上版本 |
<dubbo:service> |
provider |
|
string |
可选 |
缺使用第一个provider配置 |
配置关联 |
指定provider,值为<dubbo:provider>的id属性 |
2.0.0以上版本 |
<dubbo:service> |
deprecated |
deprecated |
boolean |
可选 |
false |
服务治理 |
服务是否过时,如果设为true,消费方引用时将打印服务过时警告error日志 |
2.0.5以上版本 |
<dubbo:service> |
dynamic |
dynamic |
boolean |
可选 |
true |
服务治理 |
服务是否动态注册,如果设为false,注册后将显示后disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。 |
2.0.5以上版本 |
<dubbo:service> |
accesslog |
accesslog |
string/boolean |
可选 |
false |
服务治理 |
设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 |
2.0.5以上版本 |
<dubbo:service> |
owner |
owner |
string |
可选 |
|
服务治理 |
服务负责人,用于服务治理,请填写负责人公司邮箱前缀 |
2.0.5以上版本 |
<dubbo:service> |
document |
document |
string |
可选 |
|
服务治理 |
服务文档URL |
2.0.5以上版本 |
<dubbo:service> |
weight |
weight |
int |
可选 |
|
性能调优 |
服务权重 |
2.0.5以上版本 |
<dubbo:service> |
executes |
executes |
int |
可选 |
0 |
性能调优 |
服务提供者每服务每方法最大可并行执行请求数 |
2.0.5以上版本 |
<dubbo:service> |
actives |
actives |
int |
可选 |
0 |
性能调优 |
每服务消费者每服务每方法最大并发调用数 |
2.0.5以上版本 |
<dubbo:service> |
proxy |
proxy |
string |
可选 |
javassist |
性能调优 |
生成动态代理方式,可选:jdk/javassist |
2.0.5以上版本 |
<dubbo:service> |
cluster |
cluster |
string |
可选 |
failover |
性能调优 |
集群方式,可选:failover/failfast/failsafe/failback/forking |
2.0.5以上版本 |
<dubbo:service> |
filter |
service.filter |
string |
可选 |
default |
性能调优 |
服务提供方远程调用过程拦截器名称,多个名称用逗号分隔 |
2.0.5以上版本 |
<dubbo:service> |
listener |
exporter.listener |
string |
可选 |
default |
性能调优 |
服务提供方导出服务监听器名称,多个名称用逗号分隔 |
|
<dubbo:service> |
protocol |
|
string |
可选 |
|
配置关联 |
使用指定的协议暴露服务,在多协议时使用,值为<dubbo:protocol>的id属性,多个协议ID用逗号分隔 |
2.0.5以上版本 |
<dubbo:service> |
layer |
layer |
string |
可选 |
|
服务治理 |
服务提供者所在的分层。如:biz、dao、intl:web、china:acton。 |
2.0.7以上版本 |
<dubbo:service> |
register |
register |
boolean |
可选 |
true |
服务治理 |
该协议的服务是否注册到注册中心 |
2.0.8以上版本 |
<dubbo:reference/>
(+) (#)
服务消费者引用服务配置:
配置类:com.alibaba.dubbo.config.ReferenceConfig
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:reference> |
id |
|
string |
必填 |
|
配置关联 |
服务引用BeanId |
1.0.0以上版本 |
<dubbo:reference> |
interface |
|
class |
必填 |
|
服务发现 |
服务接口名 |
1.0.0以上版本 |
<dubbo:reference> |
version |
version |
string |
可选 |
|
服务发现 |
服务版本,与服务提供者的版本一致 |
1.0.0以上版本 |
<dubbo:reference> |
group |
group |
string |
可选 |
|
服务发现 |
服务分组,当一个接口有多个实现,可以用分组区分,必需和服务提供方一致 |
1.0.7以上版本 |
<dubbo:reference> |
timeout |
timeout |
long |
可选 |
缺省使用<dubbo:consumer>的timeout |
性能调优 |
服务方法调用超时时间(毫秒) |
1.0.5以上版本 |
<dubbo:reference> |
retries |
retries |
int |
可选 |
缺省使用<dubbo:consumer>的retries |
性能调优 |
远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 |
2.0.0以上版本 |
<dubbo:reference> |
connections |
connections |
int |
可选 |
缺省使用<dubbo:consumer>的connections |
性能调优 |
对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 |
2.0.0以上版本 |
<dubbo:reference> |
loadbalance |
loadbalance |
string |
可选 |
缺省使用<dubbo:consumer>的loadbalance |
性能调优 |
负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮循,最少活跃调用 |
2.0.0以上版本 |
<dubbo:reference> |
async |
async |
boolean |
可选 |
缺省使用<dubbo:consumer>的async |
性能调优 |
是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 |
2.0.0以上版本 |
<dubbo:reference> |
generic |
generic |
boolean |
可选 |
缺省使用<dubbo:consumer>的generic |
服务治理 |
是否缺省泛化接口,如果为泛化接口,将返回GenericService |
2.0.0以上版本 |
<dubbo:reference> |
check |
check |
boolean |
可选 |
缺省使用<dubbo:consumer>的check |
服务治理 |
启动时检查提供者是否存在,true报错,false忽略 |
2.0.0以上版本 |
<dubbo:reference> |
url |
<url> |
string |
可选 |
|
服务治理 |
点对点直连服务提供者地址,将绕过注册中心 |
1.0.6以上版本 |
<dubbo:reference> |
stub |
stub |
class/boolean |
可选 |
|
服务治理 |
服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceLocal(XxxService xxxService) |
2.0.0以上版本 |
<dubbo:reference> |
mock |
mock |
class/boolean |
可选 |
|
服务治理 |
服务接口调用失败Mock实现类名,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 |
Dubbo1.0.13及其以上版本支持 |
<dubbo:reference> |
cache |
cache |
string/boolean |
可选 |
|
服务治理 |
以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 |
Dubbo2.1.0及其以上版本支持 |
<dubbo:reference> |
validation |
validation |
boolean |
可选 |
|
服务治理 |
是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 |
Dubbo2.1.0及其以上版本支持 |
<dubbo:reference> |
proxy |
proxy |
boolean |
可选 |
javassist |
性能调优 |
选择动态代理实现策略,可选:javassist, jdk |
2.0.2以上版本 |
<dubbo:reference> |
client |
client |
string |
可选 |
|
性能调优 |
客户端传输类型设置,如Dubbo协议的netty或mina。 |
Dubbo2.0.0以上版本支持 |
<dubbo:reference> |
registry |
|
string |
可选 |
缺省将从所有注册中心获服务列表后合并结果 |
配置关联 |
从指定注册中心注册获取服务列表,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔 |
2.0.0以上版本 |
<dubbo:reference> |
owner |
owner |
string |
可选 |
|
服务治理 |
调用服务负责人,用于服务治理,请填写负责人公司邮箱前缀 |
2.0.5以上版本 |
<dubbo:reference> |
actives |
actives |
int |
可选 |
0 |
性能调优 |
每服务消费者每服务每方法最大并发调用数 |
2.0.5以上版本 |
<dubbo:reference> |
cluster |
cluster |
string |
可选 |
failover |
性能调优 |
集群方式,可选:failover/failfast/failsafe/failback/forking |
2.0.5以上版本 |
<dubbo:reference> |
filter |
reference.filter |
string |
可选 |
default |
性能调优 |
服务消费方远程调用过程拦截器名称,多个名称用逗号分隔 |
2.0.5以上版本 |
<dubbo:reference> |
listener |
invoker.listener |
string |
可选 |
default |
性能调优 |
服务消费方引用服务监听器名称,多个名称用逗号分隔 |
2.0.5以上版本 |
<dubbo:reference> |
layer |
layer |
string |
可选 |
|
服务治理 |
服务调用者所在的分层。如:biz、dao、intl:web、china:acton。 |
2.0.7以上版本 |
<dubbo:reference> |
init |
init |
boolean |
可选 |
false |
性能调优 |
是否在afterPropertiesSet()时饥饿初始化引用,否则等到有人注入或引用该实例时再初始化。 |
2.0.10以上版本 |
<dubbo:reference> |
protocol |
protocol |
string |
可选 |
|
服力治理 |
只调用指定协议的服务提供方,其它协议忽略。 |
2.2.0以上版本 |
<dubbo:protocol/>
(+) (#)
服务提供者协议配置:
配置类:com.alibaba.dubbo.config.ProtocolConfig
说明:如果需要支持多协议,可以声明多个<dubbo:protocol>标签,并在<dubbo:service>中通过protocol属性指定使用的协议。
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:protocol> |
id |
|
string |
可选 |
dubbo |
配置关联 |
协议BeanId,可以在<dubbo:service protocol="">中引用此ID,如果ID不填,缺省和name属性值一样,重复则在name后加序号。 |
2.0.5以上版本 |
<dubbo:protocol> |
name |
<protocol> |
string |
必填 |
dubbo |
性能调优 |
协议名称 |
2.0.5以上版本 |
<dubbo:protocol> |
port |
<port> |
int |
可选 |
dubbo协议缺省端口为20880,rmi协议缺省端口为1099,http和hessian协议缺省端口为80 |
服务发现 |
服务端口 |
2.0.5以上版本 |
<dubbo:protocol> |
host |
<host> |
string |
可选 |
自动查找本机IP |
服务发现 |
-服务主机名,多网卡选择或指定VIP及域名时使用,为空则自动查找本机IP,-建议不要配置,让Dubbo自动获取本机IP |
2.0.5以上版本 |
<dubbo:protocol> |
threadpool |
threadpool |
string |
可选 |
fixed |
性能调优 |
线程池类型,可选:fixed/cached |
2.0.5以上版本 |
<dubbo:protocol> |
threads |
threads |
int |
可选 |
100 |
性能调优 |
服务线程池大小(固定大小) |
2.0.5以上版本 |
<dubbo:protocol> |
iothreads |
threads |
int |
可选 |
cpu个数+1 |
性能调优 |
io线程池大小(固定大小) |
2.0.5以上版本 |
<dubbo:protocol> |
accepts |
accepts |
int |
可选 |
0 |
性能调优 |
服务提供方最大可接受连接数 |
2.0.5以上版本 |
<dubbo:protocol> |
payload |
payload |
int |
可选 |
88388608(=8M) |
性能调优 |
请求及响应数据包大小限制,单位:字节 |
2.0.5以上版本 |
<dubbo:protocol> |
codec |
codec |
string |
可选 |
dubbo |
性能调优 |
协议编码方式 |
2.0.5以上版本 |
<dubbo:protocol> |
serialization |
serialization |
string |
可选 |
dubbo协议缺省为hessian2,rmi协议缺省为java,http协议缺省为json |
性能调优 |
协议序列化方式,当协议支持多种序列化方式时使用,比如:dubbo协议的dubbo,hessian2,java,compactedjava,以及http协议的json等 |
2.0.5以上版本 |
<dubbo:protocol> |
accesslog |
accesslog |
string/boolean |
可选 |
|
服务治理 |
设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 |
2.0.5以上版本 |
<dubbo:protocol> |
path |
<path> |
string |
可选 |
|
服务发现 |
提供者上下文路径,为服务path的前缀 |
2.0.5以上版本 |
<dubbo:protocol> |
transporter |
transporter |
string |
可选 |
dubbo协议缺省为netty |
性能调优 |
协议的服务端和客户端实现类型,比如:dubbo协议的mina,netty等,可以分拆为server和client配置 |
2.0.5以上版本 |
<dubbo:protocol> |
server |
server |
string |
可选 |
dubbo协议缺省为netty,http协议缺省为servlet |
性能调优 |
协议的服务器端实现类型,比如:dubbo协议的mina,netty等,http协议的jetty,servlet等 |
2.0.5以上版本 |
<dubbo:protocol> |
client |
client |
string |
可选 |
dubbo协议缺省为netty |
性能调优 |
协议的客户端实现类型,比如:dubbo协议的mina,netty等 |
2.0.5以上版本 |
<dubbo:protocol> |
dispatcher |
dispatcher |
string |
可选 |
dubbo协议缺省为all |
性能调优 |
协议的消息派发方式,用于指定线程模型,比如:dubbo协议的all, direct, message, execution, connection等 |
2.1.0以上版本 |
<dubbo:protocol> |
queues |
queues |
int |
可选 |
0 |
性能调优 |
线程池队列大小,当线程池满时,排队等待执行的队列大小,建议不要设置,当线程程池时应立即失败,重试其它服务提供机器,而不是排队,除非有特殊需求。 |
2.0.5以上版本 |
<dubbo:protocol> |
charset |
charset |
string |
可选 |
UTF-8 |
性能调优 |
序列化编码 |
2.0.5以上版本 |
<dubbo:protocol> |
buffer |
buffer |
int |
可选 |
8192 |
性能调优 |
网络读写缓冲区大小 |
2.0.5以上版本 |
<dubbo:protocol> |
heartbeat |
heartbeat |
int |
可选 |
0 |
性能调优 |
心跳间隔,对于长连接,当物理层断开时,比如拔网线,TCP的FIN消息来不及发送,对方收不到断开事件,此时需要心跳来帮助检查连接是否已断开 |
2.0.10以上版本 |
<dubbo:protocol> |
telnet |
telnet |
string |
可选 |
|
服务治理 |
所支持的telnet命令,多个命令用逗号分隔 |
2.0.5以上版本 |
<dubbo:protocol> |
register |
register |
boolean |
可选 |
true |
服务治理 |
该协议的服务是否注册到注册中心 |
2.0.8以上版本 |
<dubbo:protocol> |
contextpath |
contextpath |
String |
可选 |
缺省为空串 |
服务治理 |
|
2.0.6以上版本 |
<dubbo:registry/>
(+) (#)
注册中心配置:
配置类:com.alibaba.dubbo.config.RegistryConfig
说明:如果有多个不同的注册中心,可以声明多个<dubbo:registry>标签,并在<dubbo:service>或<dubbo:reference>的registry属性指定使用的注册中心。
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:registry> |
id |
|
string |
可选 |
|
配置关联 |
注册中心引用BeanId,可以在<dubbo:service registry="">或<dubbo:reference registry="">中引用此ID |
1.0.16以上版本 |
<dubbo:registry> |
address |
<host:port> |
string |
必填 |
|
服务发现 |
注册中心服务器地址,如果地址没有端口缺省为9090,同一集群内的多个地址用逗号分隔,如:ip:port,ip:port,不同集群的注册中心,请配置多个<dubbo:registry>标签 |
1.0.16以上版本 |
<dubbo:registry> |
protocol |
<protocol> |
string |
可选 |
dubbo |
服务发现 |
注同中心地址协议,支持dubbo, http, local三种协议,分别表示,dubbo地址,http地址,本地注册中心 |
2.0.0以上版本 |
<dubbo:registry> |
port |
<port> |
int |
可选 |
9090 |
服务发现 |
注册中心缺省端口,当address没有带端口时使用此端口做为缺省值 |
2.0.0以上版本 |
<dubbo:registry> |
username |
<username> |
string |
可选 |
|
服务治理 |
登录注册中心用户名,如果注册中心不需要验证可不填 |
2.0.0以上版本 |
<dubbo:registry> |
password |
<password> |
string |
可选 |
|
服务治理 |
登录注册中心密码,如果注册中心不需要验证可不填 |
2.0.0以上版本 |
<dubbo:registry> |
transport |
registry.transporter |
string |
可选 |
netty |
性能调优 |
网络传输方式,可选mina,netty |
2.0.0以上版本 |
<dubbo:registry> |
timeout |
registry.timeout |
int |
可选 |
5000 |
性能调优 |
注册中心请求超时时间(毫秒) |
2.0.0以上版本 |
<dubbo:registry> |
session |
registry.session |
int |
可选 |
60000 |
性能调优 |
注册中心会话超时时间(毫秒),用于检测提供者非正常断线后的脏数据,比如用心跳检测的实现,此时间就是心跳间隔,不同注册中心实现不一样。 |
2.1.0以上版本 |
<dubbo:registry> |
file |
registry.file |
string |
可选 |
|
服务治理 |
使用文件缓存注册中心地址列表及服务提供者列表,应用重启时将基于此文件恢复,注意:两个注册中心不能使用同一文件存储 |
2.0.0以上版本 |
<dubbo:registry> |
wait |
registry.wait |
int |
可选 |
0 |
性能调优 |
停止时等待通知完成时间(毫秒) |
2.0.0以上版本 |
<dubbo:registry> |
check |
check |
boolean |
可选 |
true |
服务治理 |
注册中心不存在时,是否报错 |
2.0.0以上版本 |
<dubbo:registry> |
register |
register |
boolean |
可选 |
true |
服务治理 |
是否向此注册中心注册服务,如果设为false,将只订阅,不注册 |
2.0.5以上版本 |
<dubbo:registry> |
subscribe |
subscribe |
boolean |
可选 |
true |
服务治理 |
是否向此注册中心订阅服务,如果设为false,将只注册,不订阅 |
2.0.5以上版本 |
<dubbo:registry> |
dynamic |
dynamic |
boolean |
可选 |
true |
服务治理 |
服务是否动态注册,如果设为false,注册后将显示后disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。 |
2.0.5以上版本 |
<dubbo:monitor/>
(+) (#)
监控中心配置:
配置类:com.alibaba.dubbo.config.MonitorConfig
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:monitor> |
protocol |
protocol |
string |
可选 |
dubbo |
服务治理 |
监控中心协议,如果为protocol="registry",表示从注册中心发现监控中心地址,否则直连监控中心。 |
2.0.9以上版本 |
<dubbo:monitor> |
address |
<url> |
string |
可选 |
N/A |
服务治理 |
直连监控中心服务器地址,address="10.20.130.230:12080" |
1.0.16以上版本 |
<dubbo:application/>
(+) (#)
应用信息配置:
配置类:com.alibaba.dubbo.config.ApplicationConfig
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
缺省值 |
作用 |
描述 |
兼容性 |
<dubbo:application> |
name |
application |
string |
必填 |
|
服务治理 |
当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样,此参数不是匹配条件,你当前项目叫什么名字就填什么,和提供者消费者角色无关,比如:kylin应用调用了morgan应用的服务,则kylin项目配成kylin,morgan项目配成morgan,可能kylin也提供其它服务给别人使用,但kylin项目永远配成kylin,这样注册中心将显示kylin依赖于morgan |
1.0.16以上版本 |
<dubbo:application> |
version |
application.version |
string |
可选 |
|
服务治理 |
当前应用的版本 |
2.2.0以上版本 |
<dubbo:application> |
owner |
owner |
string |
可选 |
|
服务治理 |
应用负责人,用于服务治理,请填写负责人公司邮箱前缀 |
2.0.5以上版本 |
<dubbo:application> |
organization |
organization |
string |
可选 |
|
服务治理 |
组织名称(BU或部门),用于注册中心区分服务来源,此配置项建议不要使用autoconfig,直接写死在配置中,比如china,intl,itu,crm,asc,dw,aliexpress等 |
2.0.0以上版本 |
<dubbo:application> |
architecture |
architecture |
string |
可选 |
|
服务治理 |
用于服务分层对应的架构。如,intl、china。不同的架构使用不同的分层。 |
2.0.7以上版本 |
<dubbo:application> |
environment |
environment |
string |
可选 |
|
服务治理 |
应用环境,如:develop/test/product,不同环境使用不同的缺省值,以及作为只用于开发测试功能的限制条件 |
2.0.0以上版本 |
<dubbo:application> |
compiler |
compiler |
string |
可选 |
javassist |
性能优化 |
Java字节码编译器,用于动态类的生成,可选:jdk或javassist |
2.1.0以上版本 |
<dubbo:application> |
logger |
logger |
string |
可选 |
slf4j |
性能优化 |
日志输出方式,可选:slf4j,jcl,log4j,jdk |
2.2.0以上版本 |
<dubbo:module/>
(+) (#)
模块信息配置:
配置类:com.alibaba.dubbo.config.ModuleConfig
标签 |
属性 |
对应URL参数 |
类型 |
是否必填 |
|