【G】開源的分散式部署解決方案(一) - 開篇

来源:http://www.cnblogs.com/doddgu/archive/2017/01/23/g_1.html
-Advertisement-
Play Games

從功能上來說,請參考 預告篇,因自知當時預告篇沒有任何含金量,所以並沒有主動推送到首頁,而是私下的給一些人發的。 從個人角度上來說,我希望.net的環境會越來越好,就我自己的成長曲線是從mxdn開始自學、cxdn嘗試解答問題、博客園讀別人博客再到自己寫博客、最後到工作中經常使用到的stackxxxx ...


做這個開源項目的意義是什麼?(口水自問自答,不喜可略過)

從功能上來說,請參考 預告篇,因自知當時預告篇沒有任何含金量,所以並沒有主動推送到首頁,而是私下的給一些人發的。

從個人角度上來說,我希望.net的環境會越來越好,就我自己的成長曲線是從mxdn開始自學、cxdn嘗試解答問題、博客園讀別人博客再到自己寫博客、最後到工作中經常使用到的stackxxxxflow、gxxgle。這其中我當然是走了很多彎路,踩過無數的坑,也埋了無數的坑。現在自己有了一點小小的能力,想盡自己所能,通過一個項目整理出來給大家參考、學習的同時也能給自己一些意見。對新人來說也算是一種回饋,對老人來說也算是互相切磋互相提升。

 

什麼是分散式部署解決方案?

部署也有很多人叫發佈。那正常的流程是什麼樣的呢?

 

相信這張圖大家都不會太陌生。一般少數幾台伺服器的時候直接這樣發佈是最省時省力的。

但是,如果有一天,你的伺服器變成幾十臺,然後又面臨著經常發佈的情況該怎麼辦呢?

@echo off
echo Start to Publish ApplicationName All Site
set local="C:\inetpub\ApplicationName"
Set RemotePath=C$\inetpub\ApplicationName

For %%I in (192.168.0.2 192.168.0.3 ... 192.168.0.n) do (
echo "Publish ApplicationName %%I"
net use \\%%I\ipc$ Password /User:UserName
For %%P in (default) do (
echo "Publish \\%%I\%RemotePath%\"dd
xcopy /e /y %local% "\\%%I\%RemotePath%\"
)
net use \\%%I\ipc$ /del
)

:End
pause;

上面這段代碼,相信也有一部分人用過吧。使用流程也比較簡單,先用vs發佈到本地,然後再使用批處理文件,通過發佈命令來進行多台網站的部署。

 

突然有一天,你是上司跟你說,你的這段批處理有很多問題,比如不利於維護、沒有部署記錄、發佈後首次訪問很慢、沒有版本管理、部署過程一旦發生異常也沒有容錯機制等等。

是的,這些問題都還是基礎的。如果你的伺服器數量達到一定級別以後,你的部署會變得異常艱難。某台伺服器上部署了多少個服務、某幾台伺服器是一組,這些會讓你抓狂,甚至想說髒話,就如同下圖。

由於後面還會有一系列文章要出,此處就不再過多的解釋,當你看到完整的項目之後,相信你會對它有一個新的認識。

 

第一個正式版包含哪些功能?

請允許我偷個懶,從預告篇把尚不成熟的功能列表copy一份過來:

 

1 基礎的許可權控制(可能只支持一個角色,甚至是寫死)

2 部署項目管理(以Jenkins為例,做自動化構建方案)

3 部署伺服器管理(以Aliyun伺服器為例)

4 部署組管理(包括部署組、部署組項)

5 創建部署任務(包括觸發自動化構建、部署文件關聯等)

6 部署伺服器常駐服務(以Windows Service的形式駐留,主要完成中控的指令協助部署)

7 一鍵部署(支持單台或部署組)

  7.1 支持手動綁定歷史部署文件版本(理論上支持所有的,如Jenkins這種構建方案還會涉及到保存構建副本數量和天數等,另本功能只支持單台部署,部署組的修改版本通過創建部署任務時統一指定)

  7.2 自動檢測部署文件包狀態(以Jenkins為例,會自動等待構建完畢,並會自行檢測構建狀態判斷是否繼續向下執行)

  7.3 下載部署文件包並解壓

  7.4 控制負載均衡降權

  7.5 部署(包括等待伺服器正在執行的請求完成的檢測)

  7.6 觸發緩存(也可以理解為觸發首次訪問,提升用戶體驗)

  7.7 控制負載均衡升權

 

PS:其中為了支持單台伺服器部署,所以一些擴展性功能會採用插件(暫定)的形式允許自行實現,同時也會包含一套以阿裡雲、jenkisn為基礎的示例實現。

後續也會考慮把一些功能提取出來做成API,允許把功能嵌入到自己的系統里去。當然,這個要看有多少人需要了。

 

核心技術與開發工具

後端:.net 4.6.1,EF6,mvc5(不上.net core的原因是1.1.0目前並不穩定,還是有不少bug,我真的親身踩到了,實在是不想無限踩過去,請原諒我沒有勇於踩坑的心,確確實實是精力有限)

前端:AdminLTE 2 支持PC、Mobile雙端

資料庫:SQL Server LocalDB

IDE:Visual Studio 2017 RC

源碼托管:oschina git

 

現在做到哪一步了?

先上一張解決方案資源管理器的截圖,簡單的看下項目結構。

可以看到,目前只有一個項目,而且比較亂,Business、Data、Models 各種亂入。

這麼低級的一個項目怎麼好意思開源的?

是的,沒錯,目前項目狀態就是這樣。

因為我要做的不是發佈出來一個成品,寫個介紹就完了。

我會從0代碼開始在git上保留整個過程。且根據進度不定期更新博文來講解編碼過程中的各種問題以及解決思路。

而下一篇的名字我也已經想好了。

【G】開源的分散式部署解決方案(二) -  好項目是從爛項目基礎上重構出來的

在我的這個開源系列博客中,你可以看到一個開源項目的完整成長歷程。我不知道這個項目會走多遠,但我堅信這個項目一定會幫到一部分人,這就足夠了。

下麵放幾張截圖,也是下一篇內容的主角。

(簡單的登錄頁)

(後臺UI的基礎框架)

(已完成的一個功能,部署伺服器管理)

(支持手機端的table)

 

登錄的實現

為了避免太水的嫌疑,上一點點乾貨。

新建項目時,點擊Change Authentication會看到4個選項。至於如何選擇我就不多說了,我先說說我選了 Identity(Individual User Accounts)踩過的坑。

因為我之前主要是做架構方向的,可以理解為這些都是所謂的“小弟”在做的功能,而我一個不小心就掉進了陷阱里去。說是陷阱吧,其實主要是因為自己不熟悉,畢竟mvc還是比較龐大的,即便你順著它的思路去做,也未必能做得對。

預設情況下生成好的項目是已經使用推薦的EF6實現了整個登錄流程。而我又希望自己可以掌控關鍵的驗證邏輯,所以一路摸下去把 ApplicationUser、AppplicationUserManager、UserManager、UserStore都看了一遍,經過各種嘗試,發現驗證邏輯封裝在Microsoft.AspNet.Identity.EntityFramework(這個是盲打的,已經回不去了,如果錯了歡迎指正)。

找到了目標當然第一想法是功課他,隨著不斷的踩坑發現工作量異常的大,遂放棄。想從另外一個角度入手,因為UserManager才是核心,那我順著這條線是否可以把他已經實現的EF那套開給剔除掉。

於是就有了下麵的代碼:

首先要改造Model,於是自己把 ApplicationUser、IdentityUser、UserStore都重寫了。前面兩個比較簡單,重點是UserStore,要實現IUserStore<TUser>這個介面,這裡是自行編寫驗證邏輯的轉折點。

其次,Controller也進行的小改造,去掉了SignInManager等,只保留了UserManager,同時Startup.Auth裡面的DbContext也換成了自己的。

最後把Name也一同存入了Cookie,方便layout裡面要顯示用戶名。

 

核心代碼如下:

1.IdentityUser 其實這個類可以跟 ApplicationUser合併的,我也是跟官方生成項目時的寫法保留下來的。可能故意分開在ApplicationUser裡面寫的是邏輯,而IdentityUser是對屬性的定義,這樣會顯得更清晰一點吧,雖然我也會這麼做,也很熱衷於這麼做,但區別是我不會讓ApplicationUser繼承IdentityUser,而是寫一個Business來實現方法做一個徹底的拆分。

    public class IdentityUser : IUser<string>
    {
        public string Id { get; set; }

        public string Name { get; set; }

        public string Password { get; set; }

        public string Role { get; set; }

        public string UserName { get; set; }
    }

2.UserStore其實並沒有多少借鑒的意義,因為這是很小學生的寫法了,主要是為了突出UserStore的重要性。

    public class UserStore : IUserStore<ApplicationUser>
    {
        public async Task CreateAsync(ApplicationUser user)
        {
            using (var dbContext = GDbContext.Create())
            {
                dbContext.User.Add(new User()
                {
                    UserName = user.UserName,
                    Password = user.Password,
                    Name = user.Name,
                    Role = user.Role,
                });

                await dbContext.SaveChangesAsync();
            }
        }

        public Task DeleteAsync(ApplicationUser user)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            //nothing to do
        }

        public Task<ApplicationUser> FindByIdAsync(string userId)
        {
            int id = 0;
            if (!Int32.TryParse(userId, out id))
            {
                throw new ArgumentException(nameof(userId));
            }

            using (var dbContext = GDbContext.Create())
            {
                var user = dbContext.User.SingleOrDefault(u => u.ID == id && !u.IsDelete);

                return Task.FromResult(new ApplicationUser()
                {
                    Id = user.ID.ToString(),
                    Name = user.Name,
                    Password = user.Password,
                    Role = user.Role,
                    UserName = user.UserName
                });
            }
        }

        public Task<ApplicationUser> FindByNameAsync(string userName)
        {
            using (var dbContext = GDbContext.Create())
            {
                var user = dbContext.User.SingleOrDefault(u => u.UserName == userName && !u.IsDelete);

                return Task.FromResult(new ApplicationUser()
                {
                    Id = user.ID.ToString(),
                    Name = user.Name,
                    Password = user.Password,
                    Role = user.Role,
                    UserName = user.UserName
                });
            }
        }

        public Task UpdateAsync(ApplicationUser user)
        {
            throw new NotImplementedException();
        }
    }

 

 3.Startup.Auth ConfigureAuth方法進行瞭如下的改動,主要是修改 DbContext 的獲取,以及SecurityStampValidator.OnvalidateIdentity這個方法的參數調整。

           // 配置資料庫上下文、用戶管理器和登錄管理器,以便為每個請求使用單個實例
            app.CreatePerOwinContext(GDbContext.Create);
            app.CreatePerOwinContext(() => new UserManager<ApplicationUser>(new UserStore()));

            // 使應用程式可以使用 Cookie 來存儲已登錄用戶的信息
            // 並使用 Cookie 來臨時存儲有關使用第三方登錄提供程式登錄的用戶的信息
            // 配置登錄 Cookie
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // 當用戶登錄時使應用程式可以驗證安全戳。
                    // 這是一項安全功能,當你更改密碼或者向帳戶添加外部登錄名時,將使用此功能。
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager<ApplicationUser>, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });            

 

說起來簡單,但真的做起來還是踩過了大大小小的坑,即便是你覺得很不起眼的一個功能,都有可能折騰的你要死要活。

我會告訴你我新建項目、刪除項目、再新建、再刪除,這個過程已經重覆好多遍了嗎?

當你看到一段好的代碼在你面前時,又有幾個人能體會寫的人死了多少腦細胞?

我不會拒絕伸手黨,但我希望伸手的同時能再點個贊,你的支持是無數同行堅持在這條路上的動力。

 

聲明

1.在出第一個正式版之前不會使用任何開源協議

2.永遠免費,不會出什麼專業版、旗艦版之類的進行收費

3.第一個版本完結時間目前還不知道,我這個人懶散慣了,但我會儘量多抽出一些時間儘快寫出來。

 

最後,本項目暫定名為 G,唯一群號:7424099

Git地址:http://git.oschina.net/doddgu/G   (希望大家可以順手點個star,如果有喜歡的朋友捐贈下就更好了,感謝各位的支持)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 3. 添加一個視圖 · 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-view · 譯文地址:http://www.cnblogs.com/powertoolsteam/ar ...
  • 2. 添加一個控制器 · 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-controller · 譯文地址:http://www.cnblogs.com/powertools ...
  • 1.平臺互操作性和不安全的代碼:C#功能強大,但有些時候,它的表現仍然有些“力不從心”,所以我們只能摒棄它所提供的所有安全性,轉而退回到記憶體地址和指針的世界。 C#通過3種方式對此提供支持。 (1)第一種方式是通過平臺調用(Platform Invoke,P/Invoke)來調用非托管代碼DLL所公 ...
  • Socket裡面的協議解析是Socket通訊程式設計中最複雜的地方,如果你的應用層協議設計或實現不佳,Socket通訊中常見的粘包,分包就難以避免。SuperSocket內置了命令行格式的協議CommandLineProtocol,如果你使用了其它格式的協議,就必須自行實現自定義協議CustomPr ...
  • 1.在多個線程的同步數據中,避免使用this、typeof(type)、string進行同步鎖,使用這3個容易造成死鎖。 2.使用Interlocked類:我們一般使用的互斥鎖定模式(同步數據)為Lock關鍵字(即Monitor類),這個同步屬於代價非常高的一種操作。除了使用Monitor之外,還有 ...
  • 1.Task概述:Task是對操作系統線程的抽象,目的是使線程池能高效地管理線程的分配和回收,Task使用的底層線程屬於一種共用資源,任務需要互相協作,並及時歸還線程,以便用相同的共用資源(線程)滿足其他請求。 2.Task.AsyncState:獲取在創建 Task 時提供的狀態對象,如果未提供, ...
  • 1.List.BinarySearch():BinarySearch()採用的是二分搜索演算法,要求元素已經排好序,其特點是假如元素沒有找到,會返回一個負整數,該值的按位取反(~)結果是“大於被查找元素的下一個元素”的索引,如果沒有更大的值,則是元素的總數。這樣一來就可以在列表中的特定位置方便地插入新 ...
  • 1.在使用反射時,反射可以繞過安全訪問級別(private、protected)修飾的類或屬性,來獲取需要的信息。 2.泛型的反射:可以使用Type.ContainsGenericParameters這個屬性來判斷一個類或方法是否包含尚未設置的泛型實參,Type.IsGenericType屬性表示是 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...