• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            從需求角度看NOSQL發展

             

            早先當640kb就足夠使用的觀點流行的時候,數據處理規模很小,需求也不多,于是簡單的文件存儲即可滿足需求,發展一段時間之后ISAM之類的簡單存儲就可滿足需求,再之后sql流行,當sql為了適應各種需求變得越來越龐大的時候,效率也止步不前,在將緩存和多線程性能榨取完了之后,sql各項性能還只停留在滿足常規應用的地步,難于處理1秒萬次以上的讀寫操作,也難于解決萬個以上的并發連接,一般的企業不可能動不動就上硬件,所以nosql發展是時代的需要是需求的推動。當然一般sql對傳統企業還是足夠滿足的,所以我們在nosql的發展上沒看到傳統企業的身影,只看到當前發展最快的SNS公司積極推動nosql不斷發展,著名的如:Facebook 推動Cassandra發展,Linkedin推動Voldemort發展,這都是最大的一類sns網站,這些網站都有幾千萬以上的用戶,巨量數據讀寫,所以這些數據庫都是極其強調分布式應用的,并不單純的強調每個點的讀寫性能。再看小一點的mixi推動的Tokyo CabinetTokoy Tyrantgreen.jp推動Flare的發展,這些數據庫都滿足于幾千萬條數據的高速訪問,也沒看到特別的強調并發性,只強調他們的速度,當然幾千萬條數據還是有可能全放在內存里面的,就算放不下全部數據也至少可完全放下全部索引,這樣讀寫當然快了,據說tt到億條之后寫性能急劇下降,大概就是這個原因吧。純內存式數據庫也必須要提一下,典型的如LiveJournal開發的memcached以及另一個新秀Redis等,前面提到的tt也支持memcached的協議,雖然這類數據庫有很多局限,但在某些場合的確又很適合,memcahced其實連持續存儲都不支持,為了解決持續存儲問題,又有人發展了一些,如tt其實就是一個支持存儲的memcached,國內新浪團隊也給memcached加上berkeleydb支持持續存儲。

            上面說了這么多,無非想說一句話,需求推動技術進步,每一個技術進步其實都是為了滿足某種需求的結果,就如google的三大基石bigtablegfsmap/reduce都是為了解決它的巨量數據而折騰出來的東西,google也正是靠這幾個核心技術把持了互聯網近十年的風光。同理我們可以想見,雖然百度沒有大力的宣傳他們的底層技術,但我們很容易想到,他們一定也是需要這些技術的,而且他們內部就算沒有這些技術,但一定有類似的接替代產品,否則支撐不了他們那么巨量的數據,雖然替代產品未必有google的產品那么好,但大概是略差一點或相當的水平吧。國內互聯網巨頭騰訊支持了國內最大的im應用 10億級,最大的棋牌游戲近億在線,加上他們布局網絡門戶,布局qzone等,都是巨量用戶,可以想見他們一定有類似的方案,早先聽說他們棋牌游戲是通過很多mysql + proxy來完成的,雖然這個方式現在看起來也不是很完美,但至少是一個可行的解決方案,臆測下可以這樣使用,proxy有個巨大的hash表,每個qqid計算一下就知道在哪個區段,重定向到哪個區段讀寫數據即可,說起來容易做起來難啊,就算我玩種菜都不知道遇到多少次他們數據出故障了,說明他們的系統面對巨大數據壓力的時候還是碰到了很多問題。國內還有個公司不得不提,阿里巴巴淘寶,馬云團隊發跡很快,淘寶每年不知道要成交多少筆,但他們的數據也是一個天量,看了下他們dba團隊的主頁,牛一點的dba都籠絡了不少,就是自己開發能力稍弱了一點,縱觀國內對巨量數據需求最迫切的也就這幾家公司了,雖然之后的51、開心網、盛大等也有類似需求,但數據量總歸還是沒有超過前面幾家公司。

            在需求的推動下,國內的nosqlkey-value應用也慢慢發展了一些,如張宴在新浪搞的memcachedb,到金山之后搞的dbcached,豆瓣開發的beansdb等,還有一些沒開源沒介紹不大為外界知道的應該也有一些,但總的來看水平還是比較低,有點不成氣候的樣子,靠的大多是1-2個牛人支撐,離開了這么幾個人就不行了,東西也沒人維護,的確,離開了巨量數據的需求一般的企業用sql就能滿足也不會去研究這些東西,少數小一點的互聯網企業有這個需求又沒有相應的人才有能力去研究,年輕一點的開發人員都在玩概念想做也做不出這些東西,畢竟做這些東西沒有很深厚的數據結構知識,沒有3-5年的深入編程磨練是不可能真正做好一個像樣東西的,矛盾啊。

            最后說下我最近在做的一個東西,分布式md5計算,這個東西網上隨便查一下就知道做的人不少,提供網站服務的都不少,但搜了幾篇文章,看了幾個網站www.cmd5.com www.md5.com.cn就知道,水平之低下超出了我的想象,基本上還是停留在用sql數據庫的層次上,根據這些網站寫的時間節點感覺他們大多數時間就是在制造數據,速度大概是幾個月制造幾十億條數據,都號稱有幾萬億條數據,但事實上提供公開查詢的數據只有區區幾億條,其他都要收費才能查詢,天知道到底有沒有那幾萬億條記錄,看上很吸引人,其實用處不算很大,用我最近整的md5數據制造方法1秒制造100w條數據,1億條數據也就在2分鐘內搞定,幾億條數據也不過10分鐘左右就生成好了,1億條記錄耗費空間1.5G左右,不過10G左右空間即可,技術含量可見并不是很高。 其實我做這個項目并不是想做個類似的網站,主要是覺得這個東西玩技術很有意思,可大可小,一臺機器也可玩,1T硬盤放600億數據沒問題,1萬臺機器也不多,全字母遍歷到10位就算是上1w臺機器也不夠用,分布式存儲分布式計算典型云計算概念,clientp2p可不p2p,很多技術元素都可參與其中,很有玩性的一個程序,所以就較上勁了,也好,正好練練技術,玩玩nosql的概念。

            各種新興技術出來都看到國內有深入分析,就說nosql系列的吧,深入分析memcached,深入分析tt,深入分析Cassandra的文章不計其數,到底也沒看到有幾個國人能寫類似的東西,分析得頭頭是道,做的時候白癡一樣,就算是使用都難用好,更別說自己動手做個這方面的好產品了,國情如此,略感欣慰的是國內現在也有一些公司和一些高水平的人真正參與其中,未來還是有可能有所突破的,正入本文所說,需求會推動技術發展,但短期肯定還是國外為主,國內的產品最多是一絲點綴。

            posted @ 2010-10-03 14:18 袁斌 閱讀(405) | 評論 (0)編輯 收藏

            Jsonajax領域很流行,記得當時看過它的介紹后很興奮,網上找了一些解析jsonc

             

            c++代碼,不過沒有找到特別好的,有的寫得不錯不過要依賴于boost,有的用c寫的不大好用,好在json語法簡單,參考了一些c/c++json解析代碼做了一個json類,最近又把去年寫的json類修改為unicode下使用,增了一些功能,現在CJsonw可以解析const char *型輸入,也可解析const wchar_t *型輸入,可解析ansi編碼、unicode編碼、utf8編碼的json文件。看看我的CJsonw定義:

             

                    JsonwType type;                     //Json類型, true false null直接由類型表示了

                    DWORD tag;                            //tag,用戶自用值,默認為0

                    union

                    {

                            struct{

                                    wchar_t *cstring;//字符串型值

                                    int clen;            //cstring按照字符計算的分配個數,包括可能的0

                            };

                            double dvalue;          //double

                            struct

                            {

                                    int ivalue;         //int

                                    DWORD dwhigh;       //高部

                            };

                            __int64 i64value;        //int64

                            OBJS *objs;                     //對象型值

                            ARRAYS *arrays;             //數組型值

                    };

            Sizeof(CJsonw) == 16

            OBJS類型描述無序的key-value型數據,ARRAYS描述 array型有序數據,定義如下:

                    typedef CHashiW<CJsonw *, CJsonw *> OBJS;

                    typedef std::vector<CJsonw *> ARRAYS;

            支持以下構造函數:

                    CJsonw(JsonwType t=json_null);

                    CJsonw(int value);

                    CJsonw(__int64 value);

                    CJsonw(float value);

                    CJsonw(double value);

                    CJsonw(const wchar_t *value);

                    //數組型構造函數

                    CJsonw(int *numbers, int count);

                    CJsonw(__int64 *numbers, int count);

                    CJsonw(float *numbers, int count);

                    CJsonw(double *numbers, int count);

                    CJsonw(const wchar_t **strings, int count);

            支持以下賦值函數:

                    bool setnull();

                    bool set(bool value);

                    bool set(int value);

                    bool set(__int64 value);

                    bool set(float value);

                    bool set(double value);

                    bool set(const wchar_t *value);

                    bool set(int *numbers, int count);

                    bool set(__int64 *numbers, int count);

                    bool set(float *numbers, int count);

                    bool set(double *numbers, int count);

                    bool set(const wchar_t **strings, int count);

                   

                    //修改常規值,就是true, false, int, real, string

                    bool setbystring(const wchar_t *value);

             

            支持以下輸入:

                    bool parse(const char *string);

                    bool parse(const wchar_t *string);

                    bool parsefile(FILE *fp);

                    bool parsefile(LPCTSTR filename);

            文件可以ansi編碼、unicode編碼、或者utf8編碼

             

            支持以下wchar_t型輸出:

                    //dump,默認為unicode編碼

                    //uunicode表示字符串中的unicode字符是否按照\uxxxx格式輸出

                    //bDisptrue按照友好格式顯示,會輸出\t換行等方便閱讀

                    //bDispfalse按照緊湊模式顯示,沒有多余字符,方便網絡傳輸等場合

                    bool dump(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=false, bool bDisp=true);

                    //跟上面的dump一樣,但如果成功會在buf里面插入一個'\0'字符

                    bool dump0(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=false, bool bDisp=true);

                    bool save(LPCTSTR filename);

                    bool save(FILE *fp);

            保存到文件默認為UNICODE格式

             

            支持以下ANSI型輸出:

                    //a系列dumpansi編碼輸出

                    //bDisptrue按照友好格式顯示,會輸出\t換行等方便閱讀

                    //bDispfalse按照緊湊模式顯示,沒有多余字符,方便網絡傳輸等場合

                    bool dumpa(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=true, bool bDisp=true);

                    //跟上面的dump一樣,但如果成功會在buf里面插入一個'\0'字符

                    bool dumpa0(CBlockBuffer *pbk, bool bNameQuotes=true, bool uunicode=true, bool bDisp=true);

            ANSI型輸出主要用在節省網絡帶寬或者和其他系統交換數據的情況下。

             

            支持以下類型判別函數:

                    //類型判別函數

                    bool IsArray() const { return type==json_array; }

                    bool IsObject() const { return type==json_object; }

                    bool IsInt() const { return type==json_int; }

                    bool IsReal() const { return type==json_real; }

                    bool IsNumber() const { return IsInt()||IsReal(); }

                    bool IsNull() const { return type==json_null; }

                    bool IsTrue() const { return type==json_true; }

                    bool IsFalse() const { return type==json_false; }

                    bool IsString() const { return type==json_string; }

             

            支持以下一些直接取值函數:

                    const wchar_t *getordef(const wchar_t *strdef)

                    int getordef(int idef)

                    __int64 getordef(__int64 idef)

                    double getordef(double ddef)

                    bool getordef(bool bdef)

                    //array的元素

                    CJsonw *get(int n)

                    CJsonw *operator[](int n) const

                    //obj的元素

                    CJsonw *get(const wchar_t *name)

                    CJsonw *operator[](const wchar_t *name) const

             

            支持以下取array型子元素數據的函數:

                    const wchar_t *getordef(int n, const wchar_t *strdef)

                    int getordef(int n, int idef)

                    __int64 getordef(int n, __int64 idef)

                    double getordef(int n, double ddef)

                    bool getordef(int n, bool bdef)

             

            支持以下取obj型子元素數據的函數:

                    const wchar_t *getordef(const wchar_t *name, const wchar_t *strdef)

                    int getordef(const wchar_t *name, int idef)

                    __int64 getordef(const wchar_t *name, __int64 idef)

                    double getordef(const wchar_t *name, double ddef)

                    bool getordef(const wchar_t *name, bool bdef)

             

            支持以下obj遍歷函數:

                    //遍歷函數,最常見寫法:

                    //for(CJsonw::OBJIT *p=xxx.FirstObj(); p; p=p->next())...

                    OBJIT *firstobj()

             

                    //arrayobject元素個數,string類型返回分配的字符個數(包括可能的),其他類型都返回

                    int size() const

             

            另外支持一些增加array子元素函數:

                    bool add(CJsonw *pnode)

                    bool del(int n, bool bfree=true)

                    bool addnull(){ return add(new CJsonw(json_null)); }

                    bool addtrue(){ return add(new CJsonw(json_true)); }

                    bool addfalse(){ return add(new CJsonw(json_false)); }

                    bool add(int value){ return add(new CJsonw(value)); }

                    bool add(__int64 value){ return add(new CJsonw(value)); }

                    bool add(float value){ return add(new CJsonw(value)); }

                    bool add(double value){ return add(new CJsonw(value)); }

                    bool add(const wchar_t *value){ return add(new CJsonw(value)); }

             

            也支持obj增加刪除子對象函數:

                    bool addobj(const wchar_t *name, CJsonw *pnode)

                    bool delobj(const wchar_t *name, bool bfree=true)

                    bool addobjnull(const wchar_t *name){ return addobj(name, new CJsonw(json_null)); }

                    bool addobjtrue(const wchar_t *name){ return addobj(name, new CJsonw(json_true)); }

                    bool addobjfalse(const wchar_t *name){ return addobj(name, new CJsonw(json_false)); }

                    bool addobj(const wchar_t *name, int value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, __int64 value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, float value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, double value){ return addobj(name, new CJsonw(value)); }

                    bool addobj(const wchar_t *name, const wchar_t *value){ return addobj(name, new CJsonw(value)); }

             

            還有一些特殊函數:

                    //計算整個樹的crc

                    DWORD calccrc();

                    //計算整個樹的md5,要求md5不少于個字節

                    byte *calcmd5(byte *md5);

                    //計算hex表示的md5,不寫尾部,要求md5hex不少于個字符

                    char *calcmd5hex(char *md5hex, const byte x='x');

                    //計算hex表示的md5,寫尾部,要求md5hex不少于個字符

                    char *calcmd5hex0(char *md5hex, const byte x='x');

             

             

            json類上花了較多時間,主要是覺得這個類很有用,可以描述任意對象,易保存易傳輸易構造,對速度要求不苛刻的應用程序用json作為基本數據結構很合適,配合json里面的data自定義字段理論上支持描述任意對象,配合使用一些cache可擴大json類的使用范圍,用它取代ini xml等配置簡直是大材小用,用json類來做stringtable簡直就是小菜一碟,而且還是hash級高效率,絲毫不比手工做一個hash_map<,>表差。

            在實際應用中,去年有一個網絡驗證的項目就大量使用了這個類,配置、幫助都是json格式,應用中管理大量對象的內存數據庫也是用了json類,編碼后直接網上傳輸,server內部也是一個json對象直接管理了大量用戶的信息,非常方便,可以說用json類使得這個程序少寫了大量代碼,也使得整個項目只用了1個月時間就做出來了,還部署成master – master- slave(N)模式穩定運行了將近1年時間。

            在另一些網絡應用中,俺將json格式數據作為變長包使用,前面俺寫過一篇短文介紹了變長包最常見的幾種格式,分別是:

            1、 key\0value\0…

            2、 json格式

            3、 xml格式

            使用json格式作為變長包現在很流行,這也是大量ajax所采用所依賴的技術,qq種菜,google搜索預列表都是采用json格式的。

            posted @ 2010-10-03 14:17 袁斌 閱讀(919) | 評論 (0)編輯 收藏

            HashCrack程序規劃

             

            最近幾天在思考如何遍歷md5找出原碼字符串,但九十多個可見字符,96^6 782757789696,就算只遍歷6位組合也是非常驚人的巨量數據,單機根本無法完成,根據常用密碼合成規律,我們可以采用分而治之的方法解決,方法大致如下:

            1、 使用很多機器,機器越多覆蓋的范圍越大。

            2、 優先覆蓋最常用的范圍,如全數字組合,小寫字母組合,小寫數字混合組合,大寫字母組合,夾雜一個非字母數字字符的組合,之后覆蓋非常見組合,如所有可見字符的N個全排列。

            3、 采用c/s結構,中心機管理區段分配策略,優先覆蓋常用區段,所有slavemaster一起構成一個覆蓋網。

            4、 不僅支持md5,也支持sha等其他類似算法。

            5、 Masterslave也支持添加字典,為了覆蓋盡可能多的組合,可添加任何合適的字典組合。

             

            實現難點:

            1、 數據組織。

            方案一、考慮過磁盤存儲方案,研究了sqlite,寫效率大概10w/s,加了索引大概5w/ssqlite存儲效率也不是很高,比berkeley存儲浪費很多空間,加了索引后空間放大了一倍。也嘗試過berkeley方案,寫效率大概只有4.5w/s,存儲相對sqlite緊湊一些。但由于寫效率太低,都難于實現我所希望的一個slave一下分配1億數據量的模式(1億數據大概要占磁盤5-10G,最經濟模式大概也要占2.xG)。由于對btree+不太熟悉,暫時還沒有找到高效的存儲方案。

             

            方案二、其實首先是考慮了內存方案,用內存相比磁盤其實要簡單一些,不過受機器可用內存的限制以及客戶接受程度的限制,難于讓一臺slave處理1億以上的數據量,默認大概只能分配2000w-5000w左右的數據量(大概占用內存400M-1.2G)。

             

            以上兩種方案其實選擇方案一更合適一點,因為一般的機器擠2G左右的磁盤基本都沒有問題,甚至20G-200G可能都問題不大,但要持久占用1G內存可能不大好,畢竟大多數用戶比容易接受。第一版暫時用了方案二,待高速寫存儲方案做好后替換一個dll即可(該dll已經留好了接口可直接替換)。

             

            2、 區段劃分

            單純的劃分某一個區段也是比較容易的,如10個數字的8個組合,可用如下方法表示

            Digits = “0123456789”

            Range(Digits, 8, 0, 20000000) 表示digits 8個字母的排列 [0,20000000]

            但將一些常用區段單獨出來之后涉及到和更大范圍字母全排列的重合情況就不大好扣出來,暫時沒有找到較好的表示方法,好在小范圍排列被冗余也問題不是很大,此表示方法待繼續研究,暫時采用冗余方案。

             

            3、 Master 發現機制

            其實這是一個經典的問題,可考慮得很復雜,也可考慮得很簡單,由于我名下幾個域名都被禁止解析了,所以這個問題變得不是那么方便,不過暫時還是用個域名部署一下最為簡單,存儲空間也是個問題,待我聯系幾個朋友看看能不能找到一個合適的存儲地點,待找到后第一版就這么部署出去吧。

             

             

            實現方法:

            由于要有一個中心提供調度方案,因此該系統肯定有一個中心(不管是一個點還是N個點),所以考慮采用c/s模式,第一版采用一個masterNslave的方案。

            master主要實現以下功能:

            1、 覆蓋最常用區段排列,籍此提供最基本的查詢服務。

            2、 支持大量slave接入(暫采用iocp模式接入)。

            3、 提供區段劃分功能,slave接入斷開自動分配區段,優先分配常用區段,其次分配非常用區段。

            4、 查詢轉發功能,接收slave的查詢請求,轉發給其他slave

             

            slave實現以下功能:

            1、 master交互,接收分配的區段,處理區段內的數據并提供該區段數據查詢服務(此功能由一個接口dll實現,可輕易替換)。

            2、 支持查詢功能。

            3、 在客戶端還計劃支持apislaveapiproxyapi通過消息向slave發送查詢請求,slave通過給master發送查詢請求,在整個群落里面提供查詢服務,此功能為該體系的一大亮點,暫時沒考慮做什么限制,主要為吸引用戶提供很主動的編程功能,第一版通過一個cdll提供api調用功能,在此api基礎上用戶應該可以很容易包裝出其他語言的調用接口,如luapython的接口等。

             

             

            進度說明:

            由于該項目只是一個即興性項目,沒打算耗費很多時間,計劃在一周內完成,已經過去了3天,所以在細節上暫時無法抽出很多時間仔細研究,待整體功能成型后看情況再斟酌算法,易改變部分暫時都用接口dll實現,該項目代碼部分大概完成了一半左右,未來2-3天左右大概可以做完第一版。

            posted @ 2010-10-03 14:17 袁斌 閱讀(191) | 評論 (0)編輯 收藏

            簡單總結下asp.net狀態維持方法如下:

            client端狀態
            1、ViewState
            2、ControlState
            3、Hidden Field (post 模式)
            4、Cookie
            5、QueryString (get 模式)

            server端狀態
            1、Application (全局)
            2、Cache (全局)
            3、Session (current session,配合后臺驅動可將session持續化到很多地方,如xml,
            或者db、或者memcached 等地方)
            4、配置文件(asp.net有一個sqlprofileProvider類使您可將配置文件數據保存到sql數據庫中)
            5、db

            對保持連接的c/s程序來說,client端狀態我們不是特別關心,除了cookie也有一些參考意義,其他幾種方法很難直接在普通cs程序里面對應,對server端程序開發來說,asp.net的server端數據持續方法對我們很有參考價值,對一般的游戲程序來說,db是必然會用的,配置文件型的也可參考使用,session型的很多程序都在使用,application型的緩存估計也有很多程序在用,更有價值的是cache型,我們一般的s程序基本都沒有實現時效性cache和文件觸發性cache,asp.net的cache對我們很有參考價值。當然我們不必生搬硬套的照搬web上的概念,只要學到精髓就可以了,總之,還是我堅持的那句話,俠義地說是從web架構學習server端程序設計,更廣義地說是從web架構學習一般網絡應用程序設計。

            posted @ 2010-10-03 14:16 袁斌 閱讀(170) | 評論 (0)編輯 收藏

            寫了tmpool之后又發現居然有tcmalloc,而且比牛逼的ptmalloc好很多,真感嘆啊,世界上好東西很多,但需要智慧的眼光去發現。在linux下簡單比較了一下malloc和tcmalloc,快的真不是一點點啊,看到好多人用tcmalloc去重編譯mysql, squid,nginx等。簡單看了下tcmalloc的原理,比我寫的tmpool要多一些整理的功能,大概tmpool就是tcmalloc在win下的子集,俺的tmpool區區800行代碼自然是不能去跟tcmalloc比的,不過對付一般的server端程序還是夠用的,經過一段時間的使用效果也還可以,待有時間對比下俺的tmpool和tcmalloc。

            posted @ 2010-10-03 14:16 袁斌 閱讀(1100) | 評論 (0)編輯 收藏

            常見cs程序自定義數據包描述

             

            常見cs程序自定義包可分為塊型包、非塊型包,非塊型包如http協議的,用\r\n\r\n結束,我們這里重點討論塊型包,塊型包常見頭部如下:

            Struct PKHEAD

            {

                    Union

            {

                            DWORD type;

                            Struct

            {

                    WORD mtype;

                    WORD stype;

            };

                    };

                    DWORD len;

                    Char buf[0];

            };

            內容buf部分常見組織方式莫過于定長、變長兩種。定長的很簡單,如struct item{…};作為內容部分,如果不涉及到高低序問題很好辦,涉及到序的時候轉換一下。變長部分常見組織方式有這么一些經典方法:

            1、 Content1 \0 content2 \0 content3 \0 …

            2、 json描述。

            3、 xml描述。

            方法1是效率很高的,對ansi型字符串或者utf8型字符串都沒有問題,對utf16型字符串不行。解析這類變長部分的時候特別要注意包尾部的0,或者在緩沖區外部總保證存在一個0,或者保證包內尾部總存在一個結尾0,總之最后一個string要保證有一個合法的0結束,當然可能涉及到一些數值型到string型的轉換可能會導致效率下降,1的缺點在于只有一個層次。如果將內容看作key1\0value1\0key2\0value2\0…可解決無序問題,但終歸只有一個層次,不方便表示樹形數據。

            方法2的效率介于13之間,2由于描述很簡潔,解析也是比較快的,比1好在可以解析任意層數據,嵌套N層都無所謂,閱讀也很方便,解析的時候如果原始緩沖不釋放可讓字符串不復制直接記錄在原始緩沖中的指針,這樣可進一步提高解析效率。QQ種菜的通訊協議就是json格式的,閱讀很方便,解析效率也可以,總的效率適中。

            方法3的解析效率是最低的,好在xml描述性也比較強,解析代碼也很多,跟上層應用交互的時候也比較方便,作為一個支持變長的選擇也是可行的,不過如果特別在意效率的情況下避免使用,xml的解析效率比 2低了近一個數量級,比1可能低近2個數量級。

             

            當然自定義包還有更多格式選擇,標準協議也有很多如im 里面常見的xmppgoogleprotocol buffers等,還有json的一些擴展協議,如bjson等,如果只是處理一般的網游數據可能用不上這么復雜的協議,用上面提到的定長struct+1 or 2 or 3基本可以解決所有協議需求。也見到一些朋友自定義類型信息描述格式,個人覺得或許沒有必要,特別是json如此流行的情況下再自己定義似乎有重復發明輪子的嫌疑,當然具體情況具體對待,一切以滿足需求為目標。

            posted @ 2010-10-03 14:15 袁斌 閱讀(324) | 評論 (0)編輯 收藏

            我一直堅持一個觀點,從web體系學習服務器端程序設計,web作為發展最早也是前景最廣闊的internet模型,幾乎支撐了網絡世界一半以上的應用,其他email ftp等傳統應用雖然產生時間也很早但幾乎都很沒落,只有web風采依舊,蓬勃發展,從apache到lighttp到nginx等,一個接一個高性能的web服務器程序分別被開發出來,上層應用cgi, isapi(nsapi), fastcgi助力,html協議也在不斷發展,html5也要登堂亮相,各種腳本語言爭相斗艷,python、php、java、asp.net等。web應用支持了目前最大規模的數據google,支持了最大量用戶的訪問,因此各種存儲、云計算等都是首先在web領域獲得應用,可以說web就是it領域的創新源泉,看下apache下面有多少項目就可見一般。web體系可謂博大精深,從web體系學習服務器端程序設計是學無止境的,從nginx等服務器程序設計上可學習server程序如何分塊、如何高效,從isapi/nsapi模型上可學習如何用進程內模塊擴展應用,從fastcgi可學習如何用進程外模塊擴展應用,從各種cache方案中可學習如何為server端提速,從各種腳本應用上可學習如何為server端程序二次開發助力,web是源泉,web的各種這方式幾乎概括了server端程序的各種架構模型。當然一般自定義協議服務器和web還是有些地方不同的,最顯著的區別一般也就在于協議不一樣,另外就是web是無狀態一般不保持連接,因此web需要傳遞各種session等維持狀態的數據,總之從web可學習的地方實在是太多。

            簡單類比下web領域開發和一般server的擴展

            nginx模塊/apache模塊            server程序+plugin

            cgi                                      fork子進程

            fastcgi                                 server proxy模式,由于fastcgi可網絡方式部署,所以很容易在一個局域網內部實現一個ioserver+N logicserver模型

            簡單類比就可知道,如果一個server程序只要能很方便的支持plugin+fastcgi就可適應幾乎所有各種需求,可惜的是一般的server程序幾乎都不支持這兩個模式的擴展,大多數gameserver只支持lua等腳本,說實在的,支持個腳本跟支持fastcgi和plugin模塊相比還是差很多,如果支持fastcgi或者plugin只要做個plugin就支持lua了。

            posted @ 2010-10-03 14:15 袁斌 閱讀(226) | 評論 (0)編輯 收藏

            Server模塊如果僅僅作為一個lib包裝出來自然不是最好,雖然可在c++工程很容易使用,效率也比較高,但要使用到其他語言上去就沒有辦法,如果包裝一下自然是最好的,但如何包裝呢,包裝成一個什么樣子也是很重要的,最常見的包裝自然是包裝成一個dll,輸出一些接口,其他上層模塊在該接口的基礎上使用。最簡單的包裝一般可輸出如下一些接口,

             

            Public IServer:

            {

            Virtual void StartServer(LPCTSTR ports, LPCTSTR udpoorts, int iothreads, int syncthreads, int asyntchreads);

            Virtual void StopServer();

                     Virtual IClient *CreateClient();

                     Virtual void CloseClient(IClient *);

                     Virtual void OnCloseClient(IClient *);

                     Virtual void OnConnectClient(IClient *);

                     Virtual void PostSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam)

                     Virtual void PostAsyncEvent(DWORD event, WPARAM wparam, LPARAM lParam);

                     Virtual void OnAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnTimer(UINT uid);

                     Virtual void AddTimer(UINT uid, DWORD tk1, DWORD duetk);

            };

             

            Public IClient

            {

                     Virtual bool SendData(void *pdata, int len);

                     Virtual bool SendFile(LPCTSTR lpfilename);

                     Virtual bool SendFile(HANDLE hFile);

                     Virtual bool SendMsg(PKHEAD *ph);

                     Virtual bool SendMsg(PKHEAD *ph, void *pdata, int len);

                     Virtual bool SendMsg(PKHEAD *ph, void *pdata, int len, byte encrypt, byte compress);

                     Virtual void DelayClose();

                     Virtual void OnDelayClose();

                     Virtual void OnClose();

                     Virtual void OnConnect();

                     Virtual void OnAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void OnSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void PostSyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void PostAsyncEvent(DWORD event, WPARAM wParam, LPARAM lParam);

                     Virtual void SetTag(DWORD wParam);

                     Virtual DWORD GetTag();

                     Virtual long GetId();

            };

             

            IServer *DllCreateObject();

             

             

            通過結合LoadLibrary并提供一個類似DllCreateObject的形式可很容易的 模擬類com實現,上層可很容易的是復用dll的實現。

            posted @ 2010-10-03 14:14 袁斌 閱讀(162) | 評論 (0)編輯 收藏

            我寫東西一般是即興性創作,一般在走路的時候很容易產生各種想法,高興的時候到家或到工作的地方馬上就開寫,幾分鐘就將想法記錄下來,由于寫得快也不檢查,所以看上去可能不是很流暢,或者說得不是很清楚,甚至還有很多錯別字等,請見諒。如關于某個技術問題想和我深入探討請和我直接聯系,qq:345585946

            posted @ 2010-10-03 14:14 袁斌 閱讀(127) | 評論 (0)編輯 收藏

            有些時候需要給資源分配一個唯一id(32bit or 64bit or CHAR[N]),這里主要說下分配方法問題。

            首先我們有個基本前提,如果是單線程分配,那么我們無需下面的方法,直接++value即可(CHAR型無論幾線程都可使用GUID)順序產生不重復序列,下面討論的方法都是多線程下的分配策略:

            方法1 win下做簡單的方法莫過于使用InterlocckedIncrement(or InterlockedIncrement64)了,這個調用也很簡單,每次遞增一個,多線程間保證順序遞增絕無重復。此方法只可在單一進程上使用。

             

            方法2、區間法,每個線程一次申請一個id區間[m, n],用完了再申請下一個區段,申請的時候鎖一次,其他時間都不用鎖,效率比3略低,比1高。此方法也只可在一個進程上使用,當然如果申請的策略修改一下也可實現多個進程甚至不同機器上的進程之間獨立分配id

             

            方法3、方法1雖然簡單但畢竟InterlockedXXX系列函數調用還是有些耗時的,大概50cpu周期級別,更簡單的方法可以使用線程切分原理,如有3個線程參與id分配,我們這樣分配:

            線程1 base=1, step =3,序列1,4,7,10,…

            線程2 base=2, step=3,序列2,5,8,11,…

            線程3 base=3, step=3,序列3,6,9,12,…

            絕無重復,調用非常簡單每個線程id = base; base += step;即可。

            此方法在單進程上使用很簡單,如果要拓展到多個進程上使用要通過配置來實現,但也是不難的。

             

            方法4、如果id可用GUID表示那么方法要簡單一點,生成id直接調用guid生成算法,這個id生成算法即使在多個進程之間甚至不同機器之間也可以保證唯一,也有其價值。

            posted @ 2010-10-03 14:13 袁斌 閱讀(1089) | 評論 (0)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            久久强奷乱码老熟女网站| 久久久久久久精品成人热色戒| 热re99久久6国产精品免费| 精品久久久久久无码专区不卡| 青青草原综合久久大伊人精品| 久久久久亚洲AV成人网人人网站| 热99RE久久精品这里都是精品免费| 久久久久人妻精品一区| 国产精品一区二区久久精品无码| 国内精品伊人久久久久777| 国产精品久久毛片完整版| 日韩中文久久| 青青青国产成人久久111网站| 欧美久久久久久午夜精品| 2021久久精品国产99国产精品| 欧美久久久久久午夜精品| 国产成人久久精品区一区二区| 日韩va亚洲va欧美va久久| 色综合久久中文综合网| 免费精品久久天干天干| 久久久精品日本一区二区三区 | 国产成人久久777777| 伊人久久精品无码av一区| 亚洲AⅤ优女AV综合久久久| 亚洲一区中文字幕久久| 好久久免费视频高清| 国产精品99久久免费观看| 久久天天躁狠狠躁夜夜网站 | 久久综合精品国产一区二区三区| 99久久国产热无码精品免费| 久久久久国产精品嫩草影院| 国产精品美女久久久免费| 欧美777精品久久久久网| 久久国产高清字幕中文| 久久99精品国产| 国产精品视频久久久| 精品久久一区二区三区| 国产成人综合久久精品尤物| A级毛片无码久久精品免费| 久久高潮一级毛片免费| 久久精品成人欧美大片|