心有多大舞臺便有多大

          Embrace changes, pursue excellence, share niceness.

          導(dǎo)航

          <2008年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          留言簿(6)

          隨筆分類(82)

          隨筆檔案(94)

          文章分類(21)

          文章檔案(18)

          相冊

          收藏夾(36)

          好書推薦

          技術(shù)文章

          朋友的博客

          架構(gòu)

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          hessian序列化協(xié)議+memcached的緩存存取

          大名鼎鼎的memcached恐怕沒人不知道吧!hessian是一種遠(yuǎn)程調(diào)用的機制,類似與web service,不過它是使用自己的序列化協(xié)議.
          那么,為什么要把hessian的序列化協(xié)議和memcached結(jié)合起來實現(xiàn)緩存的讀取呢?
          有過使用memcached的經(jīng)驗的人會了解到,php+memcached的性能是最好的,java+memcached的性能比較差,其主要原因就是在于java本身的序列化機制很慢.
          我做了個簡單的測試,一個UserData類,有一個字符串屬性,一個日期屬性,一個double屬性,分別用java,hessian來序列化一百萬次,結(jié)果讓人吃驚,不止是hessian序列化的速度要比java的快上一倍,而且hessian序列化后的字節(jié)數(shù)也要比java的少一倍.因為我在測試的時候只是做了序列化這部分的工作,并沒有把序列化后的結(jié)果放到網(wǎng)絡(luò)上傳輸,所以,實際中的性能hessian應(yīng)該會更好!
          既然hessian的序列化協(xié)議要比java本身的好,而memcached客戶端的性能又在很大程度上依賴與對象的序列化.所以,我就決定把我的cache實現(xiàn)中序列化這部分的工作改成用hessian來實現(xiàn)了.
          我用的memcached客戶端是用的danga.MemCached包,主要是改動了MemCachedClient的get方法及set方法,在set方法中改為調(diào)用hessian的序列化:
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          //修改以前的序列化代碼:
           //(new ObjectOutputStream( bos )).writeObject( value );
          //修改后的序列化代碼:
          serializeByHessian(bos, value);
           val = bos.toByteArray();
          serializeByHessian方法如下:

           protected void serializeByHessian(OutputStream os, Object object) throws IOException {
                  AbstractHessianOutput out = new Hessian2Output(os);;
                  SerializerFactory serializerFactory = getSerializerFactory();
                  out.setSerializerFactory(serializerFactory);
                  out.startReply();
                  out.writeObject(object);     
                  out.completeReply();
                  out.flush();
           }
          在get方法中主要是修改了這個方法調(diào)用的類ContextObjectInputStream的readObject方法:
          在ContextObjectInputStream中覆蓋了readObjectOverride方法:
           protected Object readObjectOverride() throws IOException,  ClassNotFoundException {
                  ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                  ClHessian2Input in = new ClHessian2Input(is, this.mLoader);
                  in.setSerializerFactory(getSerializerFactory());
                  int code = in.read();//"r"
                  int major = in.read();//>=2
                  int minor = in.read();//0
                  Object value = in.readObject();
                  is.close();
                  return value;
           }
          因為我的框架是基于osgi的,所以我重載了Hessian2Input,把classloader作為參數(shù)傳進(jìn)去,否則hessian在反序列化的時候會找不到類.如果你沒有用osgi框架的話, ClHessian2Input in = new ClHessian2Input(is, this.mLoader);這行代碼就可以直接用: Hessian2Input in = new Hessian2Input(is);
          這樣修改就基本完成了.
          我把memcached client的序列化協(xié)議改為hessian也有另外一個系統(tǒng)架構(gòu)的原因,那就是因為我的服務(wù)層邏輯都是用java+spring+osgi的方式實現(xiàn),而web層則是用php實現(xiàn),兩者之間通訊已經(jīng)是采用hessian的遠(yuǎn)程調(diào)用.所以,部分緩存數(shù)據(jù)在服務(wù)層通過java設(shè)置到memcached服務(wù)器中,在php中一樣可以用memcached php client讀取出來.(php的memcached client我用的是memcached-client.php,而不是php擴展,所以一樣可以修改memcached-client.php的序列化機制)


          posted on 2008-06-18 10:04 pony 閱讀(7877) 評論(11)  編輯  收藏 所屬分類: Java

          評論

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 10:17 pony

          另外附帶說一句,我的經(jīng)驗,在使用memcached的時候,客戶端在創(chuàng)建socket連接時最好把nagle設(shè)置為false.熟悉tcp協(xié)議的都知道setTcpNoDelay有什么作用.如果Tcp_NoDelay被設(shè)置為true,那么發(fā)送數(shù)據(jù)包時將使用nagle算法對要發(fā)送的數(shù)據(jù)進(jìn)行緩存處理,只有當(dāng)達(dá)到一定數(shù)量之后才把包發(fā)送出去,設(shè)置為false則立即發(fā)送包.對于memcached緩存,一般我們放進(jìn)去的數(shù)據(jù),以及發(fā)送的get命令都是很小的包,為了將數(shù)據(jù)及時傳輸出去,所以要禁用nagle.  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 10:35 CHINA BAIDU

          不錯1!  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 12:19 dennis

          @pony
          很好的帖子,不知道換成了hession有沒有測試數(shù)據(jù)?
          對于setTcpNoDelay說反了吧?setTcpNoDelay為true,就是設(shè)置TCP_NODELAY,也就是禁掉Nagle算法;默認(rèn)就是false,表示啟用Nagle算法。禁掉Nagle算法可以提高響應(yīng)性,相應(yīng)地會降低吞吐量,在這個場景中沒啥必要。



            回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 13:24 lizongbo

          hession 的序列化效率確實不錯,

          不過需要序列化的對象,試過實現(xiàn)java.io.Externalizable接口的方式?jīng)]?


            回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 13:41 pony

          @dennis
          測試hessian和java序列化的代碼,寫的不好請見諒^_^
          由于把數(shù)據(jù)存儲到memcached服務(wù)器中跟網(wǎng)絡(luò)環(huán)境,內(nèi)存有很大關(guān)系,跟memcached client設(shè)置的參數(shù)也有很大關(guān)系,所以就不做memcached的存取測試了.

          下面的代碼在我的機器上的結(jié)果是:
          serialize 1000000 users with hessian spend 8 seconds, total size:93000000
          serialize 1000000 users with java spend 17 seconds, total size:190000000

          /**
          * Created at 2008-06-13.
          * 測試比較java和hessian的序列化效率.
          */
          import java.io.ByteArrayOutputStream;
          import java.io.ObjectOutputStream;
          import java.io.Serializable;
          import java.util.Date;

          import com.caucho.hessian.io.AbstractHessianOutput;
          import com.caucho.hessian.io.Hessian2Output;
          import com.caucho.hessian.io.SerializerFactory;

          /**
          * @author pony
          *
          * 如果有任何對代碼的修改,請按下面的格式注明修改的內(nèi)容.
          * 序號 時間 作者 修改內(nèi)容
          * 1. 2008-6-13 pony created this class.
          */
          public class TestSerializerPerformanceFucntion {
          //序列化次數(shù).
          private static final int COUNT = 1000000;

          private SerializerFactory factory;

          public static void main(String[] args) throws Exception {
          new TestSerializerPerformanceFucntion().testHessianSerializer();
          new TestSerializerPerformanceFucntion().testJavaSerializer();
          }

          public void testHessianSerializer() throws Exception {
          long curr = new Date().getTime();
          int size = COUNT;
          int len = 0;
          for (int i=0; i<size; i++) {
          User user = new User();
          ByteArrayOutputStream os = new ByteArrayOutputStream();
          AbstractHessianOutput out = new Hessian2Output(os);;
          SerializerFactory serializerFactory = getSerializerFactory();
          out.setSerializerFactory(serializerFactory);
          out.startReply();
          out.writeObject(user);
          out.completeReply();
          out.flush();
          os.flush();
          len += os.size();
          out.close();
          }
          long now = new Date().getTime();
          System.out.println("serialize " + size + " users with hessian spend " + (now-curr)/1000 + " seconds, total size:" + len);
          }

          public void testJavaSerializer() throws Exception {
          long curr = new Date().getTime();
          int size = COUNT;
          int len = 0;
          for (int i=0; i<size; i++) {
          User user = new User();
          ByteArrayOutputStream os = new ByteArrayOutputStream();
          new ObjectOutputStream(os).writeObject(user);
          os.flush();
          len += os.size();
          os.close();
          }
          long now = new Date().getTime();
          System.out.println("serialize " + size + " users with java spend " + (now-curr)/1000 + " seconds, total size:" + len);
          }

          public SerializerFactory getSerializerFactory() {
          if (null == factory) {
          factory = new SerializerFactory();
          }
          return factory;
          }
          }


          class User implements Serializable {
          /**
          * serial Version UID.
          */
          private static final long serialVersionUID = -4845300297590675952L;

          private String name = "test name";

          private Date birthday = new Date();

          private int age = 10;

          private double money = 1000.56;

          /**
          * @return the name
          */
          public String getName() {
          return name;
          }

          /**
          * @param name the name to set
          */
          public void setName(String name) {
          this.name = name;
          }

          /**
          * @return the birthday
          */
          public Date getBirthday() {
          return birthday;
          }

          /**
          * @param birthday the birthday to set
          */
          public void setBirthday(Date birthday) {
          this.birthday = birthday;
          }

          /**
          * @return the age
          */
          public int getAge() {
          return age;
          }

          /**
          * @param age the age to set
          */
          public void setAge(int age) {
          this.age = age;
          }

          /**
          * @return the money
          */
          public double getMoney() {
          return money;
          }

          /**
          * @param money the money to set
          */
          public void setMoney(double money) {
          this.money = money;
          }

          /**
          * @return the serialVersionUID
          */
          public static long getSerialVersionUID() {
          return serialVersionUID;
          }
          }  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-06-18 13:54 pony

          @lizongbo
          謝謝!這是個好建議!試過之后,只有驚訝!結(jié)果是比hessian的還快了!
          運行結(jié)果是:
          serialize 1000000 users with hessian spend 10 seconds, total size:93000000
          serialize 1000000 users with java spend 9 seconds, total size:86000000

          把上面代碼中的Serializable 改為
          Externalizable,實現(xiàn)下面兩個方法:
          public void readExternal(ObjectInput in) throws IOException,
          ClassNotFoundException {
          String name = in.readUTF();
          long time = in.readLong();
          int age = in.readInt();
          double money = in.readDouble();
          this.setName(name);
          this.setBirthday(new Date(time));
          this.setAge(age);
          this.setMoney(money);
          }

          public void writeExternal(ObjectOutput out) throws IOException {
          out.writeUTF(name);
          out.writeLong(birthday.getTime());
          out.writeInt(age);
          out.writeDouble(money);
          }

          不過因為從架構(gòu)上考慮,我要用php來讀取cache中的內(nèi)容,所以我希望序列化后的對象能遵循一個統(tǒng)一的協(xié)議,所以,我暫時還是要用hessian的方式.  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2008-12-04 10:31 LiMengyan

          博主能否來個hessian序集?講講hessian部署的結(jié)構(gòu)?我想看看hessian這個服務(wù)模塊是怎么給其他應(yīng)用提供服務(wù)的?  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取 2010-09-20 11:00 thebye85

          @pony
          怎么我這邊測試還是hessian快  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取[未登錄] 2010-10-05 16:38 Jeff

          好文章!  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取[未登錄] 2011-06-24 12:03 HK

          好文啊!  回復(fù)  更多評論   

          # re: hessian序列化協(xié)議+memcached的緩存存取[未登錄] 2013-12-19 15:40 sa

          hessian4.0.7有一個bigdecimal序列化的bug  回復(fù)  更多評論   

          主站蜘蛛池模板: 上杭县| 稻城县| 双峰县| 牡丹江市| 诸暨市| 西吉县| 华蓥市| 固安县| 临沭县| 忻城县| 化州市| 陆川县| 新营市| 鲁甸县| 晴隆县| 寿光市| 苍山县| 陵川县| 搜索| 龙陵县| 嵊州市| 革吉县| 宁化县| 微博| 济宁市| 永寿县| 英山县| 托克逊县| 虞城县| 富川| 和龙市| 夹江县| 花莲县| 襄垣县| 宁乡县| 历史| 靖安县| 泸西县| 高雄市| 卓资县| 舞钢市|