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.
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:service 和 dubbo: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:service 和 dubbo: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,即可登入成功