志當(dāng)存高遠(yuǎn),功到自然成!

          少年強則中國強,少年進(jìn)步則中國進(jìn)步!

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            53 Posts :: 2 Stories :: 2 Comments :: 0 Trackbacks

          2010年8月11日 #

          mysql 5.1支持觸發(fā)器以及自定義函數(shù)接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能夠?qū)崿F(xiàn)memcache的自動更新。簡單記錄一下安裝測試步驟。

            mysql 5.1支持觸發(fā)器以及自定義函數(shù)接口(UDF)的特性,如果配合libmemcache以及Memcached Functions for MySQL,就能夠?qū)崿F(xiàn)memcache的自動更新。簡單記錄一下安裝測試步驟。

            安裝步驟

            安裝memcached,這個步驟很簡單,隨處可見。安裝mysql server 5.1RC,安裝辦法也很大眾,不廢話 了。

            編譯libmemcached,解壓后安裝即可./configure; make; make install

            編譯Memcached Functions for MySQL,在http://download.tangent.org/找一個最新的版本下載就 是,./configure --with-mysql=/usr/local/mysql/bin/mysql_config -- libdir=/usr/local/mysql/lib/mysql/

            make

            make install

            接下來有兩個辦法讓Memcached Functions for MySQL在mysql中生效。

            在mysql的shell中執(zhí)行memcached_functions_mysql源碼目錄下的sql/install_functions.sql,這會 把memcache function作為UDF加入mysql。

            運行memcached_functions_mysql源碼目錄下的utils/install.pl,這是一個perl腳本,作用同上一 條。

            測試memcache function。

            以下測試腳本摘自memcached_functions_mysql的源碼目錄,有興趣可以試試。


          PLAIN TEXTCODE: drop table if exists urls;
          create table urls (
          id int(3) not null,
          url varchar(64) not null default '',
          primary key (id)
          );
          select memc_servers_set('localhost:11211');
          select memc_set('urls:sequence', 0);
          DELIMITER |
          DROP TRIGGER IF EXISTS url_mem_insert;
          CREATE TRIGGER url_mem_insert
          BEFORE INSERT ON urls
          FOR EACH ROW BEGIN
          SET NEW.id= memc_increment('urls:sequence');
          SET @mm= memc_set(concat('urls:',NEW.id), NEW.url);
          END |
          DELIMITER ;
          insert into urls (url) values ('http://google.com');
          insert into urls (url) values ('http://www.ooso.net/index.php');
          insert into urls (url) values ('http://www.ooso.net/');
          insert into urls (url) values ('http://slashdot.org');
          insert into urls (url) values ('http://mysql.com');
          select * from urls;
          select memc_get('urls:1');
          select memc_get('urls:2');
          select memc_get('urls:3');
          select memc_get('urls:4');
          select memc_get('urls:5');
          posted @ 2010-08-12 15:22 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(475) | 評論 (0)編輯 收藏

          假設(shè)我們有3臺memcached 服務(wù)器,server1 和server2 有3GB 的內(nèi)存空間,server3 有2GB 的內(nèi)存空間.
          下面程序說明怎么來創(chuàng)建客戶端.
          import com.danga.MemCached.*;

          public class MyClass {

          // 創(chuàng)建一個 memcached 客戶端對象

          protected static MemCachedClient mcc = new MemCachedClient();

          // 創(chuàng)建  memcached連接池

          static

          {  // 指定memcached服務(wù)地址 String[] servers =
          { "server1.mydomain.com:1121","server2.mydomain.com:1121",
          "server3.mydomain.com:1121" };
          // 指定memcached服務(wù)器負(fù)載量
          Integer[]  weights    ={ 3, 3, 2 };
          // 從連接池獲取一個連接實例

          SockIOPool pool = SockIOPool.getInstance();

          // 設(shè)置服務(wù)器和服務(wù)器負(fù)載量

          pool.setServers( servers );

          pool.setWeights( weights );

          // 設(shè)置一些基本的參數(shù)

          //設(shè)置初始連接數(shù)5   最小連接數(shù) 5   最大連接數(shù) 250

          //設(shè)置一個連接最大空閑時間6小時

          pool.setInitConn( 5 );

          pool.setMinConn( 5 );

          pool.setMaxConn( 250 );

          pool.setMaxIdle( 1000 * 60 * 60 * 6 );

          // 設(shè)置主線程睡眠時間

          // 每隔30秒醒來  然后

          // 開始維護(hù) 連接數(shù)大小

          pool.setMaintSleep( 30 );

          // 設(shè)置tcp 相關(guān)的樹形

          // 關(guān)閉nagle算法

          // 設(shè)置 讀取 超時3秒鐘  set the read timeout to 3 secs

          //  不設(shè)置連接超時

          pool.setNagle( false );

          pool.setSocketTO( 3000 );

          pool.setSocketConnectTO( 0 );

          // 開始初始化 連接池

          pool.initialize();

          // 設(shè)置壓縮模式

          //如果超過64k壓縮數(shù)據(jù)

          mcc.setCompressEnable( true );

          mcc.setCompressThreshold( 64 * 1024 );

          }

          public static void examples() {

          mcc.set( "foo", "This is a test String" );

          String bar = mcc.get( "foo" );

          }

          }
          MemCachedClient 類 常用的方法說明

          創(chuàng)建 client對象 設(shè)置參數(shù):

          MemCachedClient mc = new MemCachedClient();
          //壓縮模式
          mc.setCompressEnable(true);
          // 如果 cache數(shù)據(jù) 大于4 KB  就啟用壓縮
          mc.setCompressThreshold(4096);
          // 基本類型tostring方法
          // 通常不需要設(shè)置
          mc.setPrimitiveAsString(true);
          存儲一個對象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Object value = SomeClass.getObject();

          mc.set(key, value);
          用客戶端hashcode 存儲一個對象:


          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Object value = SomeClass.getObject();

          Integer hash = new Integer(45);

          mc.set(key, value, hash);

          set方法:在cache中存儲一個指定對象

             add 和replace 方法功能差不多

            add -- 如果不存在 這個key的對象,將會存儲一個對象到cache中
            replace --只有當(dāng)存在指定key對象的時候 會覆蓋已有對象
          刪除一個對象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          mc.delete(key);
          結(jié)合hashcode 刪除一個對象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "cacheKey1";

          Integer hash = new Integer(45);

          mc.delete(key, hashCode);
          怎么cache計數(shù),增 減計數(shù):

          MemCachedClient mc = new MemCachedClient();

          String key   = "counterKey";

          mc.storeCounter(key, new Integer(100));

          System.out.println("counter after adding      1: " mc.incr(key));

          System.out.println("counter after adding      5: " mc.incr(key, 5));

          System.out.println("counter after subtracting 4: " mc.decr(key, 4));

          System.out.println("counter after subtracting 1: " mc.decr(key));
          利用客戶端的hashcode存儲計數(shù) 增減 計數(shù):

          MemCachedClient mc = new MemCachedClient();

          String key   = "counterKey";

          Integer hash = new Integer(45);

          mc.storeCounter(key, new Integer(100), hash);

          System.out.println("counter after adding      1: " mc.incr(key, 1, hash));

          System.out.println("counter after adding      5: " mc.incr(key, 5, hash));

          System.out.println("counter after subtracting 4: " mc.decr(key, 4, hash));

          System.out.println("counter after subtracting 1: " mc.decr(key, 1, hash));
          獲取一個對象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Object value = mc.get(key);
          用客戶端hashcode獲取一個對象:

          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Integer hash = new Integer(45);

          Object value = mc.get(key, hash);
          MemCachedClient mc = new MemCachedClient();

          String key   = "key";

          Integer hash = new Integer(45);

          Object value = mc.get(key, hash);
          從cache 中獲取多個對象

          MemCachedClient mc = new MemCachedClient();

          String[] keys      ={ "key", "key1", "key2" };Mapvalues = mc.getMulti(keys);
          用客戶端hashcode 從cache中獲取多個對象
          MemCachedClient mc = new MemCachedClient();
          String[] keys      = { "key", "key1", "key2" };

          Integer[] hashes   =
          { new Integer(45), new Integer(32), new Integer(44) };
          Mapvalues = mc.getMulti(keys, hashes);
          清空所有的對象
          MemCachedClient mc = new MemCachedClient();

          mc.flushAll();
          得到服務(wù)器memcached的狀態(tài)信息
          MemCachedClient mc = new MemCachedClient();

          Map stats = mc.stats();
          注意點
          1:Failover/Failback
          當(dāng)一個memcached服務(wù)器失效的時候客戶端默認(rèn)會failover另一個服務(wù)去.

          如果失效的服務(wù)器 恢復(fù)運行,客戶端會返回到原來連接的服務(wù)器.
          如果你不想用這個功能 設(shè)置下面的參數(shù)
          pool.setFailover( false );
          pool.setFailback( false );

          2:序列化

          Boolean
          Byte
          String
          Character
          StringBuffer
          StringBuilder
          Short
          Long
          Double
          Float
          Date
          java默認(rèn)的類型沒有實現(xiàn)序列化 可以設(shè)置
          mcc.setPrimitiveAsString( true )替代.
          Meetup.com實踐過程中得出的一個經(jīng)驗 ,項目中model 對象implement Externalizable 實現(xiàn)序列化,
          可以節(jié)省cache 對象的大小。從而節(jié)省網(wǎng)絡(luò)帶寬和內(nèi)存空間。
          posted @ 2010-08-11 23:21 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(10777) | 評論 (1)編輯 收藏

          一:硬架構(gòu)

          1 :機房的選擇:

          在 選擇機房的時候,根據(jù)網(wǎng)站用戶的地域分布,可以選擇網(wǎng)通或電信機房,但更多時候,可能雙線機房才是合適的。越大的城市,機房價格越貴,從成本的角度看可以 在一些中小城市托管服務(wù)器,比如說廣州的公司可以考慮把服務(wù)器托管在東莞,佛山等地,不是特別遠(yuǎn),但是價格會便宜很多。

          2 :帶寬的大小:

          通常老板花錢請我們架構(gòu)網(wǎng)站的時候,會給我們提出一些目標(biāo),諸如網(wǎng)站每天要能承受100 萬PV 的訪問量等等。這時我們要預(yù)算一下大概需要多大的帶寬,計算帶寬大小主要涉及兩個指標(biāo)(峰值流量和頁面大小),我們不妨在計算前先做出必要的假設(shè):

          第一:假設(shè)峰值流量是平均流量的5 倍。
          第二:假設(shè)每次訪問平均的頁面大小是100K 字節(jié)左右。

          如果100 萬PV 的訪問量在一天內(nèi)平均分布的話,折合到每秒大約12 次訪問,如果按平均每次訪問頁面的大小是100K 字節(jié)左右計算的話,這12 次訪 問總計大約就是1200K 字節(jié),字節(jié)的單位是Byte ,而帶寬的單位是bit ,它們之間的關(guān)系是1Byte = 8bit ,所以1200K Byte 大致就相當(dāng)于9600K bit ,也就是9Mbps 的樣子,實際情況中,我們的網(wǎng)站必須能在峰值流量時保持正常訪問,所以按照假設(shè)的峰值流量算,真實帶寬的需求應(yīng)該在45Mbps  左右。

          當(dāng)然,這個結(jié)論是建立在前面提到的兩點假設(shè)的基礎(chǔ)上,如果你的實際情況和這兩點假設(shè)有出入,那么結(jié)果也會有差別。

          3 :服務(wù)器的劃分:

          先看我們都需要哪些服務(wù)器:圖片服務(wù)器,頁面服務(wù)器,數(shù)據(jù)庫服務(wù)器,應(yīng)用服務(wù)器,日志服務(wù)器等等。

          對于訪問量大點的網(wǎng)站而言,分離單獨的圖片服務(wù)器和頁面服務(wù)器相當(dāng)必要,我們可以用lighttpd 來跑圖片服務(wù)器,用apache 來跑頁面服務(wù) 器,當(dāng)然也可以選擇別的,甚至,我們可以擴展成很多臺圖片服務(wù)器和很多臺頁面服務(wù)器,并設(shè)置相關(guān)域名,如img.domain.com 和 www.domain.com ,頁面里的圖片路徑都使用絕對路徑,如<img src="http://img.domain.com/abc.gif" /> ,然后設(shè)置DNS 輪循,達(dá)到最初級的負(fù)載均衡。當(dāng)然,服務(wù)器多了就不可避免的涉及一個同步的問題,這個可以使用rsync 軟件來搞定。

          數(shù)據(jù)庫服務(wù)器是重中之重,因為網(wǎng)站的瓶頸問題十有八九是出在數(shù)據(jù)庫身上。現(xiàn)在一般的中小網(wǎng)站多使用MySQL 數(shù)據(jù)庫,不過它的集群功能似乎還沒有達(dá) 到stable 的階段,所以這里不做評價。一般而言,使用MySQL 數(shù)據(jù)庫的時候,我們應(yīng)該搞一個主從(一主多從)結(jié)構(gòu),主數(shù)據(jù)庫服務(wù)器使用innodb  表結(jié)構(gòu),從數(shù)據(jù)服務(wù)器使用myisam 表結(jié)構(gòu),充分發(fā)揮它們各自的優(yōu)勢,而且這樣的主從結(jié)構(gòu)分離了讀寫操作,降低了讀操作的壓力,甚至我們還可以設(shè)定一個專門的從服務(wù)器做備份服務(wù)器,方便備份。不然如果你只有一臺主服務(wù)器,在大數(shù)據(jù)量的情況下,mysqldump 基本就沒戲了,直接拷貝數(shù)據(jù)文件的話,還得先停止數(shù)據(jù)庫服務(wù)再拷貝,否則備份文件會出錯。但對于很多網(wǎng)站而言,即使數(shù)據(jù)庫服務(wù)僅停止了一秒也是不可接受的。如果你有了一臺從數(shù)據(jù)庫服務(wù)器,在備份數(shù) 據(jù)的時候,可以先停止服務(wù)(slave stop )再備份,再啟動服務(wù)(slave start )后從服務(wù)器會自動從主服務(wù)器同步數(shù)據(jù),一切都沒有影響。但是主從結(jié)構(gòu)也是有致命缺點的,那就是主從結(jié)構(gòu)只是降低了讀操作的壓力,卻不能降低寫操作的壓力。為了適應(yīng)更大的規(guī)模,可能只剩下最后這招了:橫向/ 縱向分割數(shù)據(jù)庫。所謂橫向分割數(shù)據(jù)庫,就是把不同的表保存到不同的數(shù)據(jù)庫服務(wù)器上,比如說用戶表保存在A 數(shù)據(jù)庫服務(wù)器上,文章表保存在B 數(shù)據(jù)庫服務(wù)器上,當(dāng)然這樣的分割是有代價的,最基本的就是你沒法進(jìn)行LEFT JOIN 之類的操作了。所謂縱向分割數(shù)據(jù)庫,一般是指按照用戶標(biāo)識(user_id )等來劃分?jǐn)?shù)據(jù)存儲的服務(wù)器,比如說:我們有5 臺數(shù)據(jù)庫服務(wù)器,那么 “user_id % 5 + 1” 等于1 的就保存到1 號服務(wù)器,等于2 的就保存到2 好服務(wù)器,以此類推,縱向分隔的原則有很多種,可以視情況選擇。不過和橫向分割數(shù)據(jù)庫一樣,縱向分割 數(shù)據(jù)庫也是有代價的,最基本的就是我們在進(jìn)行如COUNT, SUM 等匯總操作的時候會麻煩很多。綜上所述,數(shù)據(jù)庫服務(wù)器的解決方案一般視情況往往是一個混合的方案,以其發(fā)揮各種方案的優(yōu)勢,有時候還需要借助 memcached 之類的第三方軟件,以便適應(yīng)更大訪問量的要求。

          如果有專門的應(yīng)用服務(wù)器來跑PHP 腳本是最合適不過的了,那樣我們的頁面服務(wù)器只保存靜態(tài)頁面就可以了,可以給應(yīng)用服務(wù)器設(shè)置一些諸如 app.domain.com 之類的域名來和頁面服務(wù)器加以區(qū)別。對于應(yīng)用服務(wù)器,我還是更傾向于使用prefork 模式的apache ,配上必要的 xcache 之類的PHP 緩存軟件,加載模塊要越少越好,除了mod_rewrite 等必要的模塊,不必要的東西統(tǒng)統(tǒng)舍棄,盡量減少httpd 進(jìn)程的內(nèi)存消耗,而那些圖片服務(wù)器,頁面服務(wù)器等靜態(tài)內(nèi)容就可以使用lighttpd 或者tux 來搞,充分發(fā)揮各種服務(wù)器的特點。

          如果條件允許,獨立的日志服務(wù)器也是必要的,一般小網(wǎng)站的做法都是把頁面服務(wù)器和日志服務(wù)器合二為一了,在凌晨訪問量不大的時候cron 運行前一天 的日志計算,不過如果你使用awstats 之類的日志分析軟件,對于百萬級訪問量而言,即使按天歸檔,也會消耗很多時間和服務(wù)器資源去計算,所以分離單獨的日志服務(wù)器還是有好處的,這樣不會影響正式服務(wù)器的工作狀態(tài)。

          二:軟架構(gòu)

          1 :框架的選擇:

          現(xiàn)在的PHP 框架有很多選擇,比如:CakePHP ,Symfony ,Zend Framework 等等,至于應(yīng)該使用哪一個并沒有唯一的答案,要根據(jù)Team 里團(tuán)隊成員對各個框架的了解程度而定。很多時候,即使沒有使用框架,一樣能寫出好的程序來,比如Flickr 據(jù)說就是用Pear+Smarty 這樣的類庫寫出來的,所以是否用框架,用什么框架,一般不是最重要,重要的是我們的編程思想里要有框架的意識。

          現(xiàn)在的.NET 框架有很多選擇,比如:cnForums ,.text ,cs, Castle, 等等

          2 :邏輯的分層:

          網(wǎng)站規(guī)模到了一定的程度之后,代碼里各種邏輯糾纏在一起,會給維護(hù)和擴展帶來巨大的障礙,這時我們的解決方式其實很簡單,那就是重構(gòu),將邏輯進(jìn)行分層。通常,自上而下可以分為表現(xiàn)層,應(yīng)用層,領(lǐng)域?qū)樱志脤印?/font>

          所 謂表現(xiàn)層,并不僅僅就指模板,它的范圍要更廣一些,所有和表現(xiàn)相關(guān)的邏輯都應(yīng)該被納入表現(xiàn)層的范疇。比如說某處的字體要顯示為紅色,某處的開頭要空兩格, 這些都屬于表現(xiàn)層。很多時候,我們?nèi)菀追傅腻e誤就是把本屬于表現(xiàn)層的邏輯放到了其他層面去完成,這里說一個很常見的例子:我們在列表頁顯示文章標(biāo)題的時 候,都會設(shè)定一個最大字?jǐn)?shù),一旦標(biāo)題長度超過了這個限制,就截斷,并在后面顯示“..” ,這就是最典型的表現(xiàn)層邏輯,但是實際情況,有很多程序員都是在非表現(xiàn)層代碼里完成數(shù)據(jù)的獲取和截斷,然后賦值給表現(xiàn)層模板,這樣的代碼最直接的缺點就是同樣一段數(shù)據(jù),在這個頁面我可能想顯示前10 個字,再另一個 頁面我可能想顯示前15 個字,而一旦我們在程序里固化了這個字?jǐn)?shù),也就喪失了可移植性。正確的做法是應(yīng)該做一個視圖助手之類的程序來專門處理此類邏輯,比如說:Smarty 里的truncate 就屬于這樣的視圖助手(不過它那個實現(xiàn)不適合中文)。

          所謂應(yīng)用層,它的主要作用是定義用戶可以做什么,并把操作結(jié)果反饋給表現(xiàn)層。至于如何做,通常不是它的職責(zé)范圍(而是領(lǐng)域?qū)拥穆氊?zé)范圍),它會通過委派把如何做的工作交給領(lǐng)域?qū)尤ヌ幚怼T谑褂肕VC 架構(gòu)的網(wǎng)站中,我們可以看到類似下面這樣的URL :domain.com/articles/view/123 ,其內(nèi)部編碼實現(xiàn),一般就是一個Articles 控制器類,里面有一個view 方法,這就是一 個典型的應(yīng)用層操作,因為它定義了用戶可以做一個查看的動作。在MVC 架構(gòu)中,有一個準(zhǔn)則是這么說的:Rich Model Is Good 。言外之意,就是Controller 要保持“ 瘦” 一些比較好,進(jìn)而說明應(yīng)用層要盡量簡單,不要包括涉及領(lǐng)域內(nèi)容的邏輯。

          所謂領(lǐng)域?qū)樱钪苯拥慕忉尵褪前I(lǐng)域邏輯的層。它是一個軟件的靈魂所在。先來看看什么叫領(lǐng)域邏輯,簡單的說,具有明確的領(lǐng)域概念的邏輯就是領(lǐng)域邏輯,比如我們在ATM 機上取錢,過程大致是這樣的:插入銀聯(lián)卡,輸入密碼,輸入取款金額,確定,拿錢,然后ATM 吐出一個交易憑條。在這個過程中,銀聯(lián)卡 在ATM 機器里完成錢從帳戶上劃撥的過程就是一個領(lǐng)域邏輯,因為取錢在銀行中是一個明確的領(lǐng)域概念,而ATM 機吐出一個交易憑條則不是領(lǐng)域邏輯,而僅是一 個應(yīng)用邏輯,因為吐出交易憑條并不是銀行中一個明確的領(lǐng)域概念,只是一種技術(shù)手段,對應(yīng)的,我們?nèi)″X后不吐交易憑條,而發(fā)送一條提醒短信也是可能的,但并 不是一定如此,如果在實際情況中,我們要求取款后必須吐出交易憑條,也就是說吐出交易憑條已經(jīng)和取款緊密結(jié)合,那么你也可以把吐出交易憑條看作是領(lǐng)域邏輯 的一部分,一切都以問題的具體情況而定。在Eric 那本經(jīng)典的領(lǐng)域驅(qū)動設(shè)計中,把領(lǐng)域?qū)臃譃榱宋宸N基本元素:實體,值對象,服務(wù),工廠,倉儲。具體可以參 閱書中的介紹。領(lǐng)域?qū)幼畛7傅腻e誤就是把本應(yīng)屬于領(lǐng)域?qū)拥倪壿嬓孤兜搅似渌麑哟危热缯f在一個CMS 系統(tǒng),對熱門文章的定義是這樣的:每天被瀏覽的次數(shù)多 于1000 次,被評論的次數(shù)多于100 次,這樣的文章就是熱門文章。對于一個CMS 來說,熱門文章這個詞無疑是一個重要的領(lǐng)域概念,那么我們?nèi)绾螌崿F(xiàn)這個邏輯的設(shè)計的?你可能會給出類似下面的代碼:“SELECT ... FROM ... WHERE  瀏覽 > 1000 AND  評論 > 100” ,沒錯,這是最簡單的實現(xiàn)方式,但是這里需要注意的是“ 每天被瀏覽的次數(shù)多于1000 次,被評論的次數(shù)多于100 次” 這個重要的領(lǐng)域邏輯被隱藏到了SQL 語句中,SQL 語句顯然不屬于領(lǐng)域?qū)拥姆懂牐簿褪钦f,我們的領(lǐng)域邏輯泄露了。

          所謂持久層,就是指把我們的領(lǐng)域模型保存到數(shù)據(jù)庫中。因為我們的程序代碼是面向?qū)ο箫L(fēng)格的,而數(shù)據(jù)庫一般是關(guān)系型的數(shù)據(jù)庫,所以我們需要把領(lǐng)域模型 碾平,才能保存到數(shù)據(jù)庫中,但是在 PHP 里,直到目前還沒有非常好的 ORM 出現(xiàn),所以這方面的解決方案不是特別多,參考 Martin 的企業(yè)應(yīng)用架構(gòu)模式一   書,大致可以使用的方法有行數(shù)據(jù)入口( Row Data Gateway )或者表數(shù)據(jù)入口( Table Data Gateway),或者把領(lǐng)域?qū)雍统志脤雍隙橐蛔兂苫顒佑涗洠ˋctive Record)的方式。

          posted @ 2010-08-11 14:32 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(433) | 評論 (0)編輯 收藏

          TOMCAT崩潰事件

          http://www.aygfsteel.com/tedeyang/archive/2008/06/04/205740.html

          今天一大早產(chǎn)品一部項目經(jīng)理就來找我,他們的一臺服務(wù)器昨天晚上tomcat服務(wù)崩潰,還不能重啟服務(wù),最后將服務(wù)器重啟才OK。
          我將事件過程和分析過程記錄如下:

          服務(wù)器:win 2000 sp4,apache 2 + tomcat 5.0 采用mod_jk級聯(lián)。內(nèi)存2G,硬盤剩余空間充足,CPU基本空閑。
          主要應(yīng)用:J2EE 1.4,JDBC(連接另一臺mysql服務(wù)器)
          崩潰時間: 2008-6-3 18:37:50

          一.各種日志綜合如下:

             1.37分45秒,操作系統(tǒng)事件中諾頓殺毒軟件報內(nèi)存過低警報
             2.37分45秒,web應(yīng)用拋出JDBC連接異常:

          2008-06-03 18:37:45 cn.*.db.DBManager.getConnection(DBManager.java:157) ERROR swim.db.DBManager   com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception:
          ** BEGIN NESTED EXCEPTION **
          java.net.SocketException
          MESSAGE: java.net.SocketException: No buffer 
          space available (maximum connections reached?): JVM_Bind


             3.37分50秒,tomcat拋出session無法save異常:

          2008-06-03 18:37:50 ERROR- IOException while saving persisted sessions: java.io.FileNotFoundException: "izzs"SESSIONS.ser (系統(tǒng)資源不足,無法完成請求的服務(wù)。)
          java.io.FileNotFoundException: "izzs"SESSIONS.ser (系統(tǒng)資源不足,無法完成請求的服務(wù)。)
              at java.io.FileOutputStream.open(Native Method)
              at java.io.FileOutputStream.
          <init>(FileOutputStream.java:179)
              at java.io.FileOutputStream.
          <init>(FileOutputStream.java:70)
              at org.apache.catalina.session.StandardManager.doUnload(StandardManager.java:
          511)
              at org.apache.catalina.session.StandardManager.unload(StandardManager.java:
          485)
              at org.apache.catalina.session.StandardManager.stop(StandardManager.java:
          687)
              at org.apache.catalina.core.StandardContext.stop(StandardContext.java:
          4496)
              at org.apache.catalina.core.StandardContext.reload(StandardContext.java:
          3037)
              at org.apache.catalina.core.StandardContext.backgroundProcess(StandardContext.java:
          4658)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1619)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1628)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:
          1628)
              at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:
          1608)
              at java.lang.Thread.run(Thread.java:
          534)


           

          二.簡單分析

          崩潰原因:內(nèi)存不足導(dǎo)致資源不足,引起Tomcat的session崩潰。
            這臺服務(wù)器上運行著很多應(yīng)用,是什么原因引起內(nèi)存不足還無法確定。
          初步判斷罪魁禍?zhǔn)卓赡苁莂pache,該進(jìn)程平常占用500MB內(nèi)存,經(jīng)常會飚到1G以上。

          Apache2的配置文件中:KeepAlive=On,MaxKeepAliveRequests=100,KeepAliveTimeout=15,分析aceess.log文件可以發(fā)現(xiàn)每個頁面觸發(fā)的request數(shù)量在10個以下,點擊率較低,可能使連接過多。
          我建議將keepAlive設(shè)為off,增加CPU負(fù)載,降低內(nèi)存消耗。

          三.效果

           有待觀察......

          參考資料:
          http://www.withend.com/post/78.html

          四.結(jié)局 
          時隔一天,晚上九點再次崩潰,黑暗事件重演。
          這一次,我才得知原來該apache還配置有其他域名,于是調(diào)出該域名下的access.log。項目經(jīng)理去了機房,在轟轟地風(fēng)扇聲中打電話給我,讓我分析分析。
          仔細(xì)看訪問日志,發(fā)現(xiàn)原來有N多Connect 443連接,443是什么?是SSL端口!HTTPS!,Connect命令則顯然是代理功能!
          而且這些connect的IP來自全球各地,加拿大、美國、澳洲、新西蘭、北京、上海、英國、哪都有。
          看來這臺服務(wù)器是被人當(dāng)代理服務(wù)器用了。
          怪不得半夜會死機,人家西半球那時正大白天撒歡兒呢。

          問題就出在apache的配置上,由于應(yīng)用眾多,并且這臺服務(wù)器還是其他幾臺web服務(wù)器的對外出口,因此apache中配置了反向代理,不過不小心把正向代理(mod_proxy模塊的ProxyRequests指令)也打開了。
          看看apache2.0的官方文檔中mod_proxy部分,里面明明白白寫著:

          警告
          在您沒有對服務(wù)器采取安全措施之前,請不要用ProxyRequests啟用您的代理。一個開放的代理服務(wù)器不僅對您的網(wǎng)絡(luò)有威脅,對整個因特網(wǎng)來說也同樣如此。
          真的是很有威脅!大量代理請求急劇消耗內(nèi)存,最終造成死機!

          解決辦法就是把正向代理關(guān)掉:ProxyRequests Off
          posted @ 2010-08-11 14:25 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(2036) | 評論 (0)編輯 收藏

          分布式緩存系統(tǒng)Memcached簡介與實踐

          http://blog.csdn.net/hitman9099/archive/2008/09/04/2878417.aspx

           

          緣起: 在數(shù)據(jù)驅(qū)動的web開發(fā)中,經(jīng)常要重復(fù)從數(shù)據(jù)庫中取出相同的數(shù)據(jù),這種重復(fù)極大的增加了數(shù)據(jù)庫負(fù)載。緩存是解決這個問題的好辦法。但是ASP.NET中的雖然已經(jīng)可以實現(xiàn)對頁面局部進(jìn)行緩存,但還是不夠靈活。此時Memcached或許是你想要的。

          Memcached是什么?
          Memcached是由Danga Interactive開發(fā)的,高性能的,分布式的內(nèi)存對象緩存系統(tǒng),用于在動態(tài)應(yīng)用中減少數(shù)據(jù)庫負(fù)載,提升訪問速度。

          Memcached能緩存什么?
          通過在內(nèi)存里維護(hù)一個統(tǒng)一的巨大的hash表,Memcached能夠用來存儲各種格式的數(shù)據(jù),包括圖像、視頻、文件以及數(shù)據(jù)庫檢索的結(jié)果等。

          Memcached快么?

          非 常快。Memcached使用了libevent(如果可以的話,在linux下使用epoll)來均衡任何數(shù)量的打開鏈接,使用非阻塞的網(wǎng)絡(luò)I/O,對 內(nèi)部對象實現(xiàn)引用計數(shù)(因此,針對多樣的客戶端,對象可以處在多樣的狀態(tài)), 使用自己的頁塊分配器和哈希表, 因此虛擬內(nèi)存不會產(chǎn)生碎片并且虛擬內(nèi)存分配的時間復(fù)雜度可以保證為O(1).。

          Danga Interactive為提升Danga Interactive的速度研發(fā)了Memcached。目前,LiveJournal.com每天已經(jīng)在向一百萬用戶提供多達(dá)兩千萬次的頁面訪問。而這 些,是由一個由web服務(wù)器和數(shù)據(jù)庫服務(wù)器組成的集群完成的。Memcached幾乎完全放棄了任何數(shù)據(jù)都從數(shù)據(jù)庫讀取的方式,同時,它還縮短了用戶查看 頁面的速度、更好的資源分配方式,以及Memcache失效時對數(shù)據(jù)庫的訪問速度。

          Memcached的特點
          Memcached的緩存是一種分布式的,可以讓不同主機上的多個用戶同時訪問, 因此解決了共享內(nèi)存只能單機應(yīng)用的局限,更不會出現(xiàn)使用數(shù)據(jù)庫做類似事情的時候,磁盤開銷和阻塞的發(fā)生。

          Memcached的使用 
           
          Memcached服務(wù)器端的安裝 (此處將其作為系統(tǒng)服務(wù)安裝)
          下載文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
              1 解壓縮文件到c:\memcached
             2 命令行輸入 'c:\memcached\memcached.exe -d install' 
              3 命令行輸入 'c:\memcached\memcached.exe -d start' ,該命令啟動 Memcached ,默認(rèn)監(jiān)聽端口為 11211
          通過 memcached.exe -h 可以查看其幫助

           

          一個簡單的測試?yán)?/p>

          1. package com.mapbar.util.cache;

          2. import java.util.Date;
          3. import java.util.ResourceBundle;

          4. import com.danga.MemCached.MemCachedClient;
          5. import com.danga.MemCached.SockIOPool;
          6. /**
          7.  * 使用配置文件方式的memcache組件
          8.  *
          9.  */
          10. public class Cache {

          11.  protected static ResourceBundle rb=ResourceBundle.getBundle("memcached");;
          12.  public static MemCachedClient mcc = new MemCachedClient(); 
          13.  static {
          14.   init();
          15.  }     
          16.  public static void init(){
          17.   synchronized (mcc) {  
          18.    System.out.println("init call");
          19.    String[] servers =rb.getString("cache.servers").split(",");       
          20.          
          21.          String[] strWeights =rb.getString("cache.weights").split(",");  
          22.          Integer[] weights = new Integer[strWeights.length];
          23.          for(int i=0;i<strWeights.length;i++){
          24.           weights[i]=Integer.parseInt(strWeights[i]);
          25.          }
          26.         
          27.          //創(chuàng)建一個實例對象SockIOPool     
          28.          SockIOPool pool = SockIOPool.getInstance();       
          29.         
          30.          // set the servers and the weights    
          31.          //設(shè)置Memcached Server    
          32.          pool.setServers( servers );       
          33.          pool.setWeights( weights );       
          34.          pool.setInitConn(Integer.parseInt(rb.getString("cache.initConn")));       
          35.          pool.setMinConn(Integer.parseInt(rb.getString("cache.minConn")));       
          36.          pool.setMaxConn(Integer.parseInt(rb.getString("cache.maxConn")));       
          37.          pool.setMaxIdle(Long.parseLong(rb.getString("cache.maxIdle")));       
          38.         
          39.          // set the sleep for the maint thread       
          40.          // it will wake up every x seconds and       
          41.          // maintain the pool size       
          42.          pool.setMaintSleep( 30 );       
          43.         
          44. //         Tcp的規(guī)則就是在發(fā)送一個包之前,本地機器會等待遠(yuǎn)程主機    
          45. //         對上一次發(fā)送的包的確認(rèn)信息到來;這個方法就可以關(guān)閉套接字的緩存,    
          46. //         以至這個包準(zhǔn)備好了就發(fā);    
          47.          pool.setNagle( false );       
          48.          //連接建立后對超時的控制    
          49.          pool.setSocketTO( 3000 );    
          50.          //連接建立時對超時的控制    
          51.          pool.setSocketConnectTO( 0 );       
          52.         
          53.          // initialize the connection pool       
          54.          //初始化一些值并與MemcachedServer段建立連接    
          55.          pool.initialize();    

          56.          // lets set some compression on for the client       
          57.          // compress anything larger than 64k       
          58.          mcc.setCompressEnable( true );       
          59.          mcc.setCompressThreshold( 64 * 1024 );  
          60.   }
          61.  }
          62.  protected static void bulidCache(){  
          63.   
          64.         //set(key,value,Date) ,Date是一個過期時間,如果想讓這個過期時間生效的話,這里傳遞的new Date(long date) 中參數(shù)date,需要是個大于或等于1000的值。    
          65.         //因為java client的實現(xiàn)源碼里是這樣實現(xiàn)的 expiry.getTime() / 1000 ,也就是說,如果 小于1000的值,除以1000以后都是0,即永不過期    
          66.         mcc.set( "test""This is a test String" ,new Date(100000));   //十秒后過期    
          67.               
          68.     }       
          69.       
          70.  protected static void output() {       
          71.         //從cache里取值    
          72.         String value = (String) mcc.get( "test" );       
          73.         System.out.println(value);        
          74.     }       
          75.            
          76.  public static void main(String[] args){       
          77.         bulidCache();      
          78.         output();           
          79.     }        

          80. }


          其中在classespath下有個memcached.properties文件

          內(nèi)容如下:

          ##muti servers spilt by ,

          #這里是你的memcached啟動的地址
          cache.servers=192.168.0.116:11211  
          cache.weights=1
          #memcached be used
          cache.cluster=true

          #set some basic pool settings       
          #5 initial, 5 min, and 250 max conns       
          #and set the max idle time for a conn       
          #to 6 hours  6*60*60*1000
          cache.initConn=5
          cache.minConn=5
          cache.maxConn=250
          cache.maxIdle=21600000

           

           

           

           

          在Windows下安裝Memcached

          http://www.oschina.net/docs/article/4

          很多phper不知道如何在Windows下搭建Memcache的開發(fā)調(diào)試環(huán)境,最近個人也在研究Memcache,記錄下自己安裝搭建的過程。
          其實我開始研究Memcache的時候并不知道居然還有memcached for Win32這個鳥東西,害得我在CnetOS下折騰1天才搞定,今天突然發(fā)現(xiàn)Windows下的Memcache進(jìn)行開發(fā)調(diào)試完全沒有問題,所以寫篇 Memcache的文檔分享給大家。

          Windows下的Memcache安裝
          1. 下載memcache的 windows穩(wěn)定版,解壓放某個盤下面,比如在c:\memcached
          2. 在終端(也即cmd命令界面)下輸入 ‘c:\memcached\memcached.exe -d install’ 安裝
          3. 再輸入: ‘c:\memcached\memcached.exe -d start’ 啟動。NOTE: 以后memcached將作為windows的一個服務(wù)每次開機時自動啟動。這樣服務(wù)器端已經(jīng)安裝完畢了。
          4.下載php_memcache.dll, 請自己查找對應(yīng)的php版本的文件
          5. 在C:\winnt\php.ini 加入一行 ‘extension=php_memcache.dll’
          6.重新啟動Apache,然后查看一下phpinfo,如果有memcache,那么就說明安裝成功!

          memcached的基本設(shè)置

          -p 監(jiān)聽的端口
          -l 連接的IP地址, 默認(rèn)是本機
          -d start 啟動memcached服務(wù)
          -d restart 重起memcached服務(wù)
          -d stop|shutdown 關(guān)閉正在運行的memcached服務(wù)
          -d install 安裝memcached服務(wù)
          -d uninstall 卸載memcached服務(wù)
          -u 以的身份運行 (僅在以root運行的時候有效)
          -m 最大內(nèi)存使用,單位MB。默認(rèn)64MB
          -M 內(nèi)存耗盡時返回錯誤,而不是刪除項
          -c 最大同時連接數(shù),默認(rèn)是1024
          -f 塊大小增長因子,默認(rèn)是1.25
          -n 最小分配空間,key+value+flags默認(rèn)是48
          -h 顯示幫助

          Memcache環(huán)境測試
          運行下面的php文件,如果有輸出This is a test!,就表示環(huán)境搭建成功。開始領(lǐng)略Memcache的魅力把!
          < ?php
          $mem = new Memcache;
          $mem->connect(”127.0.0.1″, 11211);
          $mem->set(’key’, ‘This is a test!’, 0, 60);
          $val = $mem->get(’key’);
          echo $val;
          ?>

          posted @ 2010-08-11 14:22 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(466) | 評論 (0)編輯 收藏

          日志原文:http://j2ee.blog.sohu.com/70343632.html   
          memcache for win 軟件主頁:http://jehiah.cz/projects/memcached-win32/  
          http://labs.northscale.com/memcached-packages/
          meecache for liunx 軟件主頁:http://memcached.org/  
                                               
          最近一直在做一個項目的前期設(shè)計工作,考慮到后期系統(tǒng)的擴展和性能問題也找了很多解決方法,有一個就是用到了數(shù)據(jù)庫的緩存工具memcached(當(dāng)然該工具并不僅僅局限于數(shù)據(jù)庫的緩存)。先簡單的介紹下什么是memcached。

              Memcached是高性能的,分布式的內(nèi)存對象緩存系統(tǒng),用于在動態(tài)應(yīng)用中減少數(shù)據(jù)庫負(fù) 載,提升訪問速度。Memcached由Danga Interactive開發(fā),用于提升LiveJournal.com訪問速度的。LJ每秒動態(tài)頁面訪問量幾千次,用戶700萬。Memcached將數(shù) 據(jù)庫負(fù)載大幅度降低,更好的分配資源,更快速訪問。

              上網(wǎng)baidu了很多東西,幾乎都差不多,而且基于java的說的很少,所有只有在研究了各個其他語言類的應(yīng)用后再來嘗試在java上進(jìn)行簡單的操作應(yīng) 用。先從memcached上進(jìn)行說明,memcached的最新版是采用c語言進(jìn)行開發(fā)和設(shè)計的,據(jù)說舊版的是采用perl語言開發(fā)的,而且它是一個應(yīng) 用軟件來的,是作為緩存服務(wù)器的服務(wù)器端運行在服務(wù)器上的,需要使用特定的語言編寫客戶端與其進(jìn)行通信來進(jìn)行數(shù)據(jù)的緩存和獲取。通常我們是把 memcached安裝運行在web服務(wù)器上,然后通過對需要的數(shù)據(jù)進(jìn)行緩存,據(jù)我目前所知,所有數(shù)據(jù)的緩存設(shè)置和存取操作,以及數(shù)據(jù)的更新后替換操作全 部需要程序來進(jìn)行,而不是自動進(jìn)行的(自動不知道能不能成功,呵呵)。下面從一個實際的例子來應(yīng)用memcached。

              首先到http://danga.com/memcached/下 載memcached的windows版本和java客戶端jar包,目前最新版本是memcached-1.2.1-win32.zip和 java_memcached-release_1.6.zip,分別解壓后即可!首先是安裝運行memcached服務(wù)器,我們將memcached- 1.2.1-win32.zip解壓后,進(jìn)入其目錄,然后運行如下命令:

          c:>memcached.exe -d install
          c:>memcached.exe -l 127.0.0.1 -m 32 -d start

              第一行是安裝memcached成為服務(wù),這樣才能正常運行,否則運行失敗!第一行是啟動memcached的,作為測試我們就簡單的只分配32M內(nèi)存 了,然后監(jiān)聽本機端口和以守護(hù)進(jìn)行運行。執(zhí)行完畢后,我們就可以在任務(wù)管理器中見到memcached.exe這個進(jìn)程了。好了,我們的服務(wù)器已經(jīng)正常運 行了, 下面我們就來寫java的客戶端連接程序。

              我們將java_memcached-release_1.6.zip解壓后的目錄中的java_memcached-release_1.6.jar文件復(fù)制到j(luò)ava項目的lib目錄下,然后我們來編寫代碼,比如我提供的一個應(yīng)用類如下:

          package utils.cache;

          import java.util.Date;

          import com.danga.MemCached.MemCachedClient;
          import com.danga.MemCached.SockIOPool;


          /**
          * 使用memcached的緩存實用類.
          *
          *
          @author 鐵木箱子
          *
          */
          public class MemCached
          {
             
          // 創(chuàng)建全局的唯一實例
              protected static MemCachedClient mcc = new MemCachedClient();
             
             
          protected static MemCached memCached = new MemCached();
             
             
          // 設(shè)置與緩存服務(wù)器的連接池
              static {
                 
          // 服務(wù)器列表和其權(quán)重
                  String[] servers = {"127.0.0.1:11211"};
                  Integer[] weights
          = {3};

                 
          // 獲取socke連接池的實例對象
                  SockIOPool pool = SockIOPool.getInstance();

                 
          // 設(shè)置服務(wù)器信息
                  pool.setServers( servers );
                  pool.setWeights( weights );

                 
          // 設(shè)置初始連接數(shù)、最小和最大連接數(shù)以及最大處理時間
                  pool.setInitConn( 5 );
                  pool.setMinConn(
          5 );
                  pool.setMaxConn(
          250 );
                  pool.setMaxIdle(
          1000 * 60 * 60 * 6 );

                 
          // 設(shè)置主線程的睡眠時間
                  pool.setMaintSleep( 30 );

                 
          // 設(shè)置TCP的參數(shù),連接超時等
                  pool.setNagle( false );
                  pool.setSocketTO(
          3000 );
                  pool.setSocketConnectTO(
          0 );

                 
          // 初始化連接池
                  pool.initialize();

                 
          // 壓縮設(shè)置,超過指定大小(單位為K)的數(shù)據(jù)都會被壓縮
                  mcc.setCompressEnable( true );
                  mcc.setCompressThreshold(
          64 * 1024 );
              }
             
             
          /**
               * 保護(hù)型構(gòu)造方法,不允許實例化!
               *
              
          */
             
          protected MemCached()
              {
                 
              }
             
             
          /**
               * 獲取唯一實例.
               *
          @return
              
          */
             
          public static MemCached getInstance()
              {
                 
          return memCached;
              }
             
             
          /**
               * 添加一個指定的值到緩存中.
               *
          @param key
               *
          @param value
               *
          @return
              
          */
             
          public boolean add(String key, Object value)
              {
                 
          return mcc.add(key, value);
              }
             
             
          public boolean add(String key, Object value, Date expiry)
              {
                 
          return mcc.add(key, value, expiry);
              }
             
             
          public boolean replace(String key, Object value)
              {
                 
          return mcc.replace(key, value);
              }
             
             
          public boolean replace(String key, Object value, Date expiry)
              {
                 
          return mcc.replace(key, value, expiry);
              }
             
             
          /**
               * 根據(jù)指定的關(guān)鍵字獲取對象.
               *
          @param key
               *
          @return
              
          */
             
          public Object get(String key)
              {
                 
          return mcc.get(key);
              }
             
             
          public static void main(String[] args)
              {
                  MemCached cache
          = MemCached.getInstance();
                  cache.add(
          "hello", 234);
                  System.out.print(
          "get value : " + cache.get("hello"));
              }
          }

              那么我們就可以通過簡單的像main方法中操作的一樣存入一個變量,然后再取出進(jìn)行查看,我們可以看到先調(diào)用了add,然后再進(jìn)行g(shù)et,我們運行一次 后,234這個值已經(jīng)被我們存入了memcached的緩存中的了,我們將main方法中紅色的那一行注釋掉后,我們再運行還是可以看到get到的 value也是234,即緩存中我們已經(jīng)存在了數(shù)據(jù)了。

              對基本的數(shù)據(jù)我們可以操作,對于普通的POJO而言,如果要進(jìn)行存儲的話,那么比如讓其實現(xiàn)java.io.Serializable接口,因為 memcached是一個分布式的緩存服務(wù)器,多臺服務(wù)器間進(jìn)行數(shù)據(jù)共享需要將對象序列化的,所以必須實現(xiàn)該接口,否則會報錯的。比如我們寫一個簡單的測 試Bean如下:

          class TBean implements java.io.Serializable
          {
             
          private static final long serialVersionUID = 1945562032261336919L;
             
             
          private String name;

             
          public String getName()
              {
                 
          return name;
              }

             
          public void setName(String name)
              {
                 
          this.name = name;
              }
          }

              然后我們在main方法中加入如下幾行代碼:

          TBean tb = new TBean();
          tb.setName(
          "鐵木箱子");
          cache.add(
          "bean", tb);
          TBean tb1
          = (TBean)cache.get("bean");
          System.out.print(
          "name=" + tb1.getName());
          tb1.setName(
          "鐵木箱子_修改的");
          tb1
          = (TBean)cache.get("bean");
          System.out.print(
          "name=" + tb1.getName());

              我們首先把TBean的一個實例放入緩存中,然后再取出來,并進(jìn)行名稱的修改,然后我們再取這個對象,我們再看其名稱,發(fā)現(xiàn)修改的對象并不是緩存中的對 象,而是通過序列化過來的一個實例對象,這樣我們就無須擔(dān)心對原生類的無意修改導(dǎo)致緩存數(shù)據(jù)失效了,呵呵~~看來我也是多此一想啊。所以這表明從緩存中獲 取的對象是存入對象的一個副本,對獲取對象的修改并不能真正的修改緩存中的數(shù)據(jù),而應(yīng)該使用其提供的replace等方法來進(jìn)行修改。

              以上是我在windows下對memcached的一點小學(xué)習(xí)和實踐,在以后的項目開發(fā)過程中將會更深入的學(xué)習(xí)和應(yīng)用這一緩存工具,也希望和有興趣的同行一起討論學(xué)習(xí)該工具的使用~~ 微笑


          posted @ 2010-08-11 13:51 存鷹之心于高遠(yuǎn),取鷹之志而凌云,習(xí)鷹之性以涉險,融鷹之神在山巔. 閱讀(769) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 太谷县| 四川省| 巴楚县| 厦门市| 高碑店市| 久治县| 竹溪县| 墨玉县| 临汾市| 阜宁县| 常熟市| 宣恩县| 平顶山市| 福海县| 特克斯县| 沙湾县| 襄垣县| 苏尼特右旗| 平江县| 海林市| 乐亭县| 聂拉木县| 英德市| 张家口市| 彭州市| 克东县| 富民县| 淮安市| 金塔县| 石城县| 琼结县| 彰武县| 淮滨县| 囊谦县| 巴林左旗| 金门县| 来宾市| 萨迦县| 比如县| 皋兰县| 琼中|