日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网站架构之缓存应用(摘录)

發(fā)布時(shí)間:2024/7/19 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网站架构之缓存应用(摘录) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

網(wǎng)站緩存這個(gè)話題并不新穎,但是能否將它用好,可是一門學(xué)問,同一件工具在不同人的手中會(huì)做出不同的事情來。這里我來分享總結(jié)下我對(duì)于網(wǎng)站架構(gòu)中緩存應(yīng)用的一些看法和經(jīng)驗(yàn),大家有好的想法可以補(bǔ)充?
??? 第一:緩存的一些基本概念。
??????? 1:緩存(CACHE)與緩沖(BUFFER)的區(qū)別,我認(rèn)為緩存可以在某種程序上理解成一級(jí)緩存(Primary Cache),數(shù)據(jù)全局共享。緩沖則屬于二級(jí)緩存,只對(duì)一部分對(duì)象共享數(shù)據(jù),二級(jí)緩存在某種程序上主要是降低一級(jí)緩存組件的訪問壓力以及提高緩存的存取效率。
??????? 2:緩存的一些基本屬性:命中率,表示緩存命中的次數(shù)/總的請(qǐng)求數(shù),這是緩存設(shè)計(jì)的重要質(zhì)量指標(biāo)之一;緩存執(zhí)行效率,例如GET,INSERT,DELETE等;容量,即緩存介質(zhì)的容量最大值;成本,即開發(fā)成本,部署成本,軟硬件成本。
??????? 3:緩存的問題,存儲(chǔ)介質(zhì)的選擇往往左右緩存的設(shè)計(jì),緩存在不命中時(shí)往往會(huì)使性能下降。
??? 第二:網(wǎng)站中緩存的應(yīng)用場景:
??????? 1:可以緩存整個(gè)頁面的html,提高訪問響應(yīng)能力;
??????? 2:針對(duì)局部頁面元素進(jìn)行緩存;
??????? 3:對(duì)復(fù)雜數(shù)據(jù)的結(jié)果進(jìn)行緩存,例如一個(gè)查詢需要結(jié)合多個(gè)數(shù)據(jù)集,然后根據(jù)這些數(shù)據(jù)集進(jìn)行相應(yīng)的運(yùn)算,即使每個(gè)子集查詢有緩存,但還是需要額外的運(yùn)算,這種情況可以考慮緩存計(jì)算后的結(jié)果。
??????? 4:對(duì)耗時(shí)的查詢進(jìn)行緩存,例如產(chǎn)品列表頁的查詢。
??????? 5:和上下文相關(guān)的用戶數(shù)據(jù),例如用戶從訂單埴寫頁進(jìn)入到訂單成功頁,或者是從產(chǎn)品列表頁點(diǎn)擊詳細(xì)產(chǎn)品進(jìn)行預(yù)訂時(shí)的訂單填寫頁,此時(shí)這兩個(gè)頁面之間都需要傳遞大量的相關(guān)數(shù)值,我們可以把所有的數(shù)值封裝在一個(gè)類中,然后通過緩存進(jìn)行通信。
??? 第三:影響緩存命中率的因素。
??????? 1:數(shù)據(jù)時(shí)實(shí)性,每個(gè)業(yè)務(wù)系統(tǒng)都對(duì)自己的數(shù)據(jù)有相應(yīng)的要求,有些數(shù)據(jù)的實(shí)時(shí)性非常強(qiáng),像每日的股票信息,這種情況如果設(shè)置了緩存,緩存的命中率會(huì)特別低。
??????? 2:緩存粒度問題,一般來說是緩存的跨度太大,即此時(shí)的KEY值包含的條件太多,會(huì)出現(xiàn)緩存命中率特別低的情況。
??? 第四:提高緩存命中率的方法:
??????? 1:增大存儲(chǔ)介質(zhì)的容量;
??????? 2:對(duì)非常熱點(diǎn)的數(shù)據(jù)進(jìn)行捕捉,可以采用實(shí)時(shí)更新緩存的方式來平衡緩存與實(shí)時(shí)性的問題,例如可以單獨(dú)開啟一個(gè)后臺(tái)服務(wù)來定時(shí)做更新緩存的工作。
??????? 3:調(diào)整緩存KEY值的算法,盡量保證緩存KEY的細(xì)粒度,KEY-VALUE就是很好的細(xì)粒度例子。
??????? 4:根據(jù)業(yè)務(wù)調(diào)整緩存的過期策略。
???????
??? 第五:如何實(shí)現(xiàn)緩存組件:
??????? 1:采用二級(jí)緩存架構(gòu),即在web server上設(shè)置二級(jí)緩存,這里的二級(jí)緩存即上面的提到的緩沖,只對(duì)具體的webserver進(jìn)行數(shù)據(jù)共享,二級(jí)緩存可以考慮采用微軟企業(yè)庫的緩存組件來完成。由于一級(jí)緩存的實(shí)現(xiàn)往往都是單獨(dú)的服務(wù)器,為了減少緩存服務(wù)器的壓力,在webserver上對(duì)數(shù)據(jù)進(jìn)行緩沖,在降低緩存服務(wù)器壓力的情況下最大的好處在于緩存的存取速度上。
??????? 2:一級(jí)緩存由單獨(dú)的緩存服務(wù)器來完成,至于緩存服務(wù)器采用哪種緩存方案,可以根據(jù)不同的場景來決定。如果考慮到部署的方便性,可以采用微軟企業(yè)庫來完成一級(jí)緩存,如果服務(wù)器允許,可以采用memcached來實(shí)現(xiàn)。
??????? cache服務(wù)器采用微軟企業(yè)庫實(shí)現(xiàn)的優(yōu)缺點(diǎn):
??????? 1:優(yōu)點(diǎn),開發(fā)以及部署都非常容易,不需要安裝第三方軟件等等;
??????? 2:缺點(diǎn),需要自己開發(fā)客戶端功能以實(shí)現(xiàn)分布式,這里我們可以采用一致性hash算法來實(shí)現(xiàn),同時(shí)如果服務(wù)以WCF形式公布開,在訪問效率上也不是最優(yōu)的,比起memcached的通信方式要差一些。
??????? memcached的優(yōu)缺點(diǎn):
??????? 1:優(yōu)點(diǎn),通信方式比起wcf要高;
??????? 2:缺點(diǎn),需要第三方服務(wù)的支持,需要在服務(wù)器上安裝memcached服務(wù),這好像也不是什么重要的缺點(diǎn)。


??????? 最后,貼出網(wǎng)站網(wǎng)頁在數(shù)據(jù)訪問上的流程圖,供大家參考,在下面的文章中我會(huì)把實(shí)現(xiàn)的方案分享出來。

?

上一篇我主要總結(jié)了網(wǎng)站緩存中的一些基本概念,以及我對(duì)于網(wǎng)站架構(gòu)緩存應(yīng)用的架構(gòu)實(shí)現(xiàn)思路,這篇主要分享下如何利用微軟企業(yè)庫來實(shí)現(xiàn)一二級(jí)緩存的緩存服務(wù)。

???
??? 為了能夠有效的管理緩存,需要對(duì)使用緩存方法上做一些規(guī)范,即要想使用緩存組件提供的服務(wù),需要在指定的配置文件中按照一定的規(guī)則來配置緩存條目,不允許在配置之處使用緩存。下面先展示下一條Cache條目的配置:

<Region name="MyBlog">
??? <SubRegion name="default">??
????? <Cache CacheMode="LocalCacheOnlyMode" Key="BlogListConfigKey" BufferType="AbsoluteTime" BufferTimeSeconds="300" CacheType="AbsoluteTime" CacheTimeMinutes="30" CachePriority="Normal"/>????
??? </SubRegion>
? </Region>

?

??
???? 上面的代碼中,其實(shí)由三部分構(gòu)成:
???? 1:主分區(qū):Regin,如果一個(gè)網(wǎng)站分很多子系統(tǒng),可以為每個(gè)子系統(tǒng)定義一個(gè)這樣的主分區(qū),例如食品頻道Food,手機(jī)頻道Mobile等;
???? 2:子分區(qū):SubRegion,主分區(qū)下面的子分區(qū),即對(duì)子系統(tǒng)更加小的劃分,可以根據(jù)子系統(tǒng)的功能來劃分,例如產(chǎn)品列表頁List,詳細(xì)頁Detail等;
???? 3:緩存條目:Cache,指具體的一則緩存條目規(guī)則,這里的緩存條目規(guī)則并不是指某一條緩存設(shè)置,而是指一條緩存規(guī)則,與具體的緩存條目是一對(duì)多的關(guān)系。
??????? <1>:CacheMode,設(shè)置緩存模式,是只有二級(jí)緩存還是即有一級(jí)緩存也有二級(jí)緩存,例如用戶頁面之間的信息溝通就只需要二級(jí)緩存,即緩存在web server上。而產(chǎn)品列表頁的數(shù)據(jù)屬于全局?jǐn)?shù)據(jù),就需要即采用二級(jí)緩存也需要一級(jí)緩存。
??????? <2>:BufferType,指二級(jí)緩存的過期方式,分為絕對(duì)過期,滑動(dòng)過期,文件依賴。
??????? <3>:BufferTimeSeconds,二級(jí)緩存Timespan中的秒。
??????? <4>:CacheType,一級(jí)緩存的過期方式,類型同BufferType.
??????? <5>:CacheTimeMinutes,一級(jí)緩存Timespan中的分鐘。
??????? <6>:CachePriority,緩存的優(yōu)先級(jí)。


???? 二級(jí)緩存實(shí)現(xiàn):
???? 第一:IWebCacheProvider,緩存提供者接口,它公布了所有緩存組件需要的方法,接口之所以加上了ServeiceContract標(biāo)簽,是由于下面的一級(jí)緩存WCF服務(wù)也繼承此接口的原因。小提示:WCF服務(wù)契約對(duì)于方法重載的實(shí)現(xiàn)和普通方式有小小區(qū)別,請(qǐng)注意OperationContract標(biāo)簽的定義。
????

?[ServiceContract]
??? public? interface IWebCacheProvider
??? {
??????? [OperationContract(Name = "Add")]
??????? void Insert(string key, object value, string region, string subRegion);

??????? [OperationContract(Name = "AddByAbsoluteTime")]
??????? void Insert(string key, object value, string region, string subRegion, MyCacheItemPriority scavengingPriority, AbsoluteTimeCacheDependency absoluteTimeCacheDependency);

??????? [OperationContract(Name = "AddBySlidingTime")]
??????? void Insert(string key, object value, string region, string subRegion, MyCacheItemPriority scavengingPriority, SlidingTimeCacheDependency slidingTimeCacheDependency);

??????? [OperationContract(Name = "AddByFile")]
??????? void Insert(string key, object value, string region, string subRegion, MyCacheItemPriority scavengingPriority, FileCacheDependency fileCacheDependency);

??????? [OperationContract]
??????? void Delete(string key, string region, string subRegion);

??????? [OperationContract]
??????? object Get(string key, string region, string subRegion);

??????? [OperationContract]
??????? void Clear(string region);

??????? [OperationContract]
??????? int Count(string region);
??? }


?

???
??? 第二:EntLibWebCacheProvider,微軟企業(yè)庫實(shí)現(xiàn)緩存實(shí)現(xiàn)類。代碼并不貼了,基本就是利用企業(yè)庫的緩存組件實(shí)現(xiàn)上面的接口。
???
???? 第三:MyWebCacheServiceClient,提供緩存客戶端的實(shí)例。包含了兩個(gè)重要的屬性:一級(jí)緩存實(shí)例,二級(jí)緩存實(shí)例。余下的就是調(diào)用EntLibWebCacheProvider來完成緩存的調(diào)用,以及根據(jù)緩存規(guī)則,選擇操作一級(jí)緩存以及二級(jí)緩存。

?????????? 說明:下面代碼中的GetMemcachedWebCacheProvider是下篇文章會(huì)提到的利用memcached實(shí)現(xiàn)一級(jí)緩存,由于需要支持一級(jí)緩存在企業(yè)庫以及memcached之間的切換才出現(xiàn)的邏輯。
?????

????? //一級(jí)緩存
??????? IWebCacheProvider PrimaryCacheProvider;
??????? //二級(jí)緩存
??????? IWebCacheProvider SecondaryCacheProvider;
???????? /// <summary>
??????? /// 實(shí)例化二級(jí)緩存
??????? /// </summary>
??????? /// <param name="configFilePath"></param>
??????? /// <returns></returns>
??????? private IWebCacheProvider GetSecondaryCacheProvider()
??????? {
??????????? IWebCacheProvider provider = null;
??????????? provider = WebCacheProviderFactory.GetEntLibWebCacheProvider(configFilePath);
??????????? return provider;
??????? }
??????? /// <summary>
??????? /// 獲取一級(jí)緩存
??????? /// </summary>
??????? /// <param name="hashKey"></param>
??????? /// <param name="configFilePath"></param>
??????? /// <returns></returns>
??????? private IWebCacheProvider GetPrimaryCacheProvider(uint hashKey)
??????? {
??????????? IWebCacheProvider provider = null;
??????????? string cacheType = WebConfig.ChannelConfig["CacheType"].ToString().ToLower();
??????????? switch (cacheType)
??????????? {
??????????????? case "memcached":
??????????????????? provider = WebCacheProviderFactory.GetMemcachedWebCacheProvider(configFilePath);
??????????????????? break;
??????????????? case "entlib":
??????????????????? provider = servicePool.GetServiceClient(hashKey) as IWebCacheProvider;
??????????????????? break;
??????????? }
??????????
??????????? return provider;
??????? }

?

???????
?????? 一級(jí)緩存的實(shí)現(xiàn):由于一級(jí)緩存也采用微軟企業(yè)庫實(shí)現(xiàn),而企業(yè)庫本身是不具備分布式功能的,就算是memcached,本身也不具備分布式,而在于客戶端的實(shí)現(xiàn),所以企業(yè)庫我們也可以實(shí)現(xiàn)分布式。
??????? 首先:我們把實(shí)現(xiàn)了緩存的組件以WCF服務(wù)形式分布出來,在多個(gè)服務(wù)器上部署,形成一個(gè)服務(wù)器群;
??????? 其實(shí):實(shí)現(xiàn)分布式的客戶端,讓服務(wù)的請(qǐng)求均勻的分布到之前部署的WCF緩存服務(wù)器上。這里采用一致性hash算法實(shí)現(xiàn),主要是根據(jù)key的hash值以及服務(wù)器數(shù)量來選擇存儲(chǔ)的服務(wù)器,這里貼些主要的實(shí)現(xiàn)代碼,供參考:
???????
??????? 1:定義一個(gè)hash的服務(wù)器實(shí)例集合,為每個(gè)服務(wù)器分配250個(gè)hash值,這里的值可以根據(jù)實(shí)際情況調(diào)整。

private Dictionary<uint, isRoc.Common.Cache.CacheProvider.IWebCacheProvider> hostDictionary;

?

??????? 2:定義一個(gè)hash的服務(wù)實(shí)例key集合,用來統(tǒng)計(jì)所有服務(wù)器實(shí)例中的hash key。?

private uint[] hostKeysArray;

?

??????? 3:創(chuàng)建服務(wù)器列表的hash值。

/// <summary>
??????? /// 重新設(shè)置服務(wù)器列表
??????? /// </summary>
??????? /// <param name="hosts">服務(wù)器列表</param>
??????? internal void Setup(List<WebCacheServerInfo> hosts)
??????? {
??????????? hostDictionary = new Dictionary<uint, isRoc.Common.Cache.CacheProvider.IWebCacheProvider>();
??????????? List<isRoc.Common.Cache.CacheProvider.IWebCacheProvider> clientList = new List<isRoc.Common.Cache.CacheProvider.IWebCacheProvider>();
??????????? List<uint> hostKeysList = new List<uint>();
??????????? foreach (WebCacheServerInfo host in hosts)
??????????? {
??????????????? //創(chuàng)建客戶端

??????????????? isRoc.Common.Cache.CacheProvider.IWebCacheProvider client = ServiceProxyFactory.Create<isRoc.Common.Cache.CacheProvider.IWebCacheProvider>(host .HostUri );
??????????????? //Create 250 keys for this pool, store each key in the hostDictionary, as well as in the list of keys.
??????????????? for (int i = 0; i < 250; i++)
??????????????? {
??????????????????? uint key = 0;
??????????????????? switch (this.HashAlgorithm)
??????????????????? {
??????????????????????? case EHashAlgorithm.KetamaHash:
??????????????????????????? key = (uint)Math.Abs(KetamaHash.Generate(host.HostUri + "-" + i));
??????????????????????????? break;
??????????????????????? case EHashAlgorithm.FnvHash32:
??????????????????????????? key = BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(Encoding.UTF8.GetBytes(host.HostUri + "-" + i)), 0);
??????????????????????????? break;
??????????????????? }

??????????????????? if (!hostDictionary.ContainsKey(key))
??????????????????? {
??????????????????????? hostDictionary.Add(key, client);
??????????????????????? hostKeysList.Add(key);
??????????????????? }
??????????????? }

??????????????? clientList.Add(client);
??????????? }

??????????? //Hostlist should contain the list of all pools that has been created.
??????????? clientArray = clientList.ToArray();

??????????? //Hostkeys should contain the list of all key for all pools that have been created.
??????????? //This array forms the server key continuum that we use to lookup which server a
??????????? //given item key hash should be assigned to.
??????????? hostKeysList.Sort();
??????????? hostKeysArray = hostKeysList.ToArray();

??????? }

??????? 4:如何根據(jù)key值來查找具體的緩存服務(wù)實(shí)例呢,即具體的key存儲(chǔ)在哪一臺(tái)服務(wù)器上呢?根據(jù)傳入的key值,計(jì)算出對(duì)應(yīng)的hash值,然后經(jīng)過特定的算法計(jì)算出服務(wù)器實(shí)例地址。?

?internal isRoc.Common.Cache.CacheProvider.IWebCacheProvider GetServiceClient(uint hash)
??????? {
??????????? //Quick return if we only have one host.
??????????? if (clientArray.Length == 1)
??????????? {
??????????????? return clientArray[0];
??????????? }

??????????? //New "ketama" host selection.
??????????? int i = Array.BinarySearch(hostKeysArray, hash);

??????????? //If not exact match...
??????????? if (i < 0)
??????????? {
??????????????? //Get the index of the first item bigger than the one searched for.
??????????????? i = ~i;

??????????????? //If i is bigger than the last index, it was bigger than the last item = use the first item.
??????????????? if (i >= hostKeysArray.Length)
??????????????? {
??????????????????? i = 0;
??????????????? }
??????????? }
??????????? return hostDictionary[hostKeysArray[i]];
??????? }

??????? 總結(jié):本文簡單的介紹了如何利用微軟企業(yè)庫來實(shí)現(xiàn)具有兩級(jí)緩存的緩存組件,上篇我提到過,實(shí)現(xiàn)一級(jí)緩存也可以采用memcached,采用memcached可以不用自己開發(fā)分布式客戶端,目前有兩個(gè)成熟的解決方案:1:Memcached.ClientLibrary2:EnyimMemcached。下篇我來介紹一級(jí)緩存如何通過memcached實(shí)現(xiàn),以及如何讓組件在一級(jí)緩存上即支持企業(yè)庫也支持memcached。?

這篇來講如何利用memcached實(shí)現(xiàn)一級(jí)緩存,以及如何讓一級(jí)緩存組件支持在企業(yè)庫,memcached或者其它第三方實(shí)施方案之間的切換。memcached本人并沒有太多經(jīng)驗(yàn),如果文中有說的不對(duì)的地方,還希望批評(píng)指出,且文中關(guān)于memcached的代碼大多來自網(wǎng)絡(luò)。

??
???? 創(chuàng)建memcached實(shí)現(xiàn)類MemcachedWebCacheProvider,由它來繼承緩存提供者接口IWebCacheProvider,主里memcached客戶端我采用.NET memcached client library ,這個(gè)類庫很久沒有更新這過了,沒有和java版同步,有部分功能目前沒有實(shí)現(xiàn)。
???? 1:初始化memcached服務(wù),這段初始化代碼在程序中保證執(zhí)行一次就夠,一般可以放在gloabl文件中,或者是設(shè)置一個(gè)靜態(tài)變量來存儲(chǔ)服務(wù)的狀態(tài)。
?

?private void Setup()
??????? {
??????????? String[] serverlist = { "127.0.0.1:11211" };
??????????? this._pool = SockIOPool.GetInstance("default");
??????????? this._pool.SetServers(serverlist); //設(shè)置服務(wù)器列
??????????? //各服務(wù)器之間負(fù)載均衡的設(shè)置
??????????? this._pool.SetWeights(new int[] { 1 });
??????????? //socket pool設(shè)置
??????????? this._pool.InitConnections = 5; //初始化時(shí)創(chuàng)建的連接數(shù)
??????????? this._pool.MinConnections = 5; //最小連接數(shù)
??????????? this._pool.MaxConnections = 250; //最大連接數(shù)
??????????? //連接的最大空閑時(shí)間,下面設(shè)置為6個(gè)小時(shí)(單位ms),超過這個(gè)設(shè)置時(shí)間,連接會(huì)被釋放掉
??????????? this._pool.MaxIdle = 1000 * 60 * 60 * 6;
??????????? //通訊的超時(shí)時(shí)間,下面設(shè)置為3秒(單位ms),.NET版本沒有實(shí)現(xiàn)
??????????? this._pool.SocketTimeout = 1000 * 3;
??????????? //socket連接的超時(shí)時(shí)間,下面設(shè)置表示連接不超時(shí),即一直保持連接狀態(tài)
??????????? this._pool.SocketConnectTimeout = 0;
??????????? this._pool.Nagle = false; //是否對(duì)TCP/IP通訊使用Nalgle算法,.NET版本沒有實(shí)現(xiàn)
??????????? //維護(hù)線程的間隔激活時(shí)間,下面設(shè)置為60秒(單位s),設(shè)置為0表示不啟用維護(hù)線程
??????????? this._pool.MaintenanceSleep = 60;
??????????? //socket單次任務(wù)的最大時(shí)間,超過這個(gè)時(shí)間socket會(huì)被強(qiáng)行中斷掉(當(dāng)前任務(wù)失敗)
??????????? this._pool.MaxBusy = 1000 * 10;
??????????? this._pool.Initialize();
??????? }

?

??????? 2:獲取一個(gè)memcached客戶端。
???????

??????? private MemcachedClient GetClient()
??????? {
??????????? MemcachedClient client = new MemcachedClient();
??????????? client.PoolName = "default";
??????????? return client;
??????? }

?

??????? 3:根據(jù)memcached提供的功能實(shí)現(xiàn)IWebCacheProvider,代碼就不貼了,大家可以自己去試試。
???????
??????? 到此我們就利用memcached實(shí)現(xiàn)了一級(jí)緩存,由于.NET memcached client library 實(shí)現(xiàn)了分布式,我們只需要在多臺(tái)服務(wù)器上安裝上memcached服務(wù),在初始化memcached代碼中增加了服務(wù)器相關(guān)配置即可。String[] serverlist = { "127.0.0.1:11211" };
???????
??????? 如何讓一級(jí)緩存組件支持多實(shí)現(xiàn)方案之間的切換。
??????? MyWebCacheServiceClient:客戶端緩存組件實(shí)例,它來完成一級(jí)緩存與二級(jí)緩存之間的聯(lián)系,以及根據(jù)配置文件來選擇一級(jí)緩存的實(shí)施方案。
??????? 第一:CacheServiceMode,根據(jù)它就可以決定緩存是只緩存二級(jí)緩存還是兩級(jí)都緩存。

???????????????? 1:LocalCacheOnlyMode,只啟用web server上的二級(jí)緩存。

???????????????? 2:BufferedLCacheServerMode,即啟用web server上的二級(jí)緩存也啟用cache server上的緩存。

???????????????? 3:Off,關(guān)閉緩存功能。
??????? 第二:IWebCacheProvider service = this .GetPrimaryCacheProvider(hashKey);方式?jīng)Q定了一級(jí)緩存的實(shí)施方案。
????????

/// <summary>
??????? /// 獲取一級(jí)緩存
??????? /// </summary>
??????? /// <param name="hashKey"></param>
??????? /// <param name="configFilePath"></param>
??????? /// <returns></returns>
??????? private IWebCacheProvider GetPrimaryCacheProvider(uint hashKey)
??????? {
??????????? IWebCacheProvider provider = null;
??????????? string cacheType = WebConfig.ChannelConfig["CacheType"].ToString().ToLower();
??????????? switch (cacheType)
??????????? {
??????????????? case "memcached":
??????????????????? provider = WebCacheProviderFactory.GetMemcachedWebCacheProvider(configFilePath);
??????????????????? break;
??????????????? case "entlib":
??????????????????? provider = servicePool.GetServiceClient(hashKey) as IWebCacheProvider;
??????????????????? break;
??????????? }
??????????
??????????? return provider;
??????? }

?

???????? 插入緩存的邏輯:原理就是根據(jù)配置文件中的CacheMode來完成緩存級(jí)別的判定以及一級(jí)緩存的方案。

public void Insert(string key, object value, string region, string subRegion, CacheItemConfig cacheItemConfig)
??????? {
??????????? if (string.IsNullOrEmpty(key) || value == null)
??????????????? return;
??????????? //關(guān)閉模式,不使用緩存
??????????? if (Options.CacheServiceMode == ECacheServiceMode.Off)
??????????? {
??????????????? return;
??????????? }
??????????? else if (Options.CacheServiceMode == ECacheServiceMode.BufferedLCacheServerMode
??????????????? || Options.CacheServiceMode == ECacheServiceMode.LocalAndCacheServerAndSql
??????????????? || Options.CacheServiceMode == ECacheServiceMode.LocalCacheOnlyMode)
??????????? {//使用帶緩沖的模式
??????????????? if (Options.BufferType == ECacheDependencyType.SlidingTime)
??????????????? {
??????????????????? SecondaryCacheProvider.Insert(key, value, region, subRegion, MyCacheItemPriority.Normal, Options.BufferSlidingTime);
??????????????? }
??????????????? else if (Options.BufferType == ECacheDependencyType.AbsoluteTime)
??????????????? {
??????????????????? SecondaryCacheProvider.Insert(key, value, region, subRegion, MyCacheItemPriority.Normal, Options.BufferAbsoluteTime);
??????????????? }

??????????????? if (Options.CacheServiceMode == ECacheServiceMode.LocalCacheOnlyMode)
??????????????? {//只使用本地緩存
??????????????????? return;
??????????????? }
??????????? }

??????????? checkKey(key);
??????????? uint hashKey = hash(key);

??????????? try
??????????? {
??????????????? if (Options.CacheServiceMode == ECacheServiceMode.CacheServerMode
??????????????????? || Options.CacheServiceMode == ECacheServiceMode.BufferedLCacheServerMode
??????????????????? || Options.CacheServiceMode == ECacheServiceMode.CacheServerAndSql
??????????????????? || Options.CacheServiceMode == ECacheServiceMode.LocalAndCacheServerAndSql)
??????????????? {//CacheServer模式使用Cache服務(wù)器保存Cache?????????????????????????????????????
??????????????????? IWebCacheProvider service = this .GetPrimaryCacheProvider(hashKey);
??????????????????? byte[] byteValue = SerializationHelper.SaveToBinaryBytes(value);
??????????????????? var cachePriority = ModelConverter.ToRefClass(cacheItemConfig.CachePriority);
??????????????????? if (cacheItemConfig.CacheType == ECacheDependencyType.AbsoluteTime)
??????????????????? {
??????????????????????? AbsoluteTimeCacheDependency absTime = new AbsoluteTimeCacheDependency();
??????????????????????? absTime.AbsoluteTime = DateTime.Now.AddMinutes(cacheItemConfig.CacheTimeMinutes);
??????????????????????? service.Insert(key, byteValue, region, subRegion, cachePriority, absTime);
??????????????????? }
??????????????????? else if (cacheItemConfig.CacheType == ECacheDependencyType.SlidingTime)
??????????????????? {
??????????????????????? SlidingTimeCacheDependency slTime = new SlidingTimeCacheDependency();
??????????????????????? slTime.SlidingTime = new TimeSpan(0, cacheItemConfig.CacheTimeMinutes, 0);
??????????????????????? service.Insert(key, byteValue, region, subRegion, cachePriority, slTime);
??????????????????? }
??????????????? }
??????????? }
??????????? catch (Exception ex)
??????????? {//出現(xiàn)異常,保存到數(shù)據(jù)庫中
??????????????? servicePool.ReplaceServiceClient(hashKey);
??????????????? this.SendLogEmail(ex);
??????????? }
??????????

??????? }


?

???????
??????? 客戶端調(diào)用代碼:為了調(diào)用方便,創(chuàng)建一個(gè)CacheHelper來幫助完成:

public class CacheHelper
??? {
??????? /// <summary>
??????? /// 主分區(qū)
??????? /// </summary>
??????? public const string REGION = "MyBlog";
??????? /// <summary>
??????? /// 子分區(qū)
??????? /// </summary>
??????? public const string SUB_REGION = "default";
??????? public const string BlogListConfigKey = "BlogListConfigKey";
??????? #region 頁面間數(shù)據(jù)傳遞
??????? /// <summary>
??????? /// 新增頁面間傳遞數(shù)據(jù)到WebCache
??????? /// </summary>
??????? /// <returns>返回PageKeyID,用于頁面間傳遞的鍵值</returns>
??????? public static string InsertPageParams(string configKey, object obj,string pageKey)
??????? {
??????????? string result = null;

??????????? MyWebCacheServiceClient cacheClient = CacheClientFactory.GetWebCacheServiceClient(REGION, SUB_REGION, configKey);
??????????? cacheClient.Insert(
??????????????? MyWebCacheServiceClient.BuildKey(configKey,pageKey),
??????????????? obj,
??????????????? REGION,
??????????????? SUB_REGION);

??????????? return result;
??????? }
??????? /// <summary>
??????? /// 從Cache里獲取頁面?zhèn)鬟fCache
??????? /// </summary>
??????? /// <param name="key">FlightCacheKey里的常量</param>
??????? /// <param name="pageKeyID">頁面?zhèn)鬟f的鍵值</param>
??????? public static object GetPageParams(string configKey, string pageKey)
??????? {
??????????? object result = null;
??????????? MyWebCacheServiceClient cacheClient = CacheClientFactory.GetWebCacheServiceClient(REGION,
??????????????? SUB_REGION, configKey);
??????????? result = cacheClient.Get(
??????????????? MyWebCacheServiceClient.BuildKey(configKey, pageKey),
??????????????? REGION,
??????????????? SUB_REGION);

??????????? return result;

??????? }
??????? #endregion
??? }

對(duì)于web系統(tǒng)中增加緩存服務(wù),使用起來還是挺方便的,目前可采用的方案比較多,有微軟的企業(yè)庫,memcached等等。但如果需要很好的對(duì)項(xiàng)目中的緩存進(jìn)行監(jiān)控管理,也不是一件特別容易的事情,例如:監(jiān)控緩存服務(wù)器上都有哪些項(xiàng)目使用了緩存,具體都有多少個(gè)key,大小,單個(gè)key的命中率以及過期時(shí)間等信息。有了這些信息,就非常容易排查內(nèi)存為什么快用完的問題,如果再提供手動(dòng)過期緩存的服務(wù),就更好了,有的時(shí)候由于數(shù)據(jù)出錯(cuò),需要緊急讓緩存失效,此種辦法影響最小。

???
??? 這篇我來總結(jié)了針對(duì)memcached的緩存管理。
???
??? 其實(shí)memcached本身也提供了一些緩存統(tǒng)計(jì)信息,例如:當(dāng)前總共的緩存數(shù)量,使用的內(nèi)存量,總獲取次數(shù),總的寫入次數(shù),總的命中次數(shù)等等,但這種統(tǒng)計(jì)信息粒度太大:

??? 1:無法具體到單個(gè)key,如果我們想針對(duì)某一個(gè)key統(tǒng)計(jì)它的命中率情況,就不好辦了。

??? 2:無法分析系統(tǒng)中都有哪些項(xiàng)目使用了key,哪個(gè)項(xiàng)目占用的key多,內(nèi)存多。

??? 3:無法實(shí)現(xiàn)手工過期,這種需求某些特殊情況下也是很有幫助的。

?

??? 既然memcached本身不提供,我這里采用了一種變通的方式來記錄我們特定的信息。
???
??? 首先我們引進(jìn)一個(gè)概念:分區(qū),這個(gè)分區(qū)可以理解成電腦上的硬盤分區(qū),用戶可以把不同的文件放在不同的分區(qū)上,這樣在管理上也容易些,同樣分區(qū)底下有子分區(qū),就像電腦上的文件一樣,子分區(qū)下面就是具體的key了,對(duì)于我們的cache后臺(tái)管理,可以這樣理解,一個(gè)項(xiàng)目可以分配為一個(gè)分區(qū),按項(xiàng)目功能模塊可以分為不同的子分區(qū),子分區(qū)下來分散著N多key。

?

?

實(shí)現(xiàn)方案:我們可以對(duì)每個(gè)key的訪問記錄下它的一些信息,例如:大小,所屬分區(qū)名,過期時(shí)間,訪問命中率,然后把這些信息在每個(gè)memcached 實(shí)例上創(chuàng)建一個(gè)特殊key,用于存儲(chǔ)key的訪問信息。
???
??? 注意點(diǎn):

?????? 1:由于記錄訪問信息都需要更新特殊key,如果過于頻繁,會(huì)影響正常的cache性能,所以可以考慮形成一個(gè)內(nèi)存隊(duì)列,當(dāng)數(shù)量達(dá)到多少后(如果key使用頻率不高,還可以設(shè)定時(shí)間,當(dāng)過了這個(gè)時(shí)間,即使數(shù)量不夠也進(jìn)行更新),統(tǒng)一更新特殊key內(nèi)容。
?????? 2:由于memcached有單個(gè)key大小限制,所以對(duì)于這種統(tǒng)計(jì)信息key,不能過大,記錄key訪問信息時(shí),盡量以文本形式存儲(chǔ),這樣能保證最小。

?????? 3:每個(gè)實(shí)例中對(duì)應(yīng)一個(gè)用于存儲(chǔ)key訪問信息的key,這樣可以統(tǒng)計(jì)更多的key。

??????????
??? 監(jiān)控視圖:通過上面的努力,我們可以形成三個(gè)視圖:
??? 第一:memcached 實(shí)例視圖,以某個(gè)具體cache實(shí)例為單位,呈現(xiàn)memcached服務(wù)本身所提供的統(tǒng)計(jì)信息,還包含此實(shí)例中包含了多少個(gè)分區(qū),即實(shí)例上包含了多少個(gè)項(xiàng)目使用的緩存。
??? 第二:分區(qū)視圖,根據(jù)分區(qū)名稱,集合所有節(jié)點(diǎn)的數(shù)據(jù),最終匯總出統(tǒng)計(jì)數(shù)據(jù),例如可以統(tǒng)計(jì)酒店項(xiàng)目總共使用了多少個(gè)key等,這對(duì)分析key的分布情況比較有幫助。
??? 第三:key視圖,呈現(xiàn)具體key的訪問信息,以及手工過期功能。

?

??? 總結(jié):上面的方案雖然能實(shí)現(xiàn)需求,但在實(shí)際生產(chǎn)環(huán)境中,盡量不要打開這種監(jiān)控功能,需要的時(shí)候再打開,盡量讓cache的效率最高。

?

原文來自:雨楓技術(shù)教程網(wǎng) http://www.fengfly.com
原文網(wǎng)址:http://www.fengfly.com/plus/view-197176-1.html

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/lzjsky/archive/2012/09/05/2671464.html

總結(jié)

以上是生活随笔為你收集整理的网站架构之缓存应用(摘录)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。