中間件(Middleware)是提供系統軟體和應用軟體之間連接配接的軟體,以便于軟體各部件之間的溝通,特别是應用軟體對于系統軟體的集中的邏輯,在現代資訊技術應用架構如Web服務、面向服務的體系結構等中應用比較廣泛
目錄
1. 中間件技術
2. MetaQ中間件
3. MetaQ程式設計實踐
1. 中間件技術
0x1: 中間件簡介
中間件(Middleware)是提供系統軟體和應用軟體之間連接配接的軟體,以便于軟體各部件之間的溝通,特别是應用軟體對于系統軟體的集中的邏輯,在現代資訊技術應用架構如Web服務、面向服務的體系結構等中應用比較廣泛,如:
1. 資料庫
2. Apache的Tomcat
3. IBM公司的WebSphere
4. BEA公司的WebLogic[[應用伺服器]
5. 東方通公司的Tong系列中間件
6. Kingdee公司的等
都屬于中間件,中間件技術本質上就是在計算機系統不同層次的子產品之間的異構、跨協定的通信問題
嚴格來講,中間件技術已經不局限于應用伺服器、資料庫伺服器。中間件技術建立在對應用軟體部分常用功能的抽象上,将常用且重要的
1. 過程調用
2. 分布式元件
3. 消息隊列
4. 事務
5. 安全
6. 連結器
7. 商業流程
8. 網絡并發
9. HTTP伺服器
10. Web Service
等功能集于一身或者分别在不同産品中分别完成 ,我國學術界一般認可的定義是中間件是指網絡環境下處于作業系統、資料庫等系統軟體和應用軟體之間的一種起連接配接作用的分布式軟體,主要解決異構網絡環境下分布式應用軟體的互連與互操作問題,提供标準接口、協定,屏蔽實作細節,提高應用系統易移植性
0x2: 中間件的特征(内涵)
總的來說,中間件有幾個非常重要的特征
1. 平台化
所謂平台就是能夠獨立運作并自主存在,為其所支撐的上層系統和應用提供運作所依賴的環境。中間件是一個平台,是以中間件是必須獨立存在,是運作時刻的"系統軟體",它為上層的網絡應用系統提供一個運作環境,并通過标準的接口和API來隔離其支撐的系統,實作其獨立性,也就是平台性。J2EE應用伺服器提供JAVA應用的運作環境,就是經典的中間件
2. 應用支撐
中間件的最終目的是解決上層應用系統的問題,而且也是軟體技術發展到今天對應用軟體提供最完善徹底的解決方案。
1) 進階程式設計語言的發明,使得軟體開發變成一個獨立的科學和技術體系,而作業系統平台的出現,使得應用軟體通過标準的API接口,實作了軟體與硬體的分離。
2) 現代面向服務(SOA)的中間件在軟體的模型、結構、互操作以及開發方法等四個方面提供了更強的應用支撐能力:
2.1) 模型:構件模型彈性粒度化
通過抽象層度更高的構件模型,實作具備更高結構獨立性、内容自包含性和業務完整性的可複用構件,即服務(RESTFUL API就是一個最好的例子)。并且在細粒度服務基礎上,提供了更粗粒度的服務封裝方式,即業務層面的封裝,形成業務元件,就可以實作從元件模型到業務模型的全生命周期企業模組化的能力。
2.2) 結構:結構松散化
将"服務描述"和"服務功能實作"分離,将"服務的使用者"和"提供者"分離,進而避免分布式應用系統建構和內建時常見的技術、組織、時間等不良限制。
2.3) 互操作:互動過程标準化
将與互操作相關的内容進行标準化定義,如服務封裝、描述、釋出、發現、調用等契約,通信協定以及資料交換格式等等。最終實作通路互操作、連接配接互操作和語義互操作(RESTFUL、SOAP、WPF、WebService、SCA/SDO)
2.4) 開發內建方法:
應用系統的建構方式由代碼編寫轉為主要通過服務間的快捷組合及編排,完成更為複雜的業務邏輯的按需提供和改善,進而大大簡化和加速應用系統的搭建及重構過程(一種典型的輕耦合思想)而要最終解決軟體的品質問題、效率問題、互操作問題、靈活應變問題這四大問題,需要在軟體技術的内在結構(Structure)、架構(Architecture)層面進行思考。解決這些問題,技術的本質是複用、松耦合、互操作(标準)等軟體技術的内在機制。這也是中間件技術和産品的本質特征
3. 軟體複用
軟體複用,即軟體的重用,也叫再用,是指同一事物不作修改或稍加改動就多次重複使用。從軟體複用技術的發展來看,就是不斷提升抽象級别,擴大複用範圍。最早的複用技術是子程式,人們發明子程式,就可以在不同系統之間進行複用了。但是,子程式是最原始的複用,因為這種複用範圍是一個可執行程式内複用,靜态開發期複用,如果子程式修改,意味着所有調用這個子程式的程式必須重新編譯、測試和釋出
複用對象複用範圍
1) 子程式: 一個可執行程式内複用: 靜态開發期複用
2) 元件(DLL、Com..): 系統内複用,動态運作期複用
3) 企業對象元件(Com+、.NET、EJB..): 企業網絡内複用,不同系統之間複用
4) 服務(RESTFUL、SOAP、WPF、WebService、SCA/SDO): 不同企業之間、跨系統、跨異構環境複用,動态可配置
4. 耦合關系
1) 分布式對象技術将"連接配接邏輯"進行分離
2) 消息中間件将"連接配接邏輯"進行異步處理,增加了更大的靈活性
3) 消息代理和一些分布式對象中間件将資料轉換也進行了分離
4) 而SOA架構,通過服務的封裝,實作了業務邏輯與網絡連接配接、資料轉換等進行完全的解耦
5. 互操作性
在軟體的互操作方面,傳統中間件隻是實作了通路互操作,即通過标準化的API實作了同類系統之間的調用互操作,而連接配接互操作還是依賴于特定的通路協定,如JAVA使用RMI,CORBA使用IIOP等。而SOA通過标準的、支援Internet、與作業系統無關的SOAP協定實作了連接配接互操作。而且,服務的封裝是采用XML協定,具有自解析和自定義的特性,這樣,基于SOA的中間件還可以實作語義互操作
總之,服務化展現的是中間件在完整業務複用、靈活業務組織方面的發展趨勢,其核心目标是提升IT基礎設施的業務靈活性。是以,中間件将成為SOA的主要實作平台
Relevant Link:
http://zh.wikipedia.org/wiki/%E4%B8%AD%E9%97%B4%E4%BB%B6
http://kb.cnblogs.com/page/196448/
http://jm.taobao.org/
2. MetaQ中間件
0x1: MetaQ的應用場景
假設我們有這麼一個應用場景,為了完成一個使用者注冊操作,可能需要将使用者資訊寫入到使用者庫中,然後通知給紅包中心給使用者發新手紅包,然後還需要通知部落格系統給使用者準備對應的部落格賬号,進行合法性驗證,告知SNS系統給使用者導入新的使用者等10步操作。
那麼針對這個場景,一個最簡單的設計方法就是串行的執行整個流程
//全稱串行操作
使用者注冊->通知給紅包中心給使用者發新手紅包->部落格系統給使用者準備對應的部落格賬号->進行合法性驗證->告知SNS系統給使用者導入新的使用者
通過業務分析我們能夠得知,使用者的實際的核心流程其實隻有一個,就是使用者注冊。而後續的準備部落格帳号,通知SNS等操作雖然必須要完成,但卻是不需要讓使用者等待的。
這種模式有個專業的名詞,就叫"最終一緻",即實際上這并不是一個嚴格強制的串行操作,從業務的角度上來說,有很多步驟完全是可以異步完成的,隻要最終的結果是"最終一緻"的就可以
0x2: MetaQ技術原理
METAQ是一款完全的隊列模型消息中間件,伺服器使用Java語言編寫,可在多種軟硬體平台上部署。用戶端支援Java、C++程式設計語言

MetaQ對外提供的是一個隊列服務,内部實作也是完全的隊列模型,這裡的隊列是持久化的磁盤隊列,具有非常高的可靠性,并且充分利用了作業系統cache來提高性能
1. MetaQ是一個隊列模型的消息中間件,具有高性能、高可靠、高實時、分布式特點。
2. Producer、Consumer、隊列都可以分布式。
3. 能夠保證嚴格的消息順序
4. 提供豐富的消息拉取模式
5. 高效的訂閱者水準擴充能力
6. 實時的消息訂閱機制
7. 億級消息堆積能力
MetaQ的存儲結構是根據大規模網際網路應用需求,完全重新設計的一套存儲結構,使用這套存儲結構可以支援上萬的隊列模型,并且可以支援消息查詢、分布式事務、定時隊列等功能
MetaQ内部大部分功能都靠隊列來驅動,那麼必須支援足夠多的隊列,才能更好的滿足業務需求,MetaQ可以在單機支援上萬隊列,這裡的隊列全部為持久化磁盤方式,進而對IO性能提出了挑戰。MetaQ是這樣解決的
1. Message全部寫入到一個獨立的隊列,完全的順序寫
2. Message在檔案的位置資訊寫入到另外的檔案,串行方式寫
通過以上方式,既做到資料可靠,又可以支援更多的隊列
http://blog.csdn.net/blogdevteam/article/details/8449916
https://github.com/killme2008/Metamorphosis/wiki
http://m.bianceng.cn/web/Skills/201407/42090.htm
http://www.bkjia.com/ASPjc/871354.html
3. MetaQ程式設計實踐
消息中間件中有兩個角色: "消息生産者(Producer)"和"消息消費者(Consumer)"。Meta裡同樣有這兩個概念,消息生産者負責建立消息并發送到Meta伺服器(Broker),Meta伺服器會将消息持久化到磁盤,消息消費者從Meta伺服器拉取消息并送出給應用消費
回顧我們之前說的MetaQ的架構圖

要使用MetaQ進行分布式消息通信程式設計學習,就必須要實作最基本的架構搭建
0x1: 配置Zookeeper叢集
MetaQ使用zookeeper釋出和訂閱服務,并預設使用zookeeper存儲消費者offset,是以,你需要首先安裝一個zookeeper到某台機器上,或者使用某個現有的zk叢集
/mate-queue/taobao/metamorphosis-server-wrapper/conf/server.ini
使用内置的zookeeper伺服器進行搭建
[zookeeper]
zk.zkConnect=localhost:2181
zk.zkSessionTimeoutMs=30000
zk.zkConnectionTimeoutMs=30000
zk.zkSyncTimeMs=5000
0x2: 啟動Zookeeper
//停止local模式啟動的broker1,并重新以叢集模式啟動
bin/metaServer.sh start
0x3: 引入MetaQ需要依賴的JAR包
http://fnil.net/downloads/index.html
包括client、server的
0x4: Producer.java
package com.taobao.metamorphosis.example;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.taobao.metamorphosis.Message;
import com.taobao.metamorphosis.client.MessageSessionFactory;
import com.taobao.metamorphosis.client.MetaClientConfig;
import com.taobao.metamorphosis.client.MetaMessageSessionFactory;
import com.taobao.metamorphosis.client.producer.MessageProducer;
import com.taobao.metamorphosis.client.producer.SendResult;
import com.taobao.metamorphosis.utils.ZkUtils.ZKConfig;
public class Producer {
public static void main(String[] args) throws Exception {
final MetaClientConfig metaClientConfig = new MetaClientConfig();
final ZKConfig zkConfig = new ZKConfig();
//設定zookeeper位址
zkConfig.zkConnect = "192.168.207.128:2181";
metaClientConfig.setZkConfig(zkConfig);
// New session factory,強烈建議使用單例
MessageSessionFactory sessionFactory = new MetaMessageSessionFactory(metaClientConfig);
/*
* create producer,強烈建議使用單例
* 消息生産者的接口是MessageProducer,你可以通過它來發送消息
*/
MessageProducer producer = sessionFactory.createProducer();
// publish topic
final String topic = "test";
/*
* 這一步在發送消息前是必須的,你必須釋出你将要發送消息的topic
* 這是為了讓會話工廠幫你去查找接收這些topic的meta伺服器位址并初始化連接配接
* 這個步驟針對每個topic隻需要做一次,多次調用無影響
*/
producer.publish(topic);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = reader.readLine()) != null)
{
/*
* send message
* 在Meta裡,每個消息對象都是Message類的執行個體,Message表示一個消息對象,它包含這麼幾個屬性:
* 1) id: Long型的消息id,消息的唯一id,系統自動産生,使用者無法設定,在發送成功後由伺服器傳回,發送失敗則為0。
* 2) topic: 消息的主題,訂閱者訂閱該主題即可接收發送到該主題下的消息,生産者通過指定釋出的topic查找到需要連接配接的伺服器位址,必須。
* 3) data: 消息的有效載荷,二進制資料,也就是消息内容,meta永遠不會修改消息内容,你發送出去是什麼樣子,接收到就是什麼樣子。消息内容通常限制在1M以内,我的建議是最好不要發送超過上百K的消息,必須。資料是否壓縮也完全取決于使用者。
* 4) attribute: 消息屬性,一個字元串,可選。發送者可設定消息屬性來讓消費者過濾。
*/
SendResult sendResult = producer.sendMessage(new Message(topic, line.getBytes()));
// check result
if (!sendResult.isSuccess())
{
System.err.println("Send message failed,error message:" + sendResult.getErrorMessage());
}
else {
System.out.println("Send message successfully,sent to " + sendResult.getPartition());
}
}
}
}
0x5: AsyncConsumer.java
package com.taobao.metamorphosis.example;
import java.util.concurrent.Executor;
import com.taobao.metamorphosis.Message;
import com.taobao.metamorphosis.client.MessageSessionFactory;
import com.taobao.metamorphosis.client.MetaClientConfig;
import com.taobao.metamorphosis.client.MetaMessageSessionFactory;
import com.taobao.metamorphosis.client.consumer.ConsumerConfig;
import com.taobao.metamorphosis.client.consumer.MessageConsumer;
import com.taobao.metamorphosis.client.consumer.MessageListener;
import com.taobao.metamorphosis.utils.ZkUtils.ZKConfig;
public class AsyncConsumer {
public static void main(String[] args) throws Exception {
final MetaClientConfig metaClientConfig = new MetaClientConfig();
final ZKConfig zkConfig = new ZKConfig();
//設定zookeeper位址
zkConfig.zkConnect = "192.168.207.128:2181";
metaClientConfig.setZkConfig(zkConfig);
// New session factory,強烈建議使用單例
MessageSessionFactory sessionFactory = new MetaMessageSessionFactory(metaClientConfig);
// subscribed topic
final String topic = "test";
// consumer group
final String group = "meta-example";
/*
* create consumer,強烈建議使用單例
* 通過createConsumer方法來建立MessageConsumer,注意到我們傳入一個ConsumerConfig參數,
* 這是消費者的配置對象。每個消息者都必須有一個ConsumerConfig配置對象,
* 我們這裡隻設定了group屬性,這是消費者的分組名稱。
* Meta的Producer、Consumer和Broker都可以為叢集。
* 消費者可以組成一個叢集共同消費同一個topic,發往這個topic的消息将按照一定的負載均衡規則發送給叢集裡的一台機器。
* 同一個消費者叢集必須擁有同一個分組名稱,也就是同一個group。我們這裡将分組名稱設定為meta-example
*/
MessageConsumer consumer = sessionFactory.createConsumer(new ConsumerConfig(group));
/*
* subscribe topic
* 訂閱消息通過subscribe方法,這個方法接受三個參數
* 1) topic,訂閱的主題
* 2) maxSize,因為meta是一個消費者主動拉取的模型,這個參數規定每次拉取的最大資料量,機關為位元組,這裡設定為1M,預設最大為1M。
* 3) MessageListener,消息監聽器,負責消息消息。
*/
consumer.subscribe(topic, 1024 * 1024, new MessageListener() {
public void recieveMessages(Message message) {
System.out.println("Receive message " + new String(message.getData()));
}
public Executor getExecutor() {
// Thread pool to process messages,maybe null.
return null;
}
});
// complete subscribe
consumer.completeSubscribe();
}
}
https://github.com/killme2008/Metamorphosis/wiki/%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B
http://www.it165.net/admin/html/201402/2409.html
Copyright (c) 2014 LittleHann All rights reserved