1. 程式人生 > >dubbo框架的搭建及各種功能的實現

dubbo框架的搭建及各種功能的實現

之前專案中用過dubbo做分散式,最近想把這個框架的搭建及一些基本功能的使用記錄下來。

註冊中心用zookeeper

架構

Provider	暴露服務的服務提供⽅
Consumer	調⽤遠端服務的服務消費⽅
Registry	服務註冊與發現的註冊中⼼
Monitor	統計服務的調⽤次調和調⽤時間的監控中⼼
Container	服務運⾏容器

Dubbo 架構具有以下⼏個特點,分別是連通性、健壯性、伸縮性、以及向未來架構的升級性

建立一個dubbo-parent的maven project, packaging型別設定為pom,
在dubbo-parent下建立3個maven module,分別是dubbo-consumer、dubbo-provider,和dubbo-api packaging型別設定為jar
dubbo-parent的pom依賴及外掛如下

org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE


<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
1.0.0

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
	</dependency>
	<!-- Spring Boot Dubbo 依賴 -->
	<dependency>
		<groupId>io.dubbo.springboot</groupId>
		<artifactId>spring-boot-starter-dubbo</artifactId>
		<version>${dubbo-spring-boot}</version>
		<exclusions>
			<exclusion>
				<groupId>org.apache.zookeeper</groupId>
				<artifactId>zookeeper</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-test</artifactId>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.46</version>
	</dependency>
	<!-- Junit -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
	</dependency>
	<dependency>
		<groupId>org.apache.zookeeper</groupId>
		<artifactId>zookeeper</artifactId>
		<version>3.4.13</version>
	</dependency>
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
	</dependency>
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
	</dependency>

</dependencies>
<modules>
	<module>dubbo-api</module>
	<module>dubbo-provider</module>
	<module>dubbo-consumer</module>

dubbo-api專案建立一個介面
public interface DubboService {

public void sayHello(String str);

}

dubbo-provider專案
@Service(version = “1.0.0”)
public class DubboServiceImpl implements DubboService{

private static final Logger logger = LoggerFactory.getLogger(DubboServiceImpl.class);

@Override
public void sayHello(String str) {
	logger.info("列印資訊:" + str);
}

}

pom中要依賴dubbo-api專案

<dependency>
	<groupId>com.zookeeper</groupId>
	<artifactId>dubbo-api</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
	<groupId>io.dubbo.springboot</groupId>
	<artifactId>spring-boot-starter-dubbo</artifactId>
	<version>${dubbo-spring-boot}</version>
	<exclusions>
		<exclusion>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
		</exclusion>
	</exclusions>
</dependency>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<fork>true</fork>
			</configuration>
		</plugin>
	</plugins>
</build>

配置檔案
server:
port: 8092
spring:
dubbo:
application:
name: dubbo-provider
registry:
protocol: zookeeper
address: 127.0.0.1:2181, 127.0.0.1:2182
protocol:
name: dubbo
port: 20880
scan: org.dubbo.provider.service.impl

dubbo-consumer專案 pom配置

	<dependency>
		<groupId>com.zookeeper</groupId>
		<artifactId>dubbo-api</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</dependency>
</dependencies>

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<fork>true</fork>
			</configuration>
		</plugin>
	</plugins>
</build>

程式碼呼叫介面
@RestController
public class DubboController {

@Reference(version = "1.0.0")
private DubboService dubboService;

@GetMapping("/sayHello")
public String sayHello() {
	dubboService.sayHello("consumer 請求dubbo服務");
	return "請求成功";
}

}

配置檔案
server:
port: 8800
spring:
dubbo:
application:
name: dubbo-consumer
registry:
protocol: zookeeper
address: 127.0.0.1:2181, 127.0.0.1:2182
scan: org.dubbo.consumer.controller

啟動zookeeper, 在啟動dubbo-provider, 最後啟動dubbo-consumer專案,開啟瀏覽器,輸入地址localhost:8800/sayHello
控制欄輸出: 列印資訊:consumer 請求dubbo服務

通過api呼叫服務
建立專案dubbo-generic-consumer
public class BaseInvoker2 {

private ReferenceConfig<GenericService> config = null;

public BaseInvoker2() {
	config = new ReferenceConfig<>();
	ApplicationConfig configApplication = new ApplicationConfig();
	configApplication.setName("dubbo-generic-consumer");
	configApplication.setVersion("1.0.0");
	config.setApplication(configApplication);
	RegistryConfig registryConfig = new RegistryConfig();
	registryConfig.setProtocol("zookeeper");
	registryConfig.setAddress("127.0.0.1:2181, 127.0.0.1:2182");
	config.setRegistry(registryConfig);
	config.setProtocol("dubbo");
	
}

public void setInterface(String interfaceName) {
	config.setInterface(interfaceName);
}

public void setVersion(String version) {
	config.setVersion(version);
}

public Object invokeMethod(String method, String[] parameterTypes, Object[] values) {
	ReferenceConfigCache cache = ReferenceConfigCache.getCache();
	GenericService service = cache.get(config);
	return service.$invoke(method, parameterTypes, values);
	
}

public void setGeneric(boolean flag) {
	config.setGeneric(flag);
}

public void setGroup(String group) {
	config.setGroup(group);
}

}

@RestController
public class GenericConsumerController {

private static final Logger logger = LoggerFactory.getLogger(GenericConsumerController.class);

@GetMapping("/infos")
public String getGeneric() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.DubboService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	String[] parameterTypes = { "java.lang.String", "java.lang.String", "java.lang.Integer" };
	Object[] values = { "王五", "男", 35 };
	Object result = baseInvoker2.invokeMethod("getInfo", parameterTypes, values);
	logger.info(result.toString());
	return null;
}

@GetMapping("/diff")
public String getDifferences() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.GroupService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	baseInvoker2.setGroup("a1");
	String[] parameterTypes = {};
	Object[] values = {};
	Object result = baseInvoker2.invokeMethod("groupInfo", parameterTypes, values);
	logger.info(result.toString());
	return (String) result;
}

@GetMapping("/diff2")
public String getDifference() {
	BaseInvoker2 baseInvoker2 = new BaseInvoker2();
	baseInvoker2.setInterface("org.dubbo.api02.GroupService");
	baseInvoker2.setVersion("1.0.0");
	baseInvoker2.setGeneric(true);
	baseInvoker2.setGroup("a2");
	String[] parameterTypes = {};
	Object[] values = {};
	Object result = baseInvoker2.invokeMethod("groupInfo", parameterTypes, values);
	logger.info(result.toString());
	return (String) result;
}

}

啟動時檢查
關閉某個服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:reference interface=“com.foo.BarService” check=“false” />
關閉所有服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:consumer check=“false” />
關閉註冊中⼼啟動時檢查 (註冊訂閱失敗時報錯):
<dubbo:registry check=“false” />

叢集容錯
重試次數配置如下:
<dubbo:service retries=“2” />

<dubbo:reference retries=“2” />

dubbo:reference
<dubbo:method name=“findFoo” retries=“2” />
</dubbo:reference>

按照以下示例在服務提供⽅和消費⽅配置叢集模式
<dubbo:service cluster=“failsafe” />

<dubbo:reference cluster=“failsafe” />

負載均衡
Dubbo 提供了多種均衡策略,預設為 random 隨機調⽤
Random LoadBalance
隨機,按權重設定隨機概率。
RoundRobin LoadBalance
輪循,按公約後的權重設定輪循⽐率
LeastActive LoadBalance
最少活躍調⽤數,相同活躍數的隨機,活躍數指調⽤前後計數差。
ConsistentHash LoadBalance
⼀致性 Hash,相同引數的請求總是發到同⼀提供者

服務端服務級別
<dubbo:service interface="…" loadbalance=“roundrobin” />
客戶端服務級別
<dubbo:reference interface="…" loadbalance=“roundrobin” />
服務端⽅法級別
<dubbo:service interface="…">
<dubbo:method name="…" loadbalance=“roundrobin”/>
</dubbo:service>
客戶端⽅法級別
<dubbo:reference interface="…">
<dubbo:method name="…" loadbalance=“roundrobin”/>
</dubbo:reference>

執行緒模型
<dubbo:protocol name=“dubbo” dispatcher=“all” threadpool=“fixed” threads=“100” />
Dispatcher
all 所有訊息都派發到執行緒池,包括請求,響應,連線事件,斷開事件,⼼跳等。
direct 所有訊息都不派發到執行緒池,全部在 IO 執行緒上直接執⾏。
message 只有請求響應訊息派發到執行緒池,其它連線斷開事件,⼼跳等訊息,直接在 IO 執行緒上執⾏。
execution 只請求訊息派發到執行緒池,不含響應,響應和其它連線斷開事件,⼼跳等訊息,直接在 IO 執行緒上執 ⾏。 connection 在 IO 執行緒上,將連線斷開事件放⼊佇列,有序逐個執⾏,其它訊息派發到執行緒池。
ThreadPool
fixed 固定⼤⼩執行緒池,啟動時建⽴執行緒,不關閉,⼀直持有。(預設)
cached 快取執行緒池,空閒⼀分鐘⾃動刪除,需要時重建。
limited 可伸縮執行緒池,但池中的執行緒數只會增⻓不會收縮。只增⻓不收縮的⽬的是為了避免收縮時突然來了⼤ 流量引起的效能問題。

服務分組
當⼀個接⼝有多種實現時,可以⽤ group 區分
服務
<dubbo:service group=“feedback” interface=“com.xxx.IndexService” />
<dubbo:service group=“member” interface=“com.xxx.IndexService” />
引⽤
<dubbo:reference id=“feedbackIndexService” group=“feedback” interface=“com.xxx.IndexService” /> <dubbo:reference id=“memberIndexService” group=“member” interface=“com.xxx.IndewxService” />

任意組 :
<dubbo:reference id=“barService” interface=“com.foo.BarService” group="*" />

多版本
⽼版本服務提供者配置:
<dubbo:service interface=“com.foo.BarService” version=“1.0.0” />
新版本服務提供者配置:
<dubbo:service interface=“com.foo.BarService” version=“2.0.0” />
⽼版本服務消費者配置:
<dubbo:reference id=“barService” interface=“com.foo.BarService” version=“1.0.0” />
新版本服務消費者配置:
<dubbo:reference id=“barService” interface=“com.foo.BarService” version=“2.0.0” />
如果不需要區分版本,可以按照以下的⽅式配置 :
<dubbo:reference id=“barService” interface=“com.foo.BarService” version="*" />

分組聚合
有多種實現,⽤group區分,現在消費⽅需從每種group中調⽤⼀次 返回結果,合併結果返回,這樣就可以實現聚合選單項
搜尋所有分組
<dubbo:reference interface=“com.xxx.MenuService” group="" merger=“true” />
合併指定分組
<dubbo:reference interface=“com.xxx.MenuService” group=“aaa,bbb” merger=“true” />
指定⽅法合併結果,其它未指定的⽅法,將只調⽤⼀個 Group
<dubbo:reference interface=“com.xxx.MenuService” group="
">
<dubbo:method name=“getMenuItems” merger=“true” />
</dubbo:service>
某個⽅法不合並結果,其它都合併結果
<dubbo:reference interface=“com.xxx.MenuService” group="" merger=“true”>
<dubbo:method name=“getMenuItems” merger=“false” />
</dubbo:service>
指定合併策略,預設根據返回值型別⾃動匹配,如果同⼀型別有兩個合併器時,需指定合併器的名稱
<dubbo:reference interface=“com.xxx.MenuService” group="
"> <dubbo:method name=“getMenuItems” merger=“mymerge” /> </dubbo:service>
指定合併⽅法,將調⽤返回結果的指定⽅法進⾏合併,合併⽅法的引數型別必須是返回結果型別本身
<dubbo:reference interface=“com.xxx.MenuService” group="*">
<dubbo:method name=“getMenuItems” merger=".addAll" />
</dubbo:service>

引數驗證

<groupId>javax.validation</groupId>				
<artifactId>validation-api</artifactId>				
<version>1.0.0.GA</version> 
<groupId>org.hibernate</groupId>				
<artifactId>hibernate-validator</artifactId>				
<version>4.2.0.Final</version> 

結果快取
lru 基於最近最少使⽤原則刪除多餘快取,保持最熱的資料被快取。
threadlocal 當前執行緒快取,⽐如⼀個⻚⾯渲染,⽤到很多 portal,每個 portal 都要去查⽤戶資訊,通過執行緒緩 存,可以減少這種多餘訪問。
jcache 與 JSR107 整合,可以橋接各種快取實現
<dubbo:reference interface=“com.foo.BarService” cache=“lru” />
或:
<dubbo:reference interface=“com.foo.BarService”>
<dubbo:method name=“findBar” cache=“lru” />
</dubbo:reference>

泛化調⽤
通過 GenericService 調⽤所有服務實現,引數及返回值中的所有 POJO 均⽤ Map 表示,通 常⽤於框架整合
<dubbo:reference id=“barService” interface=“com.foo.BarService” generic=“true” />

api呼叫例子:
ReferenceConfig reference = new ReferenceConfig(); // 弱型別接⼝名 reference.setInterface(“com.xxx.XxxService”);
reference.setVersion(“1.0.0”); // 宣告為泛化接⼝ reference.setGeneric(true);
// ⽤com.alibaba.dubbo.rpc.service.GenericService可以替代所有接⼝引⽤
GenericService genericService = reference.get();
// 基本型別以及Date,List,Map等不需要轉換,直接調⽤
Object result = genericService. i n v o k e ( &quot; s a y H e l l o &quot; , n e w S t r i n g [ ] &quot; j a v a . l a n g . S t r i n g &quot; , n e w O b j e c t [ ] &quot; w o r l d &quot; ) ; / / M a p P O J O P O J O M a p M a p &lt; S t r i n g , O b j e c t &gt; p e r s o n = n e w H a s h M a p &lt; S t r i n g , O b j e c t &gt; ( ) ; p e r s o n . p u t ( &quot; n a m e &quot; , &quot; x x x &quot; ) ; p e r s o n . p u t ( &quot; p a s s w o r d &quot; , &quot; y y y &quot; ) ; / / P O J O M a p O b j e c t r e s u l t = g e n e r i c S e r v i c e . invoke(&quot;sayHello&quot;, new String[] {&quot;java.lang.String&quot;}, new Object[] {&quot;world&quot;}); // ⽤Map表示POJO引數,如果返回值為POJO也將⾃動轉成Map Map&lt;String, Object&gt; person = new HashMap&lt;String, Object&gt;(); person.put(&quot;name&quot;, &quot;xxx&quot;); person.put(&quot;password&quot;, &quot;yyy&quot;); // 如果返回POJO將⾃動轉成Map Object result = genericService. invoke(“findPerson”, new String[] {“com.xxx.Person”}, new Object[]{person});

回聲測試
回聲測試⽤於檢測服務是否可⽤,回聲測試按照正常請求流程執⾏,能夠測試整個調⽤是否通暢,可⽤於監控。

上下⽂資訊
RpcContext 是⼀個 ThreadLocal 的臨時狀態記錄器,當接收到 RPC 請求,或發起 RPC 請求時,RpcContext 的狀態 都會變化

非同步調⽤
在 consumer.xml 中配置:
<dubbo:reference id=“fooService” interface=“com.alibaba.foo.FooService”>
<dubbo:method name=“findFoo” async=“true” />
</dubbo:reference>
<dubbo:reference id=“barService” interface=“com.alibaba.bar.BarService”>
<dubbo:method name=“findBar” async=“true” />
</dubbo:reference>

程式碼
// 此調⽤會⽴即返回null fooService.findFoo(fooId); // 拿到調⽤的Future引⽤,當結果返回後,會被通知和設定到此Future Future fooFuture = RpcContext.getContext().getFuture();
// 此調⽤會⽴即返回null barService.findBar(barId); // 拿到調⽤的Future引⽤,當結果返回後,會被通知和設定到此Future Future barFuture = RpcContext.getContext().getFuture();
// 此時findFoo和findBar的請求同時在執⾏,客戶端不需要啟動多執行緒來⽀持並⾏,⽽是藉助NIO的⾮阻塞完成
// 如果foo已返回,直接拿到返回值,否則執行緒wait住,等待foo返回後,執行緒會被notify喚醒
Foo foo = fooFuture.get(); // 同理等待bar返回 Bar
bar = barFuture.get();

sent=“true” 等待訊息發出,訊息傳送失敗將丟擲異常。 sent=“false” 不等待訊息發出,將訊息放⼊ IO 佇列,即刻返回。
<dubbo:method name=“findFoo” async=“true” sent=“true” />
如果你只是想非同步,完全忽略返回值,可以配置 return=“false” ,以減少 Future 物件的建立和管理成本:
<dubbo:method name=“findFoo” async=“true” return=“false” />

引數回撥
服務接⼝示例
public interface CallbackService {
void addListener(String key, CallbackListener listener);
}

public interface CallbackListener {
void changed(String msg);
}

服務提供者接⼝實現示例
public class CallbackServiceImpl implements CallbackService {
private final Map<String, CallbackListener> listeners = new ConcurrentHashMap<String, CallbackListener>();
public CallbackServiceImpl() { Thread t = new Thread(new Runnable() { public void run() { 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();				}

public void addListener(String key, CallbackListener listener) {
listeners.put(key, listener);
listener.changed(getChanged(key)); // 傳送變更通知
}
private String getChanged(String key) {
return "Changed: " + new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date());
} }

服務提供者配置示例

<dubbo:service interface=“com.callback.CallbackService” ref=“callbackService” connections=“1” callbacks=“1000”> <dubbo:method name=“addListener”>
<dubbo:argument index=“1” callback=“true” />
</dubbo:method> </dubbo:service>

服務消費者配置示例
<dubbo:reference id=“callbackService” interface=“com.callback.CallbackService” />
服務消費者調⽤示例
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“classpath:consumer.xml”); context.start();
CallbackService callbackService = (CallbackService) context.getBean(“callbackService”);
callbackService.addListener(“http://10.20.160.198/wiki/display/dubbo/foo.bar”, new CallbackListener(){
public void changed(String msg) { System.out.println(“callback1:” + msg); } });

事件通知
在調⽤之前、調⽤之後、出現異常時,會觸發 oninvoke 、 onreturn 、 onthrow 三個事件,可以配置當事件發⽣時, 通知哪個類的哪個⽅法
服務提供者與消費者共享服務接⼝
interface IDemoService { public Person get(int id); }
服務提供者實現
class NormalDemoService implements IDemoService {
public Person get(int id) { return new Person(id, “charles`son”, 4); } }

服務提供者配置
<dubbo:application name=“rpc-callback-demo” />
<dubbo:registry address=“http://10.20.160.198/wiki/display/dubbo/10.20.153.186” />

<dubbo:service interface=“com.alibaba.dubbo.callback.implicit.IDemoService” ref=“demoService” version=“1.0.0” g roup=“cn”/>

服務消費者 Callback 接⼝
interface Notify {
public void onreturn(Person msg, Integer id); public void onthrow(Throwable ex, Integer id); }

服務消費者 Callback 實現
class NotifyImpl implements Notify {
public Map<Integer, Person> ret = new HashMap<Integer, Person>();
public Map<Integer, Throwable> errors = new HashMap<Integer, Throwable>();
public void onreturn(Person msg, Integer id) {
System.out.println(“onreturn:” + msg);
ret.put(id, msg); }
public void onthrow(Throwable ex, Integer id) {
errors.put(id, ex); } }

服務消費者 Callback 配置

<dubbo:reference id=“demoService” interface=“com.alibaba.dubbo.callback.implicit.IDemoService” version=“1.0.0” group=“cn” >
<dubbo:method name=“get” async=“true” onreturn = “demoCallback.onreturn” onthrow=“demoCallback.onthrow” />
</dubbo:reference>

callback 與 async 功能正交分解, async=true 表示結果是否⻢上返回, onreturn 表示是否需要回調。 兩者疊加存在以下⼏種組合情況 :
非同步回撥模式: async=true onreturn=“xxx” 同步回撥模式: async=false onreturn=“xxx” 非同步⽆回撥 : async=true 同步⽆回撥 : async=false

本地存根
<dubbo:service interface=“com.foo.BarService” stub=“true” />

<dubbo:service interface=“com.foo.BarService” stub=“com.foo.BarServiceStub” />

本地偽裝

本地偽裝 通常⽤於服務降級,⽐如某驗權服務,當服務提供⽅全部掛掉後,客戶端不丟擲異常,⽽是通過 Mock 資料 返回授權失敗。

<dubbo:service interface=“com.foo.BarService” mock=“true” />

<dubbo:service interface=“com.foo.BarService” mock=“com.foo.BarServiceMock” />

如果服務的消費⽅經常需要 try-catch 捕獲異常,請考慮改為 Mock 實現,並在 Mock 實現中 return null
<dubbo:service interface=“com.foo.BarService” mock=“return null” />

延遲暴露
你的服務需要預熱時間,⽐如初始化快取,等待相關資源就位等,可以使⽤ delay 進⾏延遲暴露
<dubbo:service delay=“5000” />

併發控制
限制 com.foo.BarService 的每個⽅法,伺服器端併發執⾏(或佔⽤執行緒池執行緒數)不能超過 10 個:
<dubbo:service interface=“com.foo.BarService” executes=“10” />

限制 com.foo.BarService 的 sayHello ⽅法,伺服器端併發執⾏(或佔⽤執行緒池執行緒數)不能超過 10 個:
<dubbo:service interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” executes=“10” />
</dubbo:service>

限制 com.foo.BarService 的每個⽅法,每客戶端併發執⾏(或佔⽤連線的請求數)不能超過 10 個:
<dubbo:service interface=“com.foo.BarService” actives=“10” />

<dubbo:reference interface=“com.foo.BarService” actives=“10” />

限制 com.foo.BarService 的 sayHello ⽅法,每客戶端併發執⾏(或佔⽤連線的請求數)不能超過 10 個:
<dubbo:service interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” actives=“10” />
</dubbo:service>

<dubbo:reference interface=“com.foo.BarService”>
<dubbo:method name=“sayHello” actives=“10” />
</dubbo:service>
如果 dubbo:servicedubbo:reference 都配了actives, dubbo:reference 優先

Load Balance 均衡
配置服務的客戶端的 loadbalance 屬性為 leastactive ,此 Loadbalance 會調⽤併發數最⼩的 Provider(Consumer 端併發數)。
<dubbo:reference interface=“com.foo.BarService” loadbalance=“leastactive” />

<dubbo:service interface=“com.foo.BarService” loadbalance=“leastactive” />

連線控制
服務端連線控制
限制伺服器端接受的連線不能超過 10 個 :
<dubbo:provider protocol=“dubbo” accepts=“10” />

<dubbo:protocol name=“dubbo” accepts=“10” />

客戶端連線控制
限制客戶端服務使⽤連線不能超過 10 個 :
<dubbo:reference interface=“com.foo.BarService” connections=“10” />

<dubbo:service interface=“com.foo.BarService” connections=“10” />
如果 dubbo:servicedubbo:reference 都配了 connections, dubbo:reference 優先

延遲連線
延遲連線⽤於減少⻓連線數。當有調⽤發起時,再建立⻓連線。
<dubbo:protocol name=“dubbo” lazy=“true” />

粘滯連線
粘滯連線⽤於有狀態服務,儘可能讓客戶端總是向同⼀提供者發起調⽤,除⾮該提供者掛了,再連另⼀臺。
粘滯連線將⾃動開啟延遲連線,以減少⻓連線數。
<dubbo:protocol name=“dubbo” sticky=“true” />

令牌驗證
通過令牌驗證在註冊中⼼控制權限,以決定要不要下發令牌給消費者,可以防⽌消費者繞過註冊中⼼訪問提供者
可以全域性設定開啟令牌驗證:

<dubbo:provider interface=“com.foo.BarService” token=“true” />

<dubbo:provider interface=“com.foo.BarService” token=“123456” />
也可在服務級別設定:

<dubbo:service interface=“com.foo.BarService” token=“true” />

<dubbo:service interface=“com.foo.BarService” token=“123456” />
還可在協議級別設定:

<dubbo:protocol name=“dubbo” token=“true” />

<dubbo:protocol name=“dubbo” token=“123456” />

路由規則
路由規則 決定⼀次 dubbo 服務調⽤的⽬標伺服器,分為條件路由規則和指令碼路由規則,並且⽀持可擴充套件
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); 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=” + U RL.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

指令碼路由規則
指令碼路由規則 ⽀持 JDK 指令碼引擎的所有指令碼,⽐如:javascript, jruby, groovy 等,通過 type=javascript 引數設定 指令碼型別,預設為 javascript。
“script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=” + URL.encode(“function route(invoker s) { … } (invokers)”)
基於指令碼引擎的路由規則,如:
function route(invokers) { var result = new java.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)); } } return result; } (invokers); // 表示⽴即執⾏⽅法

配置規則
向註冊中⼼寫⼊動態配置覆蓋規則 。該功能通常由監控中⼼或治理中⼼的⻚⾯完成。
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); 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&appli cation=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:retu rn+null

服務降級
可以通過服務降級功能 臨時遮蔽某個出錯的⾮關鍵服務,並定義降級後的返回策略。
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtensio n(); 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&appli cation=foo&mock=force:return+null”));
其中: mock=force:return+null 表示消費⽅對該服務的⽅法調⽤都直接返回 null 值,不發起遠端調⽤。⽤來遮蔽不重要服 務不可⽤時對調⽤⽅的影響。 還可以改為 mock=fail:return+null 表示消費⽅對該服務的⽅法調⽤在失敗後,再返回 null 值,不拋異常。⽤來容 忍不重要服務不穩定時對調⽤⽅的影響。

主機繫結
<dubbo:protocol host=“205.182.23.201”>

端⼝配置
dubbo 20880
rmi 1099
http 80
hessian 80
webservice 80
memcached 11211
redis 6379

⽇志適配

<dubbo:application logger=“log4j” />

dubbo.application.logger=log4j

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
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

功能使用

1)在泛化引用dubbo時,因為referencrConfig是一個很重的例項,所以需要使用到快取
ReferenceConfigCache cache = ReferenceConfigCache.getCache();
GenericService service = cache.get(config);//config是ReferenceConfig例項

2)dubbo-admin管理平臺搭建
通過dubbo-admin可以對消費者和提供者進行管理.可自行到官網下載:https://github.com/apache/incubator-dubbo-ops下載。

下載下來後,進入incubator-dubbo-ops資料夾,在此處開啟命令列視窗;
執行 mvn package -Dmaven.test.skip=true 命令,打包該專案;
在生成的target資料夾中找到dubbo-admin的jar包,在命令列執行該專案就好了;
根據列印的日誌找到 current host:yourip 和 Tomcat started on port(s): yourport
瀏覽器訪問yourip:yourport;
使用者名稱和密碼都輸入root或都輸guest,即可登入成功