項目演化系列--開啓分佈式(分離數據層)

前言html

  本來上一篇是打算寫分離數據層的,可是在思考的過程中發現分離數據層的時候,有一些操做是要依賴分佈式鎖的,所以先寫了分佈式鎖。web

  對於有些項目的數據層提供的是業務接口的(返回業務所需的數據),那麼當數據層壓力逐漸增大的時候,如須要使用緩存的時候,就須要開發人員去修改相應的數據接口使其使用緩存,緩存和各類數據查詢接口交錯在一塊兒,整個數據層的代碼變得很是混亂,連重構都沒法進行,只能推倒重作。因此不少的文章中,在講解數據層的時候,都是使用統一的數據接口,如:Find、Add、Save等,那麼當須要緩存的時候,就能夠在Find中直接擴展使其支持緩存,甚至能夠引入緩存配置管理,對於不一樣的表之間進行可調度的緩存週期管理,使開發人員不須要知道緩存的存在,他們仍是使用原先的Find,可是速度卻更快了,又或者冷熱數據管理、搜索引擎等,這即是大神們在通過多年開發總結下來的經驗。數據庫

  將數據層從項目中分離出來成爲一個獨立的項目,並將其發佈於獨立的服務器,相對於單機系統而言,有以下幾個優勢:緩存

  一、便於整合各方資源服務器

  二、下降成本網絡

  三、每一個層的性能更加優秀且可伸縮性強,在不斷增長的負荷下,能夠便利的增長節點數量。mvc

  四、某些次服務層出現錯誤的時候,不會致使項目的總體癱瘓。app

  五、不一樣層次可用不一樣語言實現框架

  有優勢就有缺點,最大的缺點就是較單機系統而言,分佈式系統更加複雜,不只系統自己結構會變得複雜,不一樣組件間的網絡會引入影響因素,調試困難等等。socket

  雖然有很多的缺點,可是不去實踐是不會發現另外一番天地的,不去挑戰看看永遠都只是侷限在單機系統上,也不用懼怕會遇到哪些問題,畢竟只有發現問題以後,才能想辦法解決,這是從書上沒法學習到的,那麼咱們就開始今天的文章吧。

基礎CRUD

  數據層是提供於數據庫進行操做的中間件,最基礎的功能就是CRUD,單機系統當中,調用CRUD接口的時候,要麼經過拼接SQL要麼經過ORM直接鏈接數據庫,而因爲如今是分佈式的,所以原先的調用方式就須要經過通訊協議來實現了,假設原先的接口爲:

public class DbResult
{
    public bool Error { get; set; }

    public object Data { get; set; }
}

public interface IDb
{
    DbResult Find(Dictionary<string, object> query);

    DbResult Add(object entity);

    DbResult Save(object entity);

    DbResult Remove(object entity);
}

  數據層那端的Find是以Query Object模式實現的,具體的格式能夠查看此文章--《Query Object--查詢對象模式(上)》、《Query Object--查詢對象模式(下)》。

  這裏的數據層項目,若是使用原先抽取的mvcHandler方式來實現,那麼IService的派生類就須要使用HttpWebRequest來實現了,大體的實現思路就是將相應的方法最後轉換成調用數據服務,Find實現代碼以下:

public DbResult Find(Dictionary<string, object> query)
{
    var url = string.Format("{0}/{1}/{2}", ConnectionUri, this.table, "find");
    var req = (HttpWebRequest)HttpWebRequest.Create(url);
    req.Method = "Post";
    req.Accept = "text/plain, */*; q=0.01";
    req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
    req.Timeout = 1000 * 30;
    req.KeepAlive = true;
    try
    {
        byte[] bytes = Encoding.UTF8.GetBytes(
            JsonConvert.SerializeObject(query));
        req.ContentLength = bytes.Length;
        using (var reqStream = req.GetRequestStream())
        {
            Stream requestStream = req.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
        }

        var res = new DbResult();
        using (var resp = (HttpWebResponse)req.GetResponse())
        {
            using (var respStream = resp.GetResponseStream())
            {
                using (var reader = new StreamReader(respStream, Encoding.UTF8))
                {
                    string respContent = reader.ReadToEnd();
                    return JsonConvert.DeserializeObject(respContent);
                }
            }
        }
    }
    catch
    {
        return new DbResult { Error = true };
    }
}

事務

  有了基礎的CRUD之後,接下來就要實現事務了,若是參考單機系統來實現事務的話,那麼開啓事務之後,若是業務層出現問題致使主機重啓或宕機,那麼數據層的事務將會沒法關閉,從而引起問題。

  所以須要使用其餘的方式來實現,觀察事務能夠得出從事務開啓到提交是一個總體,只有事務提交的時候才須要有狀態來斷定事務的執行狀況,而事務開啓時並能夠不須要有執行結果的斷定,所以能夠將事務當作一個隊列,而中間的每個CUD操做能夠當作是它的元素,而每個操做須要知道對應的是哪一個表、執行哪一個操做以及相應的表數據便可,代碼實現以下:

public class TransactionAction
{
    public string Table { get; set; }

    public string Name { get; set; }

    public object Data { get; set; }
}

//IDb
public interface IDb
{
    //其餘省略

    void BeginTx();

    DbResult CommitTx();
}

//IDb實現
private List actions;

public void BeginTx()
{
    this.actions = new List();
}

public DbResult CommitTx()
{
    //http訪問數據層並設置actions爲null
}

public DbResult Add(object entity)
{
    if (this.actions != null)
    {
        this.actions.Add(new TransactionAction
        {
            Name = "add",
            Table = this.table,
            Data = entity
        });
    }
    else
    {
        //單個增長
    }
}

結束語

  到這裏數據層的分離基本上就完成了,若是想要更高效的數據獲取,能夠將訪問方式修改爲socket,之因此不直接使用WPF或者webService是由於這都是基於C#來開發的,並且若是直接使用現成的框架來用的話,能學到的東西就很少了。

  就到這裏了,若是有什麼問題或者錯誤的話,請給我留言,謝謝。

相關文章
相關標籤/搜索