說說面向服務的體系架構SOA


序言

在.Net的世界中,一提及SOA,大家想到的應該是Web Service,WCF,還有人或許也會在.NET MVC中的Web API上做上標記,然后泛泛其談!

的確,微軟的這些技術也確實推動着面向服務的世界發展,當然除了微軟還有很多面向服務的開源技術,甚至在某些方面比微軟做的更加優秀。那么什么是面向服務,面向服務的存在是為了解決什么問題呢?

說說SOA面向服務

SOA是由Garnter在1996年提出的一個概念,旨在讓軟件變的有彈性,能夠迅速響應業務的需求,實現實時企業。基本理念是讓所有信息系統中需要整合的業務使用服務和接口聯系起來,接口中立,與開發平台和編程語言無關。這也使得異構信息系統變的可開發,“信息孤島”,重復造輪子等問題在SOA的體系架構下不攻自破。

簡單通俗的說就是,SOA是不同業務建立不同的服務,服務之間的可以數據交互粗粒度的服務接口分級,這樣松散耦合提高服務的重用性,也讓業務邏輯變的可組合,並且每個服務可以根據使用情況做出合理的分布式部署,從而讓服務變的規范,高性能,高可用。

那么接下來我們首先來看下微軟在這方面做啦哪些貢獻,以及軟件開發是怎樣的一個變化歷程。

代碼復用技術的發展

面向過程(應用內/過程級復用)---->面向對象(應用內/類級復用)--->面向組件(應用內/組件級復用)--->分布式組件(應用間/組件級復用)---->面向服務(應用間/服務級復用)

微軟面向服務提供的技術

那么針對上面的一張圖,做一個簡短的說明,首先是Tcp與Http協議的比較,這兩個協議各有所長:

基於TCP協議:能夠減少網絡傳輸字節數,降低網路開銷,效率高,但是實現復雜,且由於協議和標准不同,難以進行跨平台,和企業間的便捷通信,並且當服務越來越多的時候,負載聚恆策略,服務地址管理和配置都會變得復雜和繁瑣,目前也沒有很好的開源支持。

基於Http協議:那么他相對於Tcp來說,首先他是構建在Tcp/Ip協議之上,效率相對於tcp要低,傳輸字節也要比tcp多,所以他傳輸占用的時間會長,當然我們也能使用一些gzip數據壓縮等對數據壓縮或者類似於Hessain,Thrift等等傳輸2進制數據流,減少數據傳輸量縮減與TCP的差距,當然HTTP也是有很多自己的優點,比如他的存在天生就可以解決異構調用的問題,還有處理處理大流量高並發的情況下很多成熟開源的解決方案想iis,nginx,tomcat,apache等。

所以對上面兩種協議的對比,各有所長各有其短,大家各取所需就好啦。

各種數據序列化對比

數據傳輸協議的取舍,也是根據自己的需求,在.net的世界中我認為應該json跟xml應該是被大家廣泛使用的。那么還有那些對象序列化常見於網絡傳輸呢,Hessian,thrift也是比較常用的。網上也有很多對比,我從網上拿下來的就有,其實如下圖,僅供參考。

.Net使用Hessian進行序列化,實現基於Http協議的RPC

針對上述的測試圖,我們可以看出Hessian也是一個不錯的選擇,那么在這里我來寫一個.Net mvc中使用hessian的小例子,供大家學習參考,也體驗下RPC風格的Hessian有多便捷。

同時hessian也支持N多語言,他采用二進制格式傳輸的服務框架,據測試效率是soap傳輸的10倍。所以更輕量快速,官網地址:http://hessian.caucho.com/

那么我們摒棄類微軟的webservice,wcf,webapi等框架,使用啦開源的hessian,來實施服務之間的遠程調用。

1、服務端

引用Hessiancsharp.dll

實現類繼承CHessianHandler類,引用命名空間using hessiancsharp.server,同時實現Iserverice接口,Iservice是對外提供的。

 public class Service : CHessianHandler, IService
    {
        private readonly string _connStr = ConfigurationManager.ConnectionStrings["ConnectionString_write"].ConnectionString;

        #region IService 成員

        public string ServerName { get { return ConfigurationManager.AppSettings["ServerName"]; } }
        public List<D_DriverInfo> GetDriverInfo()
        {
            try
            {
                using (DbConnection conn = new SqlConnection(_connStr))
                {
                    conn.Open();
                    string sql = "SELECT TOP 10 * FROM dbo.D_DriverInfo";

                    return conn.Query<D_DriverInfo>(sql).ToList();
                }
            }
            catch (Exception ex)
            {
                return null;
            }

        }

        public D_DriverInfo GetDriverInfoByUcode(string ucode)
        {
            try
            {
                using (DbConnection conn = new SqlConnection(_connStr))
                {
                    conn.Open();
                    string sql = "SELECT * FROM dbo.D_DriverInfo where Ucode = @Ucode";

                    return conn.QuerySingle<D_DriverInfo>(sql, new { Ucode = ucode });
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        #endregion
    }
View Code
 public interface IService
    {
        string ServerName { get;  }
        List<D_DriverInfo> GetDriverInfo();
        D_DriverInfo GetDriverInfoByUcode(string ucode);
    }
 <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <httpHandlers>
      <add verb="*" path="HessianServiceMvc.IService.hessian" type="HessianServiceMvc.Service, HessianServiceMvc" />
    </httpHandlers>
  </system.web>
   <system.webServer>
        <handlers>        
            <add name="MvcHessianService" path="*.hessian" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
        </handlers>
    </system.webServer>
public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{hessian}.hessian/{*pathInfo}");
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }      

2、客戶端使用服務

引用Hessiancsharp.dll,把服務端的接口寫下來,不用實現,遠程用服務實現服務調用方的方法。

            CHessianProxyFactory factory = new CHessianProxyFactory();
            string url = "http://172.18.5.61:9020/HessianService.hessian";//修改為你的server端地址
            IService test = (IService)factory.Create(typeof(IService), url);
            object result = test.GetDriverInfo();
            List<D_DriverInfo> s = HClient.RunClient<IService>().GetDriverInfo();
            return Json(s, JsonRequestBehavior.AllowGet);

Note,不妨試試,感受下使用起來方便快捷不?

說說服務路由,服務負載均衡與服務去中心化結構

首先如果你的業務量不是很大,服務都是單台部署,那么你的服務地址可以硬編碼到你的項目中,但是如果你的服務單台扛不住流量並發甚至性能特別差,那么我們就需要分布式部署我們的服務。

最初我們是這樣子實現的

不論你走的是老式的Esb,還是一些代理服務器,都是先把請求打到另外一台服務器,然后給你轉接給服務提供方。

現在我們是怎么實現的呢

Note:Soa架構會提供一個Client.dll,給到調用方,讓調用方不必關系你的傳輸協議怎么實現,負載算法怎么實現,這都可以配置出來。然后服務每上線一台機器,都會自動注冊接口地址等信息到服務配置中心,服務監測系統也會及時的捕捉到各個服務的上下線狀態,然后更新存儲起來,Client內置有負載均衡及緩存功能,根據監測系統提供的數據,客戶端配置的信息,自己發現最優的服務給到客戶端。然而這一切都放生在客戶端。沒有第三方代理服務器出現。

由上述兩張圖片,也可以得出一個信息,我們先假定使用圖一,如果代理服務器或是請求路由分發器之類的東西掛了,那所有的服務就不能用啦,還有中間轉接一次,性能也不如第二種好,第二種沒有中心化結構,我感覺還是挺叼的,不寫了,這篇就到這里吧。

總結

比較淺,也比較籠統,如果有什么不妥之處,還望提出,同時也歡迎加入左上方群,我們一起交流學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM