<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    概述

    灰度發(fā)布是最近一年在國內互聯(lián)網討論較多的一個話題。灰度發(fā)布在國外并沒有明確的定義,在國內的百科上如此定義

    灰度發(fā)布是指在黑與白之間,能夠平滑過渡的一種發(fā)布方式。AB test就是一種灰度發(fā)布方式,讓一部用戶繼續(xù)用A,一部分用戶開始用B,如果用戶對B沒有什么反對意見,那么逐步擴大范圍,把所有用戶都遷移到B上面 來。灰度發(fā)布可以保證整體系統(tǒng)的穩(wěn)定,在初始灰度的時候就可以發(fā)現(xiàn)、調整問題,以保證其影響度。

    由此也可見灰度發(fā)布很多時候都和AB測試混在一起,但實際上灰度發(fā)布還包含了多級發(fā)布的概念。

    11年,F(xiàn)acebook的David Wei寫了一篇文章《代碼和產品發(fā)布的幾種方式》明確分析了下幾個概念:

    1、多級發(fā)布:也可以稱為分步代碼發(fā)布,是一種代碼發(fā)布的方式。基本操作是整個團隊共用一個代碼庫,一定頻率(比如每天一次,或者每周一次)把整個代碼的最新版本做一個新的發(fā)布分支(release branch),把發(fā)布分支逐步發(fā)布到產品線。

    2、AB測試:這是一種很成熟的概念,是產品發(fā)布的常用手段。比起分步代碼發(fā)布,AB測試往往有更長的周期(比如幾個星期甚至幾個月)。基本操作是產品的開發(fā)者加一個或者多個配置控制(一般每個產品配置應該帶有配置的ID),允許通過調節(jié)相應的配置來讓一個產品發(fā)布到“逐步選擇”的用戶群。

    從概念中可以看出多級發(fā)布和AB測試中最重要的區(qū)別:面向對象不一樣。多級發(fā)布針對的是代碼發(fā)布,AB測試針對的產品發(fā)布。本文主要討論代碼多級發(fā)布相關的需求和實現(xiàn)方案。

    需求場景

    在具體的互聯(lián)網應用中(主要針對如下架構)

    多級發(fā)布的需求場景如下:

    第一種:單個業(yè)務模塊上線,屬于具體一個業(yè)務中的一個模塊,非基礎模塊。有如下的特點:

    • 50%的上線需求是這種場景。
    • 上線流程:單機器-》多機器-》全部機器 的過程。
    • 上線時間間隔非常短,一般在半個小時內完成全部上線。
    • 會對用戶帶來影響,比如說用戶不停刷新有可能看到不同的版本。

    第二種:基礎庫模塊上線。大部分的基礎庫上線會和第一種業(yè)務模塊上線類似,但部分上線(尤其是哪些影響業(yè)務模塊較多,修改較大,有高性能要求)也會有如下特點:

    • 整體預估20%的上線需求,其中5%有如下特殊需求。
    • 可能的特殊需求:分業(yè)務系統(tǒng)逐步上線到所有機器。
    • 上線時間間隔有可能持續(xù)較長時間,比如說幾周以上。
    • 基礎庫上線一般不會對用戶帶來影響。

    第三種:多業(yè)務多模塊上線。一般這種上線的項目都是非常重要或者有重大功能修改的項目,重要性非常高。特點如下:

    • 30%的比例。
    • 一般上線流程是分業(yè)務上線。并且大體原則是從后(端)到前(端)。跨系統(tǒng)依賴的會梳理出順序,按照次序先后上線。
    • 原則上各個模塊之間上線間隔都在小時或者分鐘級別。
    • 對于具體用戶可見的部分會采用,有可能會用到長時間間隔的上線方式。

    難點&解決方案

    多級發(fā)布的主要難題有以下幾個:

    1. 監(jiān)控完善到位。在每一級別的發(fā)布中,如何能夠快速的通過監(jiān)控系統(tǒng)發(fā)現(xiàn)問題,包含功能異常、性能異常。
    2. 策略靈活可控。比如說能夠支持指定用戶查看某一級別的發(fā)布版本、能夠靈活的支持動態(tài)調度和動態(tài)擴容的需求。
    3. 用戶體驗無損傷。在發(fā)布的過程中,最好能夠保證用戶不會出現(xiàn)刷新版本頻繁切換的問題。PS:該問題在facebook也存在,但據(jù)說目前不care。
    4. 發(fā)布過程可測試。在發(fā)布的過程中,每一個階段都是可以方便確認功能正確性的。

    同時多級發(fā)布也有一些限制,比如說同一個模塊的最多只能有一個上線流程在進行,也就是不支持同一個模塊多個版本并行上線

    其中監(jiān)控需求,本身是一個相對獨立的需求,不在多級發(fā)布中考慮,那么多級發(fā)布只需要解決2、3、4三個難題。

    多級發(fā)布解決方案按照不同的實現(xiàn)層度如下:

    第一、實現(xiàn)多級發(fā)布基本功能:按照比例實現(xiàn)多級發(fā)布

    假設總共有16臺機器,分成8級發(fā)布,則可以按照1/8的分級方式進行上線發(fā)布。比如發(fā)布了第一級別后如下圖:

    為什么要按照比例,而不是直接給機器劃分級別呢?主要是處于幾個考慮:

    1. 給機器不同的標簽定義會導致機器的異構化帶來維護的難度。
    2. 無法支持機器動態(tài)調度的需求。
    3. 無法支持機器數(shù)目擴容的需求。

    第二、保證用戶體驗:采用一致性哈希負載均衡

    如何保證用戶體驗不受到影響的關鍵是:在多級發(fā)布的時候保證一個用戶的請求固定的落在一個發(fā)布級別中。那么對應的方法就是:前端接入層和運行層之間采用一致性哈希負載均衡算法。

    這種算法有幾個依賴:

    • 接入層和運行層的各個節(jié)點是無狀態(tài)對等的。原則上都會滿足。
    • 在代碼發(fā)布階段,最好不能有機器的變更。如果有機器變更則會導致部分用戶在某一時刻出現(xiàn)業(yè)務版本的切換(原則上影響也不大)

    對于一些默認不是一致性hash算法的,也可以在代碼發(fā)布的時候,把前端接入層和運行層之間的負載均衡方法切換到一致性哈希。

    第三、可測性和靈活性:接入層引入規(guī)則通用庫。(如果接入層采用Nginx做反向代理,那么就是一個nginx擴展)

    可測性是指:業(yè)務模塊的階段性發(fā)布能夠理解可測。這種需要只需要接入層規(guī)則通用庫能夠支持通過Http請求某一個參數(shù)來進行強制的請求分流即可。比如說通過參與version來指定對應請求分流的版本,具體比如說URL中有參數(shù)version=1,則分流到多級發(fā)布中的第一級。

    靈活性:主要是指其他一些測試性的需求,比如說強制某些用戶分流在多級發(fā)布的某一級,這些同樣可以可以在接入層中實現(xiàn)。

    本文首發(fā)xlq的博客(轉載請保留)http://blog.xiuwz.com/2012/03/05/%e6%b5%85%e8%b0%88%e7%81%b0%e5%ba%a6%e5%8f%91%e5%b8%83%e4%b9%8b%e5%a4%9a%e7%ba%a7%e5%8f%91%e5%b8%83/
    posted @ 2012-07-04 16:59 小馬歌 閱讀(4371) | 評論 (0)編輯 收藏
     

    最近有幾個朋友提起”灰度發(fā)布"這個概念和相關的問題。想解釋一下幾種具體的發(fā)布方式(具體名稱中文翻譯不一定正確)、他們的優(yōu)缺點和實現(xiàn)難點。

    這幾種方式都可以作為快速運營的軟件或者web服務公司逐步發(fā)布新代碼或者新產品,邊嘗試邊改進的方法,這些方法可以避免一次發(fā)布里面某個產品/代碼的漏洞對網站產生瞬間毀滅性的后果。 

    幾種方式各有優(yōu)缺點和難點,根據(jù)實際情況一個公司可能使用不同的方法做不同的發(fā)布。

     

     

    • 分步代碼發(fā)布(multi-phase code push):這是敏捷開發(fā)的團隊常用的代碼發(fā)布方式。基本操作是整個團隊共用一個代碼庫,一定頻率(比如每天一次,或者每周一次)把整個代碼的最新版本做一個新的發(fā)布分支(release branch)把發(fā)布分支逐步發(fā)布到產品線。
    • 特點:"逐步選擇"的過程不由代碼控制(如果代碼控制,那新一版本的控制代碼有問題就可能讓整個代碼發(fā)布過程崩潰)。“逐步選擇”過程由運營團隊負責:比如選擇每個機柜的第一臺機器,或者每個機群的第一個機柜,或者多個數(shù)據(jù)中心里面選擇某一個數(shù)據(jù)中心⋯⋯關鍵是選擇的時候是均勻分布到各種不同的機器上。如果新代碼在某一種配置的機器上有問題,運營團隊能夠及時發(fā)現(xiàn)。另外multi-phase code push的發(fā)布周期必須短于敏捷開發(fā)的迭代周期,往往一天或者一周之內要把代碼發(fā)布到所有機器。
    • 監(jiān)控:multi-phase code push一般要做實時的監(jiān)控:代碼邏輯錯誤的信息按照代碼版本(比如svn revision number)來分類,保證新版本的代碼不帶來新的錯誤;硬件的信息(CPU內存IO)按照選擇的機器、機柜、機群、數(shù)據(jù)中心分類:保證新的版本不引起更大資源消耗。當以上的信息都確認之后,可以給更大規(guī)模的機器安裝新代碼。
    • 難點:
    • 如果前端負載均衡器不能保證用戶和機器一致的話,一個用戶可能在發(fā)布過程中看到若干次新版本和若干次舊版本(比如第一個頁面是新版本,而AJAX是舊版本),版本不兼容會造成Javascript錯誤、CSS錯位,甚至一些邏輯錯誤;Javascript體系架構需要做一些安全檢測,或者要求程序員開發(fā)的時候考慮版本兼容(一般在快節(jié)奏的web開發(fā)里面不容易);或者用保持用戶和機器一致的前端負載均衡器;
    • 監(jiān)控的時候硬件資源消耗信息有可能因為發(fā)布過程本身產生很大的擾動,而與代碼無關(比如重啟之后緩存要重新warmup,增大IO,產生虛報),這需要代碼發(fā)布經理(pusher)的經驗來排除。
    • AB測試(AB testing):這是產品發(fā)布的常用手段。比起分步代碼發(fā)布,AB測試往往有更長的周期(比如幾個星期甚至幾個月)。基本操作是產品的開發(fā)者加一個或者多個配置控制(一般每個產品配置應該帶有配置的ID),允許通過調節(jié)相應的配置來讓一個產品發(fā)布到“逐步選擇”的用戶群。
    • 特點:“逐步選擇”是一個有代碼控制的邏輯過程。一般的產品基于用戶ID選擇;也有基于IP或者其他信息的。
    • 監(jiān)控:AB測試的數(shù)據(jù)一般按照產品配置ID和打開/關閉狀態(tài)分類,分析某個產品配置在打開的時候和關閉的時候對用戶行為的影響,和對硬件資源的消耗,由此可以預測這個產品在100%發(fā)布之后的影響。
    • 難點:
      • 如何做選擇:不同的產品有不同的選擇方式。一般可以考慮用戶ID,但如果跟瀏覽器的緩存效率關系很大的,可能需要考慮IP(因為一個瀏覽器可能被多個用戶使用);如果對非注冊用戶做的產品(比如各種注冊流程的測試),也可能需要IP,或者實時隨機選取;
      • 產品效果的評價:有些產品需要有網絡效應,如果按照用戶ID隨機抽取樣本,網絡效應可能被打破而使產品在AB測試期間失效 (比如一個社交網站的平均用戶連接度是50,即一個用戶連接其他50個用戶,按照1%用戶ID隨機抽樣的AB測試,那被選中的用戶子群內部的連接度可能不到1)
      • "逐步選擇"的邏輯本身是一個代碼,如果這個代碼寫錯的話可能帶來災難性后果。
    • 灰度上線(dark launch):我想“灰度上線”這個術語可能來源于dark launch。這是產品發(fā)布的另一種手段,往往用于需要一次發(fā)布的產品。 有一些產品可能因為市場營銷策略的原因,或者因為產品本身的特點(比如Facebook的用戶名注冊,或者可能像火車售票系統(tǒng))不能進行AB測試那樣的逐步上線。同時,我們又需要知道這個產品一次上線的時候帶來的影響,在這種情況下我們可以用灰度上線。基本操作是在用戶訪問網站的時候,打開新功能所需要運行的代碼,但把用戶可見的輸出、互動和寫操作都屏蔽掉,按照AB測試的方法逐步把這個去掉用戶互動的產品發(fā)布出去。
    • 特點:外界感覺不到新產品的測試過程
    • 監(jiān)控:和AB測試一樣,但主要關注的是系統(tǒng)的負載和資源消耗
    • 難點:
      • 如何屏蔽用戶互動:一方面要獲得幾乎真實的產品負載,另一方面希望不要把代碼搞亂導致真正發(fā)布的時候需要很大改動;
      • 對真實產品發(fā)布后負載的預測:產品發(fā)布之后可能形成正反饋(比如一個產品發(fā)布之后大受歡迎,引起更多的用戶注冊⋯⋯)灰度上線只能預測第一層效果,不能預測用戶行為的改變所引起的連鎖反應。
    這幾種方式好像都被稱作灰度上線,它們還是有很大不同的。根據(jù)產品發(fā)布需要,各有優(yōu)劣。
    posted @ 2012-07-04 16:33 小馬歌 閱讀(169) | 評論 (0)編輯 收藏
     

    在傳統(tǒng)軟件產品發(fā)布過程中(例如微軟的Windows 7的發(fā)布過程中),一般都會經歷Pre-Alpha、Alpha、Beta、Release candidate(RC)、RTM、General availability or General Acceptance (GA)等幾個階段(參考Software release life cycle)。可以看出傳統(tǒng)軟件的發(fā)布階段是從公司內部->外部小范圍測試>外部大范圍測試->正式發(fā)布,涉及的用戶數(shù)也是逐步放量的過程。

        在互聯(lián)網產品的發(fā)布過程中也較多采用此種發(fā)布方式:產品的發(fā)布過程不是一蹴而就,而是逐步擴大使用用戶的范圍,從公司內部用戶->忠誠度較高的種子用戶->更大范圍的活躍用戶->所有用戶。在此過程中,產品團隊根據(jù)用戶的反饋及時完善產品相關功能。此種發(fā)布方式,按照中國特色的叫法被冠以”灰度發(fā)布“、”灰度放量“、”分流發(fā)布“。

        關于“灰度發(fā)布”叫法的來源無從考察。只不過按照中國傳統(tǒng)哲學的說法來看,很符合中國人中庸的思維模式:自然界所有的事物總是以對稱、互補、和諧的形式存在,例如黑與白、陰與陽、正與負、福與禍。在二元對立的元素間存在相互過渡的階段,所謂”禍兮福所倚,福兮禍所伏“。具體到黑與白,在非黑即白中間還有中間色——灰色。于是出現(xiàn)了很多關于灰色的說法:灰盒測試,灰色管理(極力推薦 任正非:管理的灰度),灰色收入,灰色地帶等等。因此對于灰度發(fā)布實際上就是從不發(fā)布,然后逐漸過渡到正式發(fā)布的一個過程。

    1、灰度發(fā)布的作用

    • 及早獲得用戶的意見反饋,完善產品功能,提升產品質量
    • 讓用戶參與產品測試,加強與用戶互動
    • 降低產品升級所影響的用戶范圍
    • 。。。

    2、灰度發(fā)布的步驟

      1)、定義目標

      2)、選定策略:包括用戶規(guī)模、發(fā)布頻率、功能覆蓋度、回滾策略、運營策略、新舊系統(tǒng)部署策略等

      3)、篩選用戶:包括用戶特征、用戶數(shù)量、用戶常用功能、用戶范圍等

      4)、部署系統(tǒng):部署新系統(tǒng)、部署用戶行為分析系統(tǒng)(web analytics)、設定分流規(guī)則、運營數(shù)據(jù)分析、分流規(guī)則微調

      5)、發(fā)布總結:用戶行為分析報告、用戶問卷調查、社會化媒體意見收集、形成產品功能改進列表

      6)、產品完善

      7)、新一輪灰度發(fā)布或完整發(fā)布

    3、常見問題

      3.1)、以偏概全

             1)、問題特征:

                  a、選擇的樣本不具有代表性;

                  b、樣本具有代表性,但選擇樣本用戶使用習慣并沒有涵蓋所有核心功能 
             2)、解決方案

                  樣本選擇要多樣化,樣本的組合涵蓋大部分核心功能

      3.2)、知識的詛咒

            ”知識的詛咒“的說法來自《粘住》中實驗,具體可以自己搜索一下。我們自己對于自己開發(fā)的產品極為熟悉,于是乎想當然認為用戶也應當能夠理解產品的設計思路、產品的功能使用。

             1)、問題特征:

                   a、結果沒有量化手段;

                   b、只依賴于用戶問卷調查;

                   c、沒有web analytics系統(tǒng);

                   d、運營數(shù)據(jù)不全面,只有核心業(yè)務指標(例如交易量),沒有用戶體驗指標

                   e、對結果分析,只選擇對發(fā)布有利的信息,對其他視而不見 
              2)、解決方案: 
                   a、產品設計考慮產品量化指標 
                   b、結果分析依據(jù)量化指標而不是感覺

      3.3)、發(fā)布沒有回頭路可走

            1)、問題特征:

                  a、新舊系統(tǒng)用戶使用習慣差異太大,沒有兼容原有功能

                  b、新舊系統(tǒng)由于功能差異太大,無法并行運行,只能強制升級

                  c、新系統(tǒng)只是實現(xiàn)了舊系統(tǒng)部分功能,用戶要完整使用所有功能,要在 在新舊系統(tǒng)切換

                  d、新舊系統(tǒng)數(shù)據(jù)庫數(shù)據(jù)結構差異太大,無法并行運行

             2)、解決方案:

                  前期產品策劃重點考慮這些問題,包括:

                      回滾方案、 新舊系統(tǒng)兼容方案、用戶體驗的一致性、用戶使用習慣的延續(xù)性、新舊系統(tǒng)數(shù)據(jù)模型兼容性

      3.4)、用戶參與度不夠

             1)、問題特征:

                     a、指望用戶自己去挖掘所有功能。對于一個產品,大部分用戶經常只使用部分功能,用戶大部分也很懶惰,不會主動去挖掘產品功能 
                     b、互動渠道單一 
                     c、陷入“知識的詛咒”,不尊重參與用戶意見 
            2)、解決方案: 
                    a、善待吃螃蟹的樣本用戶,包括給予參與測試的用戶小獎勵(例如MS給參與Win7測試用戶正版License)、給用戶冠以title 
                    b、通過郵件、論壇、社區(qū)、Blog、Twitter等新媒體與用戶形成互動 
                    c、提供產品功能向導。在hotmail最近的升級后的功能tip,gmail的tip都有類似的產品功能導向。在產品中會提示類似于:你知道嗎,xx還提供xx功能,通過它你可以xx 。

     

    灰度發(fā)布,灰度放量,A/B Testing,A/B 測試,分流發(fā)布

    4、灰度發(fā)布  VS.  A/B測試

        灰度發(fā)布于互聯(lián)網公司常用A/B測試似乎比較類似,老外似乎并沒有所謂的灰度發(fā)布的概念。按照wikipedia中對A/B測試的定義,A/B測試又叫:A/B/N Testing、Multivariate Testing,因此本質上灰度測試可以算作A/B測試的一種特例。只不過為了術語上不至于等同搞混淆,談談自己理解的兩者的差異。

        灰度發(fā)布是對某一產品的發(fā)布逐步擴大使用群體范圍,也叫灰度放量

        A/B測試重點是在幾種方案中選擇最優(yōu)方案

       關于A/B測試可以參考這篇文章:A/B測試終極指南

    5、灰度發(fā)布引擎

       對于一般的小系統(tǒng)并不需要單獨的灰度發(fā)布引擎,可以參考A/B測試中做法,在頁面javascript或服務器端實現(xiàn)分流的規(guī)則即可。但對于大型的互聯(lián)網應用而言,單獨的用于管理用戶分流的發(fā)布引擎就很有必要了。“錢掌柜”分流發(fā)布模式 提到了原來阿里軟件所使用的灰度發(fā)布引擎,設計思路具有普遍性,可以供參考

    灰度發(fā)布,灰度放量,A/B Testing,A/B 測試,分流發(fā)布

    6、參考文檔

      “錢掌柜”分流發(fā)布模式

       百度百科:灰度發(fā)布

       A/B testing

       A/B測試終極指南

    posted @ 2012-07-04 16:26 小馬歌 閱讀(11906) | 評論 (0)編輯 收藏
     
    #!/bin/sh

    defaultHost=//192.168.0.1/proj
    defaultUserName=root
    mountPath=/path/proj
    host=$defaultHost
    userName=$defaultUserName

    if [ $# -eq 1 ]
    then
        host=$1
        umount -l $mountPath
    elif [ $# -eq 2 ]
    then
        host=$1
        userName=$2
        umount -l $mountPath
    elif [ $# -eq 3 ]
    then
        host=$1
        userName=$2
        mountPath=$3
        umount -l $mountPath
    fi
    scmd="mount -t cifs -o user=$userName,password=workstation,rw,file_mode=0777,dir_mode=0777 $host $mountPath"
    echo $scmd
    eval $scmd
    posted @ 2012-07-04 15:34 小馬歌 閱讀(227) | 評論 (0)編輯 收藏
     
    隨著互聯(lián)網web2.0網站的興起,非關系型的數(shù)據(jù)庫現(xiàn)在成了一個極其熱門的新領域,非關系數(shù)據(jù)庫產品的發(fā)展非常迅速。而傳統(tǒng)的關系數(shù)據(jù)庫在應付web2.0網站,特別是超大規(guī)模和高并發(fā)的SNS類型的web2.0純動態(tài)網站已經顯得力不從心,暴露了很多難以克服的問題,例如:

     

    1、High performance – 對數(shù)據(jù)庫高并發(fā)讀寫的需求
    web2.0網站要根據(jù)用戶個性化信息來實時生成動態(tài)頁面和提供動態(tài)信息,所以基本上無法使用動態(tài)頁面靜態(tài)化技術,因此數(shù)據(jù)庫并發(fā)負載非常高,往往要達到每秒上萬次讀寫請求。關系數(shù)據(jù)庫應付上萬次SQL查詢還勉強頂?shù)米。菓渡先f次SQL寫數(shù)據(jù)請求,硬盤IO就已經無法承受了。其實對于普通的BBS網站,往往也存在對高并發(fā)寫請求的需求,例如像JavaEye網站的實時統(tǒng)計在線用戶狀態(tài),記錄熱門帖子的點擊次數(shù),投票計數(shù)等,因此這是一個相當普遍的需求。

    2、Huge Storage – 對海量數(shù)據(jù)的高效率存儲和訪問的需求
    類似Facebook,twitter,F(xiàn)riendfeed這樣的SNS網站,每天用戶產生海量的用戶動態(tài),以Friendfeed為例,一個月就達到了2.5億條用戶動態(tài),對于關系數(shù)據(jù)庫來說,在一張2.5億條記錄的表里面進行SQL查詢,效率是極其低下乃至不可忍受的。再例如大型web網站的用戶登錄系統(tǒng),例如騰訊,盛大,動輒數(shù)以億計的帳號,關系數(shù)據(jù)庫也很難應付。

    3、High Scalability && High Availability- 對數(shù)據(jù)庫的高可擴展性和高可用性的需求
    在基于web的架構當中,數(shù)據(jù)庫是最難進行橫向擴展的,當一個應用系統(tǒng)的用戶量和訪問量與日俱增的時候,你的數(shù)據(jù)庫卻沒有辦法像web server和app server那樣簡單的通過添加更多的硬件和服務節(jié)點來擴展性能和負載能力。對于很多需要提供24小時不間斷服務的網站來說,對數(shù)據(jù)庫系統(tǒng)進行升級和擴展是非常痛苦的事情,往往需要停機維護和數(shù)據(jù)遷移,為什么數(shù)據(jù)庫不能通過不斷的添加服務器節(jié)點來實現(xiàn)擴展呢?

    在上面提到的“三高”需求面前,關系數(shù)據(jù)庫遇到了難以克服的障礙,而對于web2.0網站來說,關系數(shù)據(jù)庫的很多主要特性卻往往無用武之地,例如:

    1、數(shù)據(jù)庫事務一致性需求
    很多web實時系統(tǒng)并不要求嚴格的數(shù)據(jù)庫事務,對讀一致性的要求很低,有些場合對寫一致性要求也不高。因此數(shù)據(jù)庫事務管理成了數(shù)據(jù)庫高負載下一個沉重的負擔。

    2、數(shù)據(jù)庫的寫實時性和讀實時性需求
    對關系數(shù)據(jù)庫來說,插入一條數(shù)據(jù)之后立刻查詢,是肯定可以讀出來這條數(shù)據(jù)的,但是對于很多web應用來說,并不要求這么高的實時性,比方說我(JavaEye的robbin)發(fā)一條消息之后,過幾秒乃至十幾秒之后,我的訂閱者才看到這條動態(tài)是完全可以接受的。

    3、對復雜的SQL查詢,特別是多表關聯(lián)查詢的需求
    任何大數(shù)據(jù)量的web系統(tǒng),都非常忌諱多個大表的關聯(lián)查詢,以及復雜的數(shù)據(jù)分析類型的復雜SQL報表查詢,特別是SNS類型的網站,從需求以及產品設計角度,就避免了這種情況的產生。往往更多的只是單表的主鍵查詢,以及單表的簡單條件分頁查詢,SQL的功能被極大的弱化了。

    因此,關系數(shù)據(jù)庫在這些越來越多的應用場景下顯得不那么合適了,為了解決這類問題的非關系數(shù)據(jù)庫應運而生,現(xiàn)在這兩年,各種各樣非關系數(shù)據(jù)庫,特別是鍵值數(shù)據(jù)庫(Key-Value Store DB)風起云涌,多得讓人眼花繚亂。前不久國外剛剛舉辦了NoSQL Conference,各路NoSQL數(shù)據(jù)庫紛紛亮相,加上未亮相但是名聲在外的,起碼有超過10個開源的NoSQLDB,例如:

    Redis,Tokyo Cabinet,Cassandra,Voldemort,MongoDB,Dynomite,HBase,CouchDB,Hypertable, Riak,Tin, Flare, Lightcloud, KiokuDB,Scalaris, Kai, ThruDB,  ……

    這些NoSQL數(shù)據(jù)庫,有的是用C/C++編寫的,有的是用Java編寫的,還有的是用Erlang編寫的,每個都有自己的獨到之處,看都看不過來了,我(robbin)也只能從中挑選一些比較有特色,看起來更有前景的產品學習和了解一下。這些NoSQL數(shù)據(jù)庫大致可以分為以下的三類:

    一、滿足極高讀寫性能需求的Kye-Value數(shù)據(jù)庫:Redis,Tokyo Cabinet, Flare

    高性能Key-Value數(shù)據(jù)庫的主要特點就是具有極高的并發(fā)讀寫性能,Redis,Tokyo Cabinet, Flare,這3個Key-Value DB都是用C編寫的,他們的性能都相當出色,但出了出色的性能,他們還有自己獨特的功能:

    1、Redis
    Redis是一個很新的項目,剛剛發(fā)布了1.0版本。Redis本質上是一個Key-Value類型的內存數(shù)據(jù)庫,很像memcached,整個數(shù)據(jù)庫統(tǒng)統(tǒng)加載在內存當中進行操作,定期通過異步操作把數(shù)據(jù)庫數(shù)據(jù)flush到硬盤上進行保存。因為是純內存操作,Redis的性能非常出色,每秒可以處理超過10萬次讀寫操作,是我知道的性能最快的Key-Value DB。

    Redis的出色之處不僅僅是性能,Redis最大的魅力是支持保存List鏈表和Set集合的數(shù)據(jù)結構,而且還支持對List進行各種操作,例如從List兩端push和pop數(shù)據(jù),取List區(qū)間,排序等等,對Set支持各種集合的并集交集操作,此外單個value的最大限制是1GB,不像memcached只能保存1MB的數(shù)據(jù),因此Redis可以用來實現(xiàn)很多有用的功能,比方說用他的List來做FIFO雙向鏈表,實現(xiàn)一個輕量級的高性能消息隊列服務,用他的Set可以做高性能的tag系統(tǒng)等等。另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一個功能加強版的memcached來用。

    Redis的主要缺點是數(shù)據(jù)庫容量受到物理內存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,并且它沒有原生的可擴展機制,不具有scale(可擴展)能力,要依賴客戶端來實現(xiàn)分布式讀寫,因此Redis適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運算上。目前使用Redis的網站有github,Engine Yard。

    2、Tokyo Cabinet和Tokoy Tyrant
    TC和TT的開發(fā)者是日本人Mikio Hirabayashi,主要被用在日本最大的SNS網站mixi.jp上,TC發(fā)展的時間最早,現(xiàn)在已經是一個非常成熟的項目,也是Kye-Value數(shù)據(jù)庫領域最大的熱點,現(xiàn)在被廣泛的應用在很多很多網站上。TC是一個高性能的存儲引擎,而TT提供了多線程高并發(fā)服務器,性能也非常出色,每秒可以處理4-5萬次讀寫操作。

    TC除了支持Key-Value存儲之外,還支持保存Hashtable數(shù)據(jù)類型,因此很像一個簡單的數(shù)據(jù)庫表,并且還支持基于column的條件查詢,分頁查詢和排序功能,基本上相當于支持單表的基礎查詢功能了,所以可以簡單的替代關系數(shù)據(jù)庫的很多操作,這也是TC受到大家歡迎的主要原因之一,有一個Ruby的項目miyazakiresistance將TT的hashtable的操作封裝成和ActiveRecord一樣的操作,用起來非常爽。

    TC/TT在mixi的實際應用當中,存儲了2000萬條以上的數(shù)據(jù),同時支撐了上萬個并發(fā)連接,是一個久經考驗的項目。TC在保證了極高的并發(fā)讀寫性能的同時,具有可靠的數(shù)據(jù)持久化機制,同時還支持類似關系數(shù)據(jù)庫表結構的hashtable以及簡單的條件,分頁和排序操作,是一個很棒的NoSQL數(shù)據(jù)庫。

    TC的主要缺點是在數(shù)據(jù)量達到上億級別以后,并發(fā)寫數(shù)據(jù)性能會大幅度下降,NoSQL: If Only It Was That Easy提到,他們發(fā)現(xiàn)在TC里面插入1.6億條2-20KB數(shù)據(jù)的時候,寫入性能開始急劇下降。看來是當數(shù)據(jù)量上億條的時候,TC性能開始大幅度下降,從TC作者自己提供的mixi數(shù)據(jù)來看,至少上千萬條數(shù)據(jù)量的時候還沒有遇到這么明顯的寫入性能瓶頸。

    這個是Tim Yang做的一個Memcached,Redis和Tokyo Tyrant的簡單的性能評測,僅供參考

    3、Flare
    TC是日本第一大SNS網站mixi開發(fā)的,而Flare是日本第二大SNS網站green.jp開發(fā)的,有意思吧。Flare簡單的說就是給TC添加了scale功能。他替換掉了TT部分,自己另外給TC寫了網絡服務器,F(xiàn)lare的主要特點就是支持scale能力,他在網絡服務端之前添加了一個node server,來管理后端的多個服務器節(jié)點,因此可以動態(tài)添加數(shù)據(jù)庫服務節(jié)點,刪除服務器節(jié)點,也支持failover。如果你的使用場景必須要讓TC可以scale,那么可以考慮flare。

    flare唯一的缺點就是他只支持memcached協(xié)議,因此當你使用flare的時候,就不能使用TC的table數(shù)據(jù)結構了,只能使用TC的key-value數(shù)據(jù)結構存儲。

    二、滿足海量存儲需求和訪問的面向文檔的數(shù)據(jù)庫:MongoDBCouchDB

    面向文檔的非關系數(shù)據(jù)庫主要解決的問題不是高性能的并發(fā)讀寫,而是保證海量數(shù)據(jù)存儲的同時,具有良好的查詢性能。MongoDB是用C++開發(fā)的,而CouchDB則是Erlang開發(fā)的:

    1、MongoDB
    MongoDB是一個介于關系數(shù)據(jù)庫和非關系數(shù)據(jù)庫之間的產品,是非關系數(shù)據(jù)庫當中功能最豐富,最像關系數(shù)據(jù)庫的。他支持的數(shù)據(jù)結構非常松散,是類似json的bjson格式,因此可以存儲比較復雜的數(shù)據(jù)類型。Mongo最大的特點是他支持的查詢語言非常強大,其語法有點類似于面向對象的查詢語言,幾乎可以實現(xiàn)類似關系數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。

    Mongo主要解決的是海量數(shù)據(jù)的訪問效率問題,根據(jù)官方的文檔,當數(shù)據(jù)量達到50GB以上的時候,Mongo的數(shù)據(jù)庫訪問速度是MySQL的10倍以上。Mongo的并發(fā)讀寫效率不是特別出色,根據(jù)官方提供的性能測試表明,大約每秒可以處理0.5萬-1.5次讀寫請求。對于Mongo的并發(fā)讀寫性能,我(robbin)也打算有空的時候好好測試一下。

    因為Mongo主要是支持海量數(shù)據(jù)存儲的,所以Mongo還自帶了一個出色的分布式文件系統(tǒng)GridFS,可以支持海量的數(shù)據(jù)存儲,但我也看到有些評論認為GridFS性能不佳,這一點還是有待親自做點測試來驗證了。

    最后由于Mongo可以支持復雜的數(shù)據(jù)結構,而且?guī)в袕姶蟮臄?shù)據(jù)查詢功能,因此非常受到歡迎,很多項目都考慮用MongoDB來替代MySQL來實現(xiàn)不是特別復雜的Web應用,比方說why we migrated from MySQL to MongoDB就是一個真實的從MySQL遷移到MongoDB的案例,由于數(shù)據(jù)量實在太大,所以遷移到了Mongo上面,數(shù)據(jù)查詢的速度得到了非常顯著的提升。

    MongoDB也有一個ruby的項目MongoMapper,是模仿Merb的DataMapper編寫的MongoDB的接口,使用起來非常簡單,幾乎和DataMapper一模一樣,功能非常強大易用。

    2、CouchDB
    CouchDB現(xiàn)在是一個非常有名氣的項目,似乎不用多介紹了。但是我卻對CouchDB沒有什么興趣,主要是因為CouchDB僅僅提供了基于HTTP REST的接口,因此CouchDB單純從并發(fā)讀寫性能來說,是非常糟糕的,這讓我立刻拋棄了對CouchDB的興趣。

    三、滿足高可擴展性和可用性的面向分布式計算的數(shù)據(jù)庫:Cassandra,Voldemort

    面向scale能力的數(shù)據(jù)庫其實主要解決的問題領域和上述兩類數(shù)據(jù)庫還不太一樣,它首先必須是一個分布式的數(shù)據(jù)庫系統(tǒng),由分布在不同節(jié)點上面的數(shù)據(jù)庫共同構成一個數(shù)據(jù)庫服務系統(tǒng),并且根據(jù)這種分布式架構來提供online的,具有彈性的可擴展能力,例如可以不停機的添加更多數(shù)據(jù)節(jié)點,刪除數(shù)據(jù)節(jié)點等等。因此像Cassandra常常被看成是一個開源版本的Google BigTable的替代品。Cassandra和Voldemort都是用Java開發(fā)的:

    1、Cassandra
    Cassandra項目是Facebook在2008年開源出來的,隨后Facebook自己使用Cassandra的另外一個不開源的分支,而開源出來的Cassandra主要被Amazon的Dynamite團隊來維護,并且Cassandra被認為是Dynamite2.0版本。目前除了Facebook之外,twitter和digg.com都在使用Cassandra。

    Cassandra的主要特點就是它不是一個數(shù)據(jù)庫,而是由一堆數(shù)據(jù)庫節(jié)點共同構成的一個分布式網絡服務,對Cassandra的一個寫操作,會被復制到其他節(jié)點上去,對Cassandra的讀操作,也會被路由到某個節(jié)點上面去讀取。對于一個Cassandra群集來說,擴展性能是比較簡單的事情,只管在群集里面添加節(jié)點就可以了。我看到有文章說Facebook的Cassandra群集有超過100臺服務器構成的數(shù)據(jù)庫群集。

    Cassandra也支持比較豐富的數(shù)據(jù)結構和功能強大的查詢語言,和MongoDB比較類似,查詢功能比MongoDB稍弱一些,twitter的平臺架構部門領導Evan Weaver寫了一篇文章介紹Cassandra:http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有非常詳細的介紹。

    Cassandra以單個節(jié)點來衡量,其節(jié)點的并發(fā)讀寫性能不是特別好,有文章說評測下來Cassandra每秒大約不到1萬次讀寫請求,我也看到一些對這個問題進行質疑的評論,但是評價Cassandra單個節(jié)點的性能是沒有意義的,真實的分布式數(shù)據(jù)庫訪問系統(tǒng)必然是n多個節(jié)點構成的系統(tǒng),其并發(fā)性能取決于整個系統(tǒng)的節(jié)點數(shù)量,路由效率,而不僅僅是單節(jié)點的并發(fā)負載能力。

    2、Voldemort
    Voldemort是個和Cassandra類似的面向解決scale問題的分布式數(shù)據(jù)庫系統(tǒng),Cassandra來自于Facebook這個SNS網站,而Voldemort則來自于Linkedin這個SNS網站。說起來SNS網站為我們貢獻了n多的NoSQL數(shù)據(jù)庫,例如Cassandar,Voldemort,Tokyo Cabinet,F(xiàn)lare等等。Voldemort的資料不是很多,因此我沒有特別仔細去鉆研,Voldemort官方給出Voldemort的并發(fā)讀寫性能也很不錯,每秒超過了1.5萬次讀寫。

    從Facebook開發(fā)Cassandra,Linkedin開發(fā)Voldemort,我們也可以大致看出國外大型SNS網站對于分布式數(shù)據(jù)庫,特別是對數(shù)據(jù)庫的scale能力方面的需求是多么殷切。前面我(robbin)提到,web應用的架構當中,web層和app層相對來說都很容易橫向擴展,唯有數(shù)據(jù)庫是單點的,極難scale,現(xiàn)在Facebook和Linkedin在非關系型數(shù)據(jù)庫的分布式方面探索了一條很好的方向,這也是為什么現(xiàn)在Cassandra這么熱門的主要原因。

    如今,NoSQL數(shù)據(jù)庫是個令人很興奮的領域,總是不斷有新的技術新的產品冒出來,改變我們已經形成的固有的技術觀念,我自己(robbin)稍微了解了一些,就感覺自己深深的沉迷進去了,可以說NoSQL數(shù)據(jù)庫領域也是博大精深的,我(robbin)也只能淺嘗輒止,我(robbin)寫這篇文章既是自己一點點鉆研心得,也是拋磚引玉,希望吸引對這個領域有經驗的朋友來討論和交流。

    從我(robbin)個人的興趣來說,分布式數(shù)據(jù)庫系統(tǒng)不是我能實際用到的技術,因此不打算花時間深入,而其他兩個數(shù)據(jù)領域(高性能NoSQLDB和海量存儲NoSQLDB)都是我很感興趣的,特別是Redis,TT/TC和MongoDB這3個NoSQL數(shù)據(jù)庫,因此我接下來將寫三篇文章分別詳細介紹這3個數(shù)據(jù)庫

    posted @ 2012-06-28 14:28 小馬歌 閱讀(217) | 評論 (0)編輯 收藏
     
         摘要: 本文參考自官方的手冊:http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ConditionalOperators%3A%3C%2C%3C%3D%2C%3E%2C%3E%3D1 ) . 大于,小于,大于或等于,小于或等于$gt:大于$lt:小于$gte:大于或等于$lte:小于或等于例子:db.collectio...  閱讀全文
    posted @ 2012-06-28 14:15 小馬歌 閱讀(200) | 評論 (0)編輯 收藏
     
         摘要: 在前面的文章“mongodb 查詢的語法”里,我介紹了Mongodb的常用查詢語法,Mongodb的update操作也有點復雜,我結合自己的使用經驗,在這里介紹一下,給用mongodb的朋友看看,也方便以后自己用到的時候查閱:注:在這篇文章及上篇文章內講的語法介紹都是在mongodb shell環(huán)境內的,和真正運用語言編程(如java,php等)使用時,...  閱讀全文
    posted @ 2012-06-28 14:14 小馬歌 閱讀(4117) | 評論 (0)編輯 收藏
     
    一、連接數(shù)據(jù)庫主機
    連接本地主機,端口為27017:
    $connection = new Mongo();
    連接遠程主機,端口為默認端口:
    $connection= new Mongo( "192.168.2.1" );
    連接遠程主機,端口為指定端口:
    $connection = new Mongo( "192.168.2.1:65432" );
    選擇數(shù)據(jù)庫,如果指定的數(shù)據(jù)庫不存在,則會自動創(chuàng)建一個新的數(shù)據(jù)庫,有2種方法:
    $db = $connection->selectDB('dbname');
    $db = $connection->dbname;
    選擇集合(collection),與使用關系型數(shù)據(jù)庫中的表類似,有2種方法:
    $collection = $db->selectCollection('people');
    $collection = $db->people;
    二、插入新文檔(document)
    collection對象用來執(zhí)行信息管理,例如,想存儲一個關于某人的信息,可以如下編碼:
    $person = array(
     'name' => 'Cesar Rodas',
     'email' => 'crodas@php.net',
     'address' => array(
      array(
       'country' => 'PY',
       'zip' => '2160',
       'address1' => 'foo bar'
      ),
      array(
       'country' => 'PY',
       'zip' => '2161',
       'address1' => 'foo bar bar foo'
      ),
     ),
     'sessions' => 0,
    );
    $safe_insert = true;
    $collection->insert($person, $safe_insert);
    $person_identifier = $person['_id'];
    其中:
    $safe_insert參數(shù)用于等待MongoDB完成操作,以便確定是否成功,默認值為false,當有大量記錄插入時使用該參數(shù)會比較有用。
    插入新文檔后,MongoDB會返回一個記錄標識。
    三、更新文檔
    例如,更新上面已經創(chuàng)建的個人信息,增加sessions屬性值,在第1個address處增加address2屬性,刪除第2個address,代碼如下:
    首先,定義一個filter(過濾器)告訴MongoDB要更新一個指定的文檔
    $filter = array('email' => 'crodas@php.net');
    $new_document = array(
     '$inc' => array('sessions' => 1),
     '$set' => array(
       'address.0.address2' =>  'Some foobar street',
     ),
     '$unset' => array('address.1' => 1),
    );
    $options['multiple'] = false;
    $collection->update(
     $filter,
     $new_document,
     $options
    );
    MongoDB也支持批量更新,與關系型數(shù)據(jù)庫類似,可以更新給定條件的所有文檔,如果想這么做的話,就需要設置options的multiple的值為true.
    四、查詢文檔
    定義一個符合給定標準的條件過濾器,通過使用查詢選擇器來獲取文檔。
    例,通過e-mail address來獲取信息:
    $filter = array('email' => 'crodas@php.net');
    $cursor = $collection->find($filter);
    foreach ($cursor as $user) 
    {
      var_dump($user);
    }
    例,獲取sessions大于10的信息:
    $filter = array('sessions' => array('$gt' => 10));
    $cursor = $collection->find($filter);
    例,獲取沒有設置sessions屬性的信息:
    $filter = array(
     'sessions' => array('$exists' => false)
    );
    $cursor = $collection->find($filter);
    例,獲取地址在PY并且sessions大于15的信息:
    $filter = array(
     'address.country' => 'PY',
     'sessions' => array('$gt' => 10)
    );
    $cursor = $collection->find($filter);
    有一個重要的細節(jié)需要注意,只有當需要結果的時候查詢才會被執(zhí)行,在第1個例子中,當foreach循環(huán)開始時,查詢才被執(zhí)行。
    這是個很有用的特性,因為這可以通過在游標(cursor)中增加選項來取回結果,恰好在定義查詢后,執(zhí)行查詢前這個時刻。例如,可以設置選項來執(zhí)行分頁,或者獲取指定數(shù)目的匹配的文檔。
    $total = $cursor->total();
    $cursor->limit(20)->skip(40);
    foreach($cursor as $user) {
    }
    五、獲取文檔的聚類
    MongoDB支持結果的聚類,類似于關系數(shù)據(jù)庫,可以使用count,distinct和group等聚類操作。
    聚類查詢返回數(shù)組(array),而不是整個文檔對象。
    分組操作允許定義用Javascript編寫的MongoDB服務器端功能,該操作執(zhí)行分組屬性。因為可以執(zhí)行許多帶有分組值的操作類型,所以會更靈活,但是相比SQL執(zhí)行例如SUM(),AVG()等
    簡單的分組操作來說,這還是有些困難。
    下面這個例子演示了如何獲取國家的的地址列表,以及匹配地址的國家出現(xiàn)的次數(shù):
    $countries = $collection->distinct(
     array("address.country")
    );
    $result = $collection->group(
     
     array("address.country" => True),
     
     array("sum" => 0),    
        
     "function (obj, prev) { prev.sum += 1; }",
     
     array("session" => array('$gt' => 10))
    );
    六、刪除文檔
    刪除文檔與獲取或更新文檔很類似。
    $filter = array('field' => 'foo');
    $collection->remove($filter);
    要注意,默認所有符合條件的文檔都會被刪除,如果只想刪除符合條件的第1個文檔,那么在給remove函數(shù)的第二個參數(shù)賦值為true。
    七、索引支持
    有一個很重要的特點,使得決定選擇MongoDB,而不是選擇其它的類似的面向文檔的數(shù)據(jù)庫,這個特點就是對索引的支持,這和關系型數(shù)據(jù)庫的表索引很類似,并不是所有的面向文檔的數(shù)據(jù)庫都
    提供內置的索引支持。
    使用MongoDB的創(chuàng)建索引功能可以避免在查詢期間在所有文檔中進行操作,這就象關系數(shù)據(jù)庫中使用索引來避免全表查詢一樣。這可以加速那些涉及到索引屬性的符合條件的文檔的查詢。
    例如,如果想在e-mail地址屬性上建立唯一的索引,如下所示:
    $collection->ensureIndex(
     array('email' => 1),
     array('unique' => true, 'background' => true)
    );
    第1個數(shù)組參數(shù)描述將要成為索引的所有屬性,可以是1個或多個屬性。
    默認情況下,索引的創(chuàng)建是一個同步操作,所以,如果文檔數(shù)目很大的話,把索引的創(chuàng)建放在后臺運行會是個好主意,就象上面例子所演示的。
    只有一個屬性的索引可能不夠用,下面這個例子演示如何通過在2個屬性上定義索引來加速查詢。
    $collection->ensureIndex(  
      array('address.country' => 1, 'sessions' => 1),
      array('background' => true)
    );
    每個索引的值定義了索引的順序:1表示降序(descending),-1表示升序(ascending)
    索引順序在有排序選項的查詢優(yōu)化中是有用的,如下例所示:
    $filter = array(    
     'address.country' => 'PY',
    );
    $cursor = $collection->find($filter)->order(
      array('sessions' => -1)
    );
    $collection->ensureIndex(
     array('address.country' => 1, 'sessions' => -1),
     array('background' => true)
    );

     

     

    八、實際應用
    一些開發(fā)人員可能害怕使用一種新型的數(shù)據(jù)庫,因為它和他們以前工作中用過的那些不同。
    在理論上學習新事物不同于在實踐中學習如何使用,所以,這部分內容將通過比較基于SQL的關系型數(shù)據(jù)庫,比如MySQL,來解釋如何用MongoDB來開發(fā)實際應用,這樣就可以熟悉這兩種途徑
    的不同。
    例如,我們將構建一個blog系統(tǒng),有用戶,提交和評論功能。在使用關系型數(shù)據(jù)庫的時候,你可以象下面這樣通過定義表模式來實現(xiàn)它。


    在MongoDB中實現(xiàn)同樣的文檔定義如下:
    $users = array(
     'username' => 'crodas',   
     'name' => 'Cesar Rodas',
    );
    $posts = array(
     'uri' => '/foo-bar-post',
     'author_id' => $users->_id,
     'title' => 'Foo bar post',
     'summary' => 'This is a summary text',
     'body' => 'This is the body',
     'comments' => array(
      array(
       'name' => 'user',
       'email' => 'foo@bar.com',
       'content' => 'nice post'
      ) 
     )
    );
    你可能注意到,我們只用一個文檔就代替了posts和comments兩個表,這是因為comments是post文檔的子文檔。這樣做使實現(xiàn)更簡單,在你想存取發(fā)布內容和它的評論時,會節(jié)省查詢數(shù)據(jù)庫的時間。
    為了更簡潔,用戶所做評論的細節(jié)可以和評論的定義合并,所以你可以用一個查詢來獲取所發(fā)布的內容,評論和用戶這些信息。
    $posts = array(
     'uri' => '/foo-bar-post',
     'author_id' => $users->_id,
     'author_name' => 'Cesar Rodas',
     'author_username' => 'crodas',
     'title' => 'Foo bar post',
     'summary' => 'This is a summary text',
     'body' => 'This is the body',
     'comments' => array(
      array(
       'name' => 'user',
       'email' => 'foo@bar.com',
       'comment' => 'nice post'
      ), 
     )
    );
    這意味著會存在一些重復信息,但現(xiàn)在磁盤空間比CPU的RAM要便宜得多,以空間換時間,網站訪問者的耐心和時間更重要。如果你關注重復信息的同步,那么在更新author信息的時候,你可以執(zhí)行下面這個更新查詢來解決這個問題。
    $filter = array(   
     'author_id' => $author['_id'],
    );
    $data = array(
     '$set' => array(
      'author_name' => 'Cesar D. Rodas',
      'author_username' => 'cesar',
     )
    );
    $collection->update($filter, $data, array(
      'multiple' => true)
    );
    以上是我們對數(shù)據(jù)模型的轉換和優(yōu)化,下面將重寫一些用在MongoDB中的和SQL等價的查詢。
    SELECT * FROM posts
     INNER JOIN users ON users.id = posts.user_id
     WHERE URL = :url;
    SELECT  * FROM comments WHERE post_id = $post_id;
    首先,增加索引:
    $collection->ensureIndex( 
     array('uri' => 1),
     array('unique' => 1, 'background')
    );
    $collection->find(array('uri' => '<uri>'));
    INSERT INTO comments(post_id, name, email, contents)
     VALUES(:post_id, :name, :email, :comment);
    $comment = array(   
     'name' => $_POST['name'],   
     'email' => $_POST['email'],   
     'comment' => $_POST['comment'],
    );
    $filter = array(
     'uri' => $_POST['uri'], 
    );
    $collection->update($filter, array(
     '$push' => array('comments' => $comment))
    );
    SELECT * FROM posts WHERE id IN (
     SELECT DISTINCT post_id FROM comments WHERE email = :email
    );
    首先,增加索引:
    $collection->ensureIndex(
     array('comments.email' => 1),
     array('background' => 1)
    );
    $collection->find( array('comments.email' => $email) );
    九、用MongoDB存儲文件
    MongoDB也提供許多超過基本數(shù)據(jù)庫操作的特點。例如,它提供了在數(shù)據(jù)庫中存儲小文件和大文件的解決方案。
    文件被自動分塊(塊)。如果MongoDB運行在自動分片(auto-sharded)環(huán)境,文件塊也會被跨多個服務器復制。
    有效地解決文件的存儲是一個相當困難的問題,尤其是當你需要管理大量的文件時。把文件保存在本地文件系統(tǒng)中通常不是個好的方案。
    一個困難的例子是YouTube必須有效地服務那些上百萬視頻的小圖片,或者由Facebook為數(shù)十億圖片提供的高效運行服務。
    MongoDB通過創(chuàng)建兩個內部集合(collections)來解決這個問題:文件集合保存關于文件元數(shù)據(jù)的信息,塊集合保存關于文件塊的信息。
    如果你想存儲一個大的視頻文件,你可以使用如下這樣的代碼:
    $metadata = array(
     "filename" => "path.avi",
     "downloads" => 0,   
     "comment" => "This file is foo bar",   
     "permissions" => array(
      "crodas" => "write",  
      "everybody" => "read",
     )
    );
    $grid = $db->getGridFS();
    $grid->storeFile("/file/to/path.avi", $metadata);
    正如你所看到的,這很簡單且容易理解。
    十、Map-Reduce
    Map-Reduce是一種處理大量信息的操作手段。map操作應用于每個文檔并產生一套新的key-value數(shù)據(jù)對。reduce操作使用map功能產生的結果并產生基本每個key的單一結果。
    MongoDB Map-Reduce功能可以應用到集合上用于數(shù)據(jù)轉換,這和Hadoop很類似。
    當map處理完成后,結果被保存并且通過鍵值(key value)被分組。對每個結果鍵(key),使用2個參數(shù)來調用reduce功能:鍵(key)及其所有值的數(shù)組。
    為了更好地理解它的工作原理,我們假設有了前面定義過的blog的提交文檔,接下來你想使每個提交的內容有一系列的tag,如果你想獲得關于這些tag的統(tǒng)計情況,你只需要像下面這樣計算一下即可:
    首先定義map和reduce功能代碼,
    $map = new  MongoCode("function () {
      var i;
      for (i=0; i < this.tags.length; i++) {
      
       emit(this.tags[i], {count: 1});
      }
    }");
    $reduce = new MongoCode("function (key, values) {
      var i, total=0;
      for (i=0; i < values.length; i++) {
       total = values[i].count;
      }
      return {count: total}
    }");
    然后執(zhí)行map-reduce命令:
    $map_reduce = array(
     
     'out' => 'tags_info',
     
     'verbose' => true,
     
     'mapreduce' => 'posts',
     'map' => $map,
     'reduce' => $reduce,
    );
    $information = $db->command($map_reduce);
    var_dump($information);
    如果MongoDB運行在切片(sharded)環(huán)境,那么這個數(shù)據(jù)處理功能將會在所有shard節(jié)點上并行。
    要知道執(zhí)行map-reduce處理通常是很慢的。它的目的是把大量的數(shù)據(jù)分布在許多服務器上。所以,如果你有許多服務器,你就可以把這個操作分布在這些服務器上進行處理并獲得結果,這會比在一臺服務器上運行所需的時間要少得多。
    建議在后臺運行map-reduce處理,因為它們需要花比較長的時候才能完成。在這種情況下,如果通過Gearman來異步管理啟動它是個不錯的方法。
    十一、Auto-sharding
    在前面多次提到sharding,但你可能并不熟悉這個概念。
    Data sharding是一種把數(shù)據(jù)分布在多個服務器上的數(shù)據(jù)庫技術手段。
    MongoDB只需要很少的配置就可完成auto-sharding。然而,安裝和配置一個shard已超出本文章的范圍。
    下面這張圖展示了工作在shard環(huán)境中的MongoDB,這樣你會在你使用sharding時都發(fā)生了什么有個了解。


     十二、其它
    正則表達式使用面面的格式:
    "/<regex>/<flags>"
    和SQL語句中的 username LIKE '%bar%'等價的方式如下:
    <?php
    $filter = array(
    'username' => new MongoRegex("/.*bar.*/i"),
    );
    $collection->find($filter);
    ?>
    在使用Regex時要小心,大多時候它不能使用索引,因此它將對整個數(shù)據(jù)掃描,所以比較好的方法是對文檔的數(shù)目進行限制。
    <?php
    $filter = array(
    'username' => new MongoRegex("/.*bar.*/i"),
    'karma' => array('$gt' => 10),
    );
    $collection->find($filter);
    ?>
    使用Regex可以完成如下這個復雜的查詢:
    <?php
    $filter = array(
    'username' => new MongoRegex("/[a-z][a-z0-9\_]+(\_[0-9])?/i"),
    'karma' => array('$gt' => 10),
    );
    $collection->find($filter);
    ?>
    posted @ 2012-06-25 17:13 小馬歌 閱讀(3945) | 評論 (0)編輯 收藏
     

    ECSHOP2.7.2 本來是個不錯的網店程序,但由于版權多出加密,有些需要去除版權的朋友會碰到一些困難,本人特整理分享最新版ecshop去處版權方法給大家分享:

    1.刪除頂部標題欄"Powered by Ecshop"信息:

    使用文本編輯器(推薦Dreamweaver,UltraEdit,記事本編輯容易出錯請勿用)打開 ecshop根目錄/includes/lib_main.php, 找到如下代碼:
    /* 初始化“頁面標題”和“當前位置” */
    $page_title = $GLOBALS['_CFG']['shop_title'] . ' - ' . 'Powered by ECShop';
    在這一句的Powered by ECShop就是標題欄的版權部分,可以刪除或者改成你自己想顯示的其他文字內容

    2 .細心的朋友可能發(fā)現(xiàn),按第一點刪改版權后ECshop像發(fā)瘋一樣會在頁面上隨機出現(xiàn)Powered by ECShop文字,這是因為康盛公司的防盜版措施,我們還需要這一步驟操作

    找到js/common.js文件
       該文件第261行到第353行代碼刪除。就是以下代碼

    1.    onload = function()
    2. {
    3. var link_arr = document.getElementsByTagName(String.fromCharCode(65));
    4. var link_str;
    5. var link_text;
    6. var regg, cc;
    7. var rmd, rmd_s, rmd_e, link_eorr = 0;
    8. var e = new Array(97, 98, 99,
    9.                   100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
    10.                   110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
    11.                   120, 121, 122
    12.                   );
    13.    try
    14.    {
    15. for(var i = 0; i < link_arr.length; i++)
    16. {
    17.    link_str = link_arr.href;
    18.    if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, e[18], e[7], e[14],
    19.                                           e[15], 46, 99, 111, e[12])) != -1)
    20.    {
    21.        if ((link_text = link_arr.innerText) == undefined)
    22.        {
    23.          throw "noIE";
    24.        }
    25.        regg = new RegExp(String.fromCharCode(80, 111, 119, 101, 114, 101, 100, 46, 42, 98, 121,
    26. 46, 42, 69, 67, 83, e[7], e[14], e[15]));
    27.        if ((cc = regg.exec(link_text)) != null)
    28.        {
    29.       if (link_arr.offsetHeight == 0)
    30.       {
    31.          break;
    32.       }
    33.       link_eorr = 1;
    34.       break;
    35.        }
    36.    }
    37.    else
    38.    {
    39.        link_eorr = link_eorr ? 0 : link_eorr;
    40.        continue;
    41.    }
    42. }
    43.    } // IE
    44.    catch(exc)
    45.    {
    46. for(var i = 0; i < link_arr.length; i++)
    47. {
    48.    link_str = link_arr.href;
    49.    if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, 115, 104, e[14],
    50.                                               e[15], 46, 99, 111, e[12])) != -1)
    51.    {
    52.        link_text = link_arr.textContent;
    53.        regg = new RegExp(String.fromCharCode(80, 111, 119, 101, 114, 101, 100, 46, 42, 98, 121,
    54. 46, 42, 69, 67, 83, e[7], e[14], e[15]));
    55.        if ((cc = regg.exec(link_text)) != null)
    56.        {
    57.       if (link_arr.offsetHeight == 0)
    58.       {
    59.          break;
    60.       }
    61.       link_eorr = 1;
    62.       break;
    63.        }
    64.    }
    65.    else
    66.    {
    67.        link_eorr = link_eorr ? 0 : link_eorr;
    68.        continue;
    69.    }
    70. }
    71.    } // FF
    72.    try
    73.    {
    74. rmd = Math.random();
    75. rmd_s = Math.floor(rmd * 10);
    76. if (link_eorr != 1)
    77. {
    78.    rmd_e = i - rmd_s;
    79.    link_arr[rmd_e].href = String.fromCharCode(104, 116, 116, 112, 58, 47, 47, 119, 119,
    80. 119,46,
    81.                                                    101, 99, 115, 104, 111, 112, 46, 99, 111,
    82. 109);
    83.    link_arr[rmd_e].innerHTML = String.fromCharCode(
    84.                                     80, 111, 119, 101, 114, 101, 100,38, 110, 98, 115, 112,
    85. 59, 98,
    86.                                     121,38, 110, 98, 115, 112, 59,60, 115, 116, 114, 111,
    87. 110, 103,
    88.                                     62, 60,115, 112, 97, 110, 32, 115, 116, 121,108,101, 61,
    89. 34, 99,
    90.                                     111, 108, 111, 114, 58, 32, 35, 51, 51, 54, 54, 70, 70,
    91. 34, 62,
    92.                                     69, 67, 83, 104, 111, 112, 60, 47, 115, 112, 97, 110,
    93. 62,60, 47,
    94.                                     115, 116, 114, 111, 110, 103, 62);
    95. }
    96.    }
    97.    catch(ex)
    98.    {
    99.    }
    100. }

    打開模板文件,例如默認的模板page_footer.lbi

    位于模板文件夾的 library/page_footer.lbi

    刪除 {foreach from=$lang.p_y item=pv}{$pv}{/foreach}{$licensed}

    4.上面的3步操作基本上完成了基本版權的去處,至于友情鏈接上的ecshop是在后臺的友情鏈接項目內,自己修改或刪除即可。logo也是在后臺網店設置里面,上傳你自己的logo.gif文件會把默認的ecshop logo替換掉。

    .有的朋友可能還需要進一步去處后臺版權,怎么去處呢,請繼續(xù)看:

    5.1 后臺的ecshop 兩張圖片位置如下:

    admin/images/ecshop_logo.gif

    admin/images/login.png 請把這2張圖片替換成你自己的圖片,大小最好相同

    5.2 右上角的“關于ECSHOP”文字去除

    打開admin/templates/top.htm

    刪除: <li><a href="index.php?act=about_us" target="main-frame">{$lang.about}</a></li>

    5.3 中部 ECSHOP 管理中心, 和底部的版權所有

    打開language/zh_cn/admin/common.php

    $_LANG['cp_home'] = 'ECSHOP 管理中心';
    $_LANG['copyright'] = '版權所有 &copy; 2005-2009 上海商派網絡科技有限公司,并保留所有權利。

    ×××××××××××××××××××××××××××××××××××××××××××××

    上面是本人給大家整理的ecshop2.7.2去處版權的方法,希望對你有幫助


    刪除ECSHOP2.7.3后臺左側菜單中的云服務中心
    2012-04-25 12:32

    ECSHOP2.7.3后臺左側菜單中增加了一個“云服務器中心”,
    若是給客戶使用可能不是很美觀,如果我想刪除掉該怎么辦捏?

    本站為你提供如下操作教程:


    打開ecshop2.7.3,
    找到admin/cloud.php 文件。
    搜索 cloud.ecshop.com
    大概在60行 ,140行,228行
    分別在每行前面加“//”注釋掉,或者將整行刪除,這樣后臺云中心菜單自動隱藏掉了。

    還有個辦法是在ECSHOP后臺模板里修改,menu.htm,start.htm 搜索cloud.php?is_ajax=1 把整段JS 刪除

    (注不需要動ECSHOP模板文件的)

    posted @ 2012-06-22 09:09 小馬歌 閱讀(1570) | 評論 (0)編輯 收藏
     

    查看索引:
    db.user_info.getIndexes();

     

    建立索引:
    db.user_info.ensureIndex({"name":1});

    ----------------------------------------------------------------------------------


    mongodb 刪除數(shù)據(jù)庫

    use test;

     db.dropDatabase();

     mongodb刪除表

     db.mytable.drop();

    ----------------------------------------------------------------------------------

    MongoDB用戶權限分配的操作是針對某個庫來說的。--這句話很重要。

     

    1、 進入ljc 數(shù)據(jù)庫:      

    use ljc;              --ljc為數(shù)據(jù)庫名稱。

    2、添加用戶(讀寫權限,readOnly-->false):

     db.addUser("java","java");

    3、 查看一下所有的用戶

    db.system.users.find();


    { "_id" : ObjectId("4e02a89fb841deb5fda3e5e2"), "user" : "java", "readOnly" : fa
    lse, "pwd" : "59cf7cc156874cbd35cb00869126f569" }

    4、用戶授權。

    db.auth("java","java");

    1                                         顯示為1 表示授權成功,0表示不成功。


     
    5、 添加用戶(只讀權限,readOnly-->true):

    db.addUser("java1","java1",true);
    db.system.users.find();
    { "_id" : ObjectId("4e02a89fb841deb5fda3e5e2"), "user" : "java", "readOnly" : fa
    lse, "pwd" : "59cf7cc156874cbd35cb00869126f569" }
    { "_id" : ObjectId("4e02aae6b841deb5fda3e5e3"), "user" : "java1", "readOnly" : t
    rue, "pwd" : "fca6bda05c87a72cce0a4a6458d1e266" }

    注意上面標紅的位置的readOnly 只讀于可寫是有區(qū)別的。

     

    6、更改密碼(為已經存在的用戶更改密碼):

     db.addUser("java","java1");

     

    7、刪除用戶:

    db.system.users.remove({user:"java1"});

    posted @ 2012-06-15 15:51 小馬歌 閱讀(338) | 評論 (0)編輯 收藏
    僅列出標題
    共95頁: First 上一頁 35 36 37 38 39 40 41 42 43 下一頁 Last 
     
    主站蜘蛛池模板: 色偷偷亚洲男人天堂| 亚洲国色天香视频| 最近免费最新高清中文字幕韩国| 一级毛片aa高清免费观看| 免费国产va视频永久在线观看| 怡红院亚洲红怡院在线观看| 日韩亚洲人成在线综合| 特黄特色大片免费| 亚洲免费网站在线观看| 亚洲一区中文字幕在线电影网| 亚洲人成777在线播放| 亚洲综合中文字幕无线码| 亚洲综合色一区二区三区| 亚洲乱人伦中文字幕无码| 色噜噜的亚洲男人的天堂| 人禽伦免费交视频播放| AAAAA级少妇高潮大片免费看| 三级毛片在线免费观看| 亚洲精品无码国产片| 蜜臀亚洲AV无码精品国产午夜.| 黄色网址免费在线| 少妇性饥渴无码A区免费| 九一在线完整视频免费观看| 中文无码日韩欧免费视频| 国产精品免费一区二区三区四区| 国产精品视频免费| 国产在线国偷精品免费看| 少妇无码一区二区三区免费| 中文在线观看永久免费| 91在线老王精品免费播放| 大地资源免费更新在线播放| 四虎在线播放免费永久视频 | 中文字幕免费观看全部电影| 性无码免费一区二区三区在线| 91手机看片国产永久免费| 日本a级片免费看| 国产亚洲人成网站观看| 亚洲一区电影在线观看| 又黄又大的激情视频在线观看免费视频社区在线 | 中文字幕在线免费| 永久免费AV无码网站在线观看|