1. [Tips] 用 “磁碟鏡像" 無痛更換硬碟

    老是寫一堆像外星文,沒人看的懂的 multi-threading 文章,偶爾也來換換口味吧。前陣子把 SERVER 的兩顆 750GB HDD (RAID1) 升級了一下,升級成兩顆 1.5TB HDD (RAID1)。更換硬碟是小事,不過這個硬碟上有些服務,如網站,資料庫,還有一些重要資料,跟分享資料夾,想一想要更換也是挺囉唆的...。

    想了幾個辦法,不過都不符合我既懶又挑毛病的個性... 原本考慮的更換方式有:

    1. 硬上... 新硬碟裝上去,檔案COPY過去,能停的服務就停掉,花一堆時間搬資料,然後再恢復原服務 (如 SQL、IIS等等)。至於比較麻煩的,像是目錄分享的,只好移掉再重建。中斷服務的時間就是從關機裝硬碟,一直到全部完成為止。
    2. 用 disk clone 的工具,如 true image / ghost 之類的軟體。不過這樣通常得停機做 clone, 750GB 也是要執行好一段時間,加上我這次買的是 Advanced Format 的硬碟,用這類工具會有效能的問題,事後還得校正回來… ouch, 算了...

    想來想去,我用的是 windows server, 有內建的 Mirror set, 就拿來用一用好了。我真正作的是把 mirror set 的兩顆都升級,不過為了簡化說明,我底下的例子就只以替換一般的硬碟就好,反正道理是一樣的。

    說穿了不值錢,就是用 mirror 的磁碟複製特性,加上 extend volume 的功能,我除了需要關機裝上新硬碟之外,其它包含資料複製的所有時間,原服務都不用中斷 (當然速度會慢一點),所有服務的設定也都不用修改,算是既無腦又防呆的完美方案... 只要簡單的按幾下滑鼠就可以達成我的目標。

     

    直接來看看怎麼作的吧! 很簡單,先利用 mirror 把資料轉移到新硬碟... 然後中斷 mirror, 再用 extend volume 把磁區大小調大就可以收工了。來看分解步驟:

     

    1. 我原本的磁碟組態是長這個樣子 (圖我是事後用 VM 模擬的),其中 Disk 1 (8.00GB) 就是我要換掉的...
      image 


    2. 關機裝上一顆新的硬碟 Disk 2 之後,變成這樣 (Disk 2 (16.00GB) 是新的硬碟):
      image


    3. 把 disk1 / disk2 做成磁碟鏡像之後,就變成這樣:
       image


    4. 鏡像做好,Resync 完成後,就可以中斷鏡像了。中斷之後變成這個樣子:
      image 


    5. 目前為止,看來磁碟轉移已經完成了,剩下就是想辦法把後面的空間吃進來。接下來的就用 Extend Volume 括大 D: 的大小:
      image 
      image

     

    之後就大功告成了。這方法不但簡單,而且整個過程中,全程 D:\ 都可以正常的使用。除了 (1) --> (2) 需要關機裝硬碟之外, (2) ~ (5) 全程,放在 D:\ 的 SQL DB,IIS 網站,還有 pagefile 通通都正常運作中。有了 windows server 的磁碟陣列還真是好用啊 :D

    不過,事情也是有黑暗面的... 這個方法是有幾個小缺點啦...

    1. 被迫使用 "動態磁碟" :
      dynamic disk 其實不是什麼缺點啦,不過你要是會用到其它 OS,像 linux 之類的,或是用其它的磁碟管理軟體,可能就不認得了。這是缺點之一..
    2. 只有 windows server 可以使用:
      desktop os (windows 2000 pro, xp, vista, win7) 都只支援部份的磁碟管理功能,這作法關鍵的 mirror 是不支援的... 只能乾瞪眼 @@
    3. Extend Volume 只適用 windows 2008 以上的版本:
      記得 windows 2003 只支援到 span volume, 在 disk manager 裡還是會顯示兩個 partition, 只不過只會有一個磁碟機代號,容量會是兩個加起來的而已。一樣啦,是不會有什麼大問題,看起來不大爽而已 XD

    偶爾換個口味,貼些小品文章,這邊我也不是很專業,有啥更好的作法也歡迎留 comment 啊 :D

    2010/03/06 Tips 技術隨筆 敗家 有的沒的

  2. 升級到 BlogEngine.NET 1.6.0.0 了!

    1.6.0.0 出來一陣子了,不過到過年才有空升級... 主要的原因只有一個,就是最近 spam comments 實在太多了 =_=,新版對於這類問題的處理比較像樣一點..

    其它改進還有 nested comments 跟其它一堆改進,就不一一列出來了,有興趣的人可到官方網站去看看。

    試了一下,升級後沒啥大問題,除了 CSS 有點走樣之外... 如果各位有發現什麼地方漏掉了,請再通知我 :D

    祝大家新年快樂 :D

    2010/02/19 BlogEngine.NET 有的沒的

  3. [設計案例] 清除Cache物件 #2. Create Custom CacheDependency

    上一篇廢話了這麼多,其實重點只有一個,我這次打算利用 CacheDependency 的機制,只要一聲令下,我想移除的 cache item 就會因為 CacheDependency 的關係自動失效,而不用很辛苦的拿著 cache key 一個一個移除。 我的想法是用 tags 的概念,建立起一套靠某個 tag 就能對應到一組 cache item,然後將它移除。開始之前先來想像一下 code 寫好長什麼樣子:

    透過 tags 來控制 cache items 的範例程式[copy code]
            static void Main(string[] args)
            {
                string[] urls = new string[] {
                    "http://columns.chicken-house.net/",
                    // 共 50 組網址... 略
                };
    
                foreach (string url in urls)
                {
                    DownloadData(new Uri(url));
                }
    
                Console.ReadLine();
                TaggingCacheDependency.DependencyDispose("funp.com");
                Console.ReadLine();
            }
    
            private static void Info(string key, object value, CacheItemRemovedReason reason)
            {
                    Console.WriteLine("Remove: {0}", key);
            }
    
            private static byte[] DownloadData(Uri sourceURL)
            {
                byte[] buffer = (byte[])HttpRuntime.Cache[sourceURL.ToString()];
    
                if (buffer == null)
                {
                    // 直接到指定網址下載。略...
                    buffer = null;
    
                    HttpRuntime.Cache.Add(
                        sourceURL.ToString(),
                        buffer,
                        new TaggingCacheDependency(sourceURL.Host, sourceURL.Scheme),
                        Cache.NoAbsoluteExpiration,
                        TimeSpan.FromSeconds(600),
                        CacheItemPriority.NotRemovable,
                        Info);
                }
    
                return buffer;
            }
        }
    
        這段 sample code 做的事很簡單,程式準備了 50 個網址清單,用 for-loop 一個一個下載。下載的 method: DownloadData(Uri sourceURL) 會先檢查 cache 是否已經有資料,沒有才真正下載 (不過下載的細節不是本篇要講的,所以就直接略過了...)。 而主程式的最後一行,則是想要把指定網站 ( funp.com ) 下載的所有資料,都從 cache 移除。為了方便觀看程式結果,我特地加上了 callback method, 當 cache item 被移除時, 會在畫面顯示資訊: image 由執行結果來看,果然被移出 cache 的都是來在 funp.com 的網址... 接著來看看程式碼中出現的 TaggingCacheDependecny 是怎麼實作的。相關的 code 如下:
    TaggingCacheDependency 的實作 [copy code]
        public class TaggingCacheDependency : CacheDependency
        {
            private static Dictionary<string, List<TaggingCacheDependency>> _lists = new Dictionary<string, List<TaggingCacheDependency>>();
    
            public TaggingCacheDependency(params string[] tags)
            {
                foreach (string tag in tags)
                {
                    if (_lists.ContainsKey(tag) == false)
                    {
                        _lists.Add(tag, new List<TaggingCacheDependency>());
                    }
                    _lists[tag].Add(this);
                }
                this.SetUtcLastModified(DateTime.MinValue);
                this.FinishInit();
            }
    
            public static void DependencyDispose(string tag)
            {
                if (_lists.ContainsKey(tag) == true)
                {
                    foreach (TaggingCacheDependency tcd in _lists[tag])
                    {
                        tcd.NotifyDependencyChanged(null, EventArgs.Empty);
                    }
                    _lists[tag].Clear();
                    _lists.Remove(tag);
                }
            }
        }
      30行不到... 其實程式很簡單,TaggingCacheDependency 繼承自 CacheDependency, 額外宣告一個靜態的 Dictionary<string, List<TaggingCacheDependency>> 來處理各個標簽及 TaggingCacheDependency 的關係,剩下的就沒什麼了。呼叫 DependencyDispose( ) 就可以通知 .NET Cache 機制,將相關的 cache item 移除。 用法很簡單,當你要把任何物件放進 cache 時,只要用 TaggingCacheDependency 物件來標示它的 tag:
    把物件加進 Cache, 配上 TaggingCacheDependency ...[copy code]
                    HttpRuntime.Cache.Add(
                        sourceURL.ToString(),
                        buffer,
                        new TaggingCacheDependency(sourceURL.Host, sourceURL.Scheme),
                        Cache.NoAbsoluteExpiration,
                        TimeSpan.FromSeconds(600),
                        CacheItemPriority.NotRemovable,
                        Info);
    在這個例子裡 (line 4), 直接在 TaggingCacheDependency 物件的 constructor 上直接標上 tags, 在此例是直接把網址的 hostname, scheme 兩個部份當作 tag, 未來就可以依照這兩種資訊直接讓 cache 裡的相關物件失效。 而要下令讓 Cache 內有標上某個 tag 的 cache item 失效,只要這行:  
    將標為 "funp.com" 的 cache item 設為失效的 cache item[copy code]
                TaggingCacheDependency.DependencyDispose("funp.com");
      結果就會如同上面的程式範例一樣,還留在 cache 的該網址下載資料,在這一瞬間通通都會被清掉...   用這種方式,是不是比拿到 key 再去呼叫 Cache.Remove( key ) 的方式簡單多了呢? 同時也能夠更快速的處理複雜的移除機制。其實運用 tagging 的方式只是一例,需要的話你也可以設計合適的 CacheDependency 類別。 以下是本篇文章的兩個附加參考檔案:
    Download File - URL清單
     

    2009/12/19 設計案例: 清除 Cache 物件 .NET C# MSDN Tips 技術隨筆 有的沒的 物件導向

  4. [設計案例] 清除Cache物件 #1. 問題與作法

    每次心裡有什麼好點子想寫出來時,第一關就卡在想不出個好標題... 想來想去的標題,怎麼看就是既不顯眼又不聳動... 果然是個老實的工程師性格 =_= ...  這次要講的,是 .NET HttpRuntime 裡提供的 Cache 物件的操作心得。這個東西我想不用我多作介紹,大家都用到爛掉了吧? 不過好用歸好用,有個老問題其實一直困擾著我很久了...

    " 我該怎麼手動的把某個物件從 cache 裡移除? "

    老實說,這問題蠻沒水準的... 老叫別人要翻 MSDN,我自己怎麼沒翻? 不不... 容我花點篇幅先說明一下問題。Cache物件,是個典型的 Dictionary 型態的應用 (雖然它沒有 implement interface: IDictionary… ), 透過 key 就可以拿到 cached item. 要從 cache 裡移除某個 item, 簡單的很,只要用 Remove 這個 method, 一行就搞定了:

    從 key 移除指定的 cache item[copy code]
       1:  HttpRuntime.Cache.Remove(“cache-key”);

    別小看這一行,實作起來障礙還不少。首先,你得額外去記著 cache key 的值。當你要移除的 cache item 有多個的時後,或是移除的 items 之間的關係有點複雜時,這些 code 就不怎麼漂亮了。下一個問題是:

    " 我該如何得知所有存在 Cache 內的 keys 有那些? "

    這個問題單純的多,那些把 intelligent sense 當購物網站的人 (平常不看文件,只會按下 . 然後挑個順眼 method 來用的人),可能這次就碰壁了... Cache 物件不像一般的 Dictionary 一樣,有提供 Keys 這樣的 property ... 它藏在 GetEnumerator 這 method 內,它會把所有的 keys 給巡一遍,你需要所有的 keys 的話,可以這樣用:

    跑過 cache 裡每一個 key[copy code]
       1:  foreach (string key in HttpRuntime.Cache) { 
       2:      // … 
       3:  }

    不過這樣的風險也是蠻高的,誰曉得你拿到 key 後的下一秒,這個 cache item 還在不在 cache 內?

     

     

     

    --------------------------------------------------------------

    本文正式開始! 哈哈,前面那一段只是廢話 + 碎碎唸,現在才是正題。前面想表達的只是,因為 cache 的不確定性 (資料隨時都會被 remove), 操作起來變的要格外小心, 即使它用起來像一般的 Dictionary 一樣。

    我舉個案例,來說明我應用 cache 的情況。假如我想實作一個簡單的 web browser, 透過網路下載資源是很慢的動作,每種 browser 都會有某種程度的 cache 機制。我們就拿 Cache 物件替代 IE 的 "temporary internet files” 目錄吧。這時很簡單,只要用 URL 當作 KEY,下載的 content 就當物件塞進去就好...

    不過事情沒那麼簡單。如果程式運作了一陣子,我想提供使用者手動清除 "部份" cache 的功能的話,那該怎麼辦? 我舉幾種情況:

    1. 從 cache 裡刪除所有從某個特定網站 (如: columns.chicken-house.net) 下載的資料
    2. 從 cache 裡刪除所有特定類型的資料 (如: content-type 為 image/jpeg 的圖檔)
    3. 從 cache 裡刪除所有透過特定 protocol (如: https) 下載的資料

    這樣的要求應該不算過份吧? 用前面提到的兩種作法,你會想哭吧 XD .. 用這些基礎,你大概只能選這幾種作法 (各位網友有好作法也記得提供一下):

    1. 自己另外管理所有下載過的 URL, 用盡各種適合的資料結構,讓你可以順利的挑出這些 match 的 key, 然後移除它。

      缺點: 都作這麼多,你乾脆自己重寫個 cache 機制好了... 何況時間一久,你管理的 key, 那些對應的資料搞不好老早就通通從 cache 裡清掉了...
    2. 聰明一點,用 regular expression … 從 GetEnumerator( ) 一筆一筆過濾出要移除的 URL, 然後清掉它...

      缺點: 這作法只會檢查還留在 cache 內的 URL,不過這樣的 cache 隨便也有成千上萬個,每次都要 looping 掃一次實在不怎麼好看... 有違處女座有潔癖的個性...

     

    這些方法 code 寫起來實在不怎麼漂亮,我就不寫 sample code 了,請各位自行想像一下寫起來的樣子。抱歉,如果你用的正好是上面的作法... 那請多包含... :D   這些都是 workable 的作法,但是看起來就是沒什麼設計感;程式可以動,不過就效能、簡潔、可讀性、美感來看,就是覺的不夠精緻 @@。跟朋友討論到這個問題時,我想到一個爛主意...

    " 用蠢方法,這些 cache item 先分好類,每一類去關聯一個檔案,設 CacheDependency … 要清掉時去 touch 一下這個檔案,一整組的物件就會自動被清出 cache 了…。”

    老實說,我覺的這是個既聰明又愚蠢的作法。聰明的是它很漂亮的解決我要如何移除某一群 item 的問題...,愚蠢的是這種單純程式內可以解決的事,竟然要繞到外面不必要的 file system I/O 動作... 而這通常是最慢的...

     

    --

    咳,寫太晚,實際的程式碼明天待續...

    2009/12/19 設計案例: 清除 Cache 物件 .NET ASP.NET C# MSDN Tips 技術隨筆 物件導向

  5. 終於突破單日 100KM 了 :D (台北 大溪)

    自從上個月,在露拍買了台二手車 (GIANT YUKON) 後,總算脫離每次都搭捷運租車來騎的日子了... 其實租車也沒什麼不好,不過租來的車子一來每次租的都不大一樣,二來都不能裝些慣用的配件... 騎起來總是不大順手,三來每次都得還車,行程多少會受限...

    買了車後,可以騎的路線就廣多了.. 上上週搭捷運,試騎了 [捷運永寧站] <----> [大溪] 的路線,還蠻好騎的,風景也棒,這次就決定從家裡出發,拼一拼從大溪來回,順便突破單日破百..

    image

    圖一: 永寧 <--> 大溪 GPS Log, 來回約 50km。感謝小熊子贊助 GPS Logger :D

    沒錯,男人就是這麼愛面子,自從上回有人留了話之後,有沒有單日破百,心裡總是覺的怪怪的... 加上沒趁機會累積一些當年勇,以後那有當年勇可以掛在嘴邊? 趁著這次小孩回娘家,天氣又正好,就來試一下...

    image

    [4.5km] 台北市淡水河三號水門 (延平門),我家到台北市河濱道,就走這裡最近了..

    因為這次拼 100km, 路上老停下來照相大概就騎不完了,加上我的 G9 被帶回外婆家了,這次用的是我老爸的相機... 不大順手就沒照太多了... 中間這段就沒特別照了。所以有些地點的照片就直接用上回拍的... 上次是大晴天,這次是陰天,一看就知道了 :D

    路線大概是這樣,到淡水河邊後,沿著淡水河右岸往南走,到華江橋牽車過橋,再往南沿著大漢溪右岸到新海橋,牽車上橋到左岸後一路騎到鶯歌..

     

    image

    [19.3km] 大漢溪左岸,快到城林橋了。

     

    image

    (上回的舊照片) 剛過城林橋..

     

    image

    [27km] 轉眼間已經到鶯歌了..

     

    image

    [28km] (上回舊照片) 鶯歌陶瓷博物館,經過了好幾次,可是都沒進去過 @_@

    image

    [28.3 km] 三鶯大橋下,鶯歌到大溪的自行車道 (2009/07 才通車)

    image

    過了三鶯大橋後,腳踏車道的風景就完全不一樣了 (Y)

    image

    過了個閘門,原來水都被關在這裡,難怪一路上大漢溪都沒什麼水...

    image

    真棒的風景,我喜歡這種有有山有水的 (Y)

     

    image

    離開溪邊,到大溪的這段路變成鄉間小逕,兩旁都是韭菜田及稻田...

    image

    [41.2km] 到大溪橋了 (這次沒照照片,拿上次的照片充數... :P)

    看看碼錶,才 41.2km, 騎回家大概連 90 都不到,更別提破百了,真是失算 @@ 看看時間還夠,回程就繞去三峽老街逛逛好了。

     

    image

    雖然公司有好幾個人住三峽,不過每個都不知道那家有名的牛角麵包是那一家… 只會跟我講我上次買錯家了 XD...

    看來還是 GOOGLE + 路人比較可靠,這次就找到了... 是在條不起眼的巷子裡,一家叫 [福美軒] 的麵包店.. 一堆人等著麵包出爐,排隊排到店外面... 足足排了一小時才買到 =_=,一個 20 元,每人限購 30 個...

    image

    在回程的路上拿了兩個出來吃,果然好吃 (Y)

     

    image

    柑園橋旁的XX公園 (抱歉,名字忘記了),有一片草地,前面的是蓮花池... 不過季節不對,看不到蓮花 @@ 那堆綠綠的是布袋蓮,可不是草地... 踩下去是會掉下去的

     

     

     

     

     

     

     

     

     

    image

    [85km] 華江橋上照的..

     

    image

    最後回到家,最後一個巷子口看了一下碼錶,98.5km…. @@

    單日破百的行程怎麼可以敗在這最後這區區 1.5km ? 於是就繞了點路,去附近的腳踏車店打個氣,然後再回家... 正好 100.29 km! 哇哈哈,單日破百的成就達成!

    2009/11/22 有的沒的 當年勇