天天看點

一起談.NET技術,.Net下的分布式緩存(2)--實作分布式緩存同步的手段

  前不久,俺寫了篇文章談到了.Net下面的分布式緩存的一些問題,并結合DNT裡面實作模式發表了一些自己的看法,近來通過學習相關的東西又有了一些新的體會, 寫在這裡作為分布式緩存列系文章的第二部分.

  其實對于性的擴充無非是Scale Up(向上擴充)或者是Scale Out(向外擴充), 微軟對此的看法是一個App的緩存最好是以它自己為實體邊界進行讀寫,而不要放到别處去,這樣帶的問題可能有對象的序列化傳送,反序列化,網絡連接配接開銷,跨程序的開銷,對于高性能的站點來說都是不能忽視的問題.出于對這些因素的考慮微推薦的作法不是把多個應用放在一起在多台Server布署,而是将一個App劃分成若幹個小的應用布署到不同的伺服器,下面的關系圖展示了這種關系, 這樣每種應用就可以獨立管理自己的緩存資料,但是對于象使用者資料這樣的通用資料仍然會存在多處.

  每台機器都維護一個WebFarm裡面的成員伺服器的清單,如果有新的伺服器進來發現自己不在這個清單中則會通知其它的伺服器把它加到這個名單裡面。添加緩存的這程是這樣, A伺服器需要插入一個新的緩存值,它把這個項目插入到自己的緩存中,然後用它初始化一個CacheControlItem并指定它的緩存政策(優先級,緩存生存時間),設定它的動作,即添加,然後把這個結象序列化通過Web傳送到每一個成員伺服器,接受到這些資料的伺服器跟據這個對象的Action指令,把反序列化後的對象加入到自己的緩存裡面,這樣一個同步的過程就完成了,移除緩存對象的過程與之類似,隻不過不需要傳送對象,隻在包裝類裡面設定它的Action為删除就可以了. 當然,為了提高性能,可以實作一個異步的偵聽線程專門用來響應緩存通知的請求. 總體上講這處辦法的效率比較低,在資料量較大的情況下可能會造成大量緩存資料的同步資料流。

  這兩個老外寫的東西似乎都比較啰索,不過對初學者來說比較友好,可以一步步地知道這件事情的來龍去脈,了解會清楚更刻一些。

  Memcached伺服器 : Win2003 sp1, Framework 2.0,P4 D 3.4G, 768MB 記憶體, 千兆網卡.

  Memcached客戶機 : Win2003 sp1, Framework 2.0,T2060, 1G記憶體( 沙加的神舟筆記本;) ), 千兆網卡.

  兩台機器通過直連線相連.

  .Net Cache單機測試 : P4 D 3.4G, 768MB 記憶體.

  測試結果, 存取10000個條目的時間:

         Memcached

Set(秒)

1.48

1.37

1.46

Get(秒)

2.42

2.43

         HttpRuntime.Cache

0.015

一起談.NET技術,.Net下的分布式緩存(2)--實作分布式緩存同步的手段
一起談.NET技術,.Net下的分布式緩存(2)--實作分布式緩存同步的手段

HttpRuntime.Cache

    protected void Page_Load(object sender, EventArgs e)

    {

            int start = 200;

            int runs = 10000;

            string keyBase = "testKey";

            string obj = "This is a test of an object blah blah es, serialization does not seem to slow things down so much.  The gzip compression is horrible horrible performance, so we only use it for very large objects.  I have not done any heavy benchmarking recently";

            long begin = DateTime.Now.Ticks;

            for(int i = start; i < start+runs; i++) 

            {

                HttpRuntime.Cache.Add(keyBase + i, obj,null,System.Web.Caching.Cache.NoAbsoluteExpiration,

                    TimeSpan.FromMinutes(1),System.Web.Caching.CacheItemPriority.Normal,null);

            }

            long end = DateTime.Now.Ticks;

            long time = end - begin;

            Response.Write(runs + " sets: " + new TimeSpan(time).ToString() + "ms<br />");

            begin = DateTime.Now.Ticks;

            int hits = 0;

            int misses = 0;

                string str = (string) HttpRuntime.Cache.Get(keyBase + i);

                if(str != null)

                    ++hits;

                else

                    ++misses;

            end = DateTime.Now.Ticks;

            time = end - begin;

            Response.Write(runs + " gets: " + new TimeSpan(time).ToString() + "ms");

    }

一起談.NET技術,.Net下的分布式緩存(2)--實作分布式緩存同步的手段
一起談.NET技術,.Net下的分布式緩存(2)--實作分布式緩存同步的手段

Memcached

namespace Memcached.MemcachedBench

{

    using System;

    using System.Collections;

    using Memcached.ClientLibrary;

    public class MemcachedBench 

        [STAThread]

        public static void Main(String[] args) 

        {

            int runs = 100;

            if(args.Length > 1)

                runs = int.Parse(args[0]);

                start = int.Parse(args[1]);

            string[] serverlist = { "140.192.34.72:11211", "140.192.34.73:11211" };

            // initialize the pool for memcache servers

            SockIOPool pool = SockIOPool.GetInstance();

            pool.SetServers(serverlist);

            pool.InitConnections = 3;

            pool.MinConnections = 3;

            pool.MaxConnections = 5;

            pool.SocketConnectTimeout = 1000;

            pool.SocketTimeout = 3000;

            pool.MaintenanceSleep = 30;

            pool.Failover = true;

            pool.Nagle = false;

            pool.Initialize();

            MemcachedClient mc = new MemcachedClient();

            mc.EnableCompression = false;

                mc.Set(keyBase + i, obj);

            Console.WriteLine(runs + " sets: " + new TimeSpan(time).ToString() + "ms");

                string str = (string) mc.Get(keyBase + i);

            Console.WriteLine(runs + " gets: " + new TimeSpan(time).ToString() + "ms");

            Console.WriteLine("Cache hits: " + hits.ToString());

            Console.WriteLine("Cache misses: " + misses.ToString());

            IDictionary stats = mc.Stats();

            foreach(string key1 in stats.Keys)

                Console.WriteLine(key1);

                Hashtable values = (Hashtable)stats[key1];

                foreach(string key2 in values.Keys)

                {

                    Console.WriteLine(key2 + ":" + values[key2]);

                }

                Console.WriteLine();

            SockIOPool.GetInstance().Shutdown();

        }

}

  通過這個對比測試我們可以看出内建的Cache比使用Memcached要快出約130倍,但是從總體速度上來看Memcached并不慢,這兩種方式可以在項目中有選擇性地結合使用可以産生很棒的效果.并且Memcached可使用的記憶體數量要多得多,同時也可以做叢集避免單點問題.

繼續閱讀