青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Daly的游戲人生

2012年11月30日 #

服務(wù)器程序常見bug總結(jié)

   最近整理了過去一年發(fā)生過的bug,包含跟其他項(xiàng)目組程序朋友交流的例子, 都是大家發(fā)生過的真實(shí)營運(yùn)事故。
   游戲服務(wù)器程序,很多bug的原因都是共通的。抽象出了以下10點(diǎn)啟示, 作為checklist, 寫下來以后寫程序review時(shí)自檢:

1. 安全邊界問題
     對于有界限的東西(數(shù)值,buffer空間,隊(duì)列或一切對象容器),一定要考慮越界判斷。
     啟示:用snprint, strncpy等限制長度.  永遠(yuǎn)都要考慮超過邊界的情況
               數(shù)值加法和乘法:考慮上限溢出; 
               減法:考慮負(fù)數(shù); 除法,判斷分母

2. 輸入?yún)?shù)非法
    case1: 扣錢邏輯,減去一個(gè)負(fù)數(shù),變成了加錢。  
    case2: int型大負(fù)數(shù)相加,負(fù)溢出變成大正數(shù)
    啟示:test case要全覆蓋輸入?yún)?shù)范圍, 處理各種可能的情況

3. 上下文改變錯(cuò)誤
     共享變量/全局變量被外部改變,這似乎很常見,而且有時(shí)很隱蔽。在異步回調(diào)的情況下更常見。

     check A變量 
     call func_B()
     ....
     A變量被func_B改變了, 但繼續(xù)信任A變量check的結(jié)果。

    啟示:白盒復(fù)查代碼時(shí),注意檢查調(diào)用后的變化。
               減少共享變量和全局變量的使用
               外部接口調(diào)用后,注意共享變量的更新和恢復(fù)
     啟示:在最接近執(zhí)行的地方,檢查上下文變量。不信任調(diào)用者,如果效率不關(guān)鍵,多一遍冗余檢查沒有壞處

4. 執(zhí)行中斷
     動(dòng)態(tài)腳本拋異常,或者引擎層面的EINTR中斷信號(hào),都有可能中斷代碼執(zhí)行,需要考慮函數(shù)的重入性問題。
     啟示:要檢查一致性,有些邏輯不允許多次被執(zhí)行(比如發(fā)獎(jiǎng)勵(lì)),需要有狀態(tài)變量確保只執(zhí)行1次(避免出刷bug)
     推廣到異步環(huán)境(多線程,多進(jìn)程,各種回調(diào)),事務(wù)的中斷也有一個(gè)重入性問題,解決方法也只有一個(gè):用一個(gè)唯一可辨認(rèn)的狀態(tài)變量,保證某些邏輯不會(huì)被多次執(zhí)行(比如購物應(yīng)用中,用唯一訂單號(hào)來識(shí)別,狀態(tài)改變是一次性的,當(dāng)邏輯運(yùn)行多次,也不會(huì)重復(fù)加物品,或者重復(fù)扣錢了)

5. 終止條件問題--死循環(huán)
     case: 異步環(huán)境中,RPC遠(yuǎn)程調(diào)用,調(diào)用成環(huán),邏輯一直不結(jié)束。
     啟示:while或遞歸的終止條件,邏輯全覆蓋檢查,避免死循環(huán)。較深層次的互相調(diào)用,要注意是否出現(xiàn)了遞歸,是否有可能死循環(huán)。

6. 關(guān)聯(lián)數(shù)據(jù)操作的不一致
     例子:Employee對象有company變量, Company中有employee變量,
          如果操作改變其中一方,而另一方?jīng)]有改變,則造成數(shù)據(jù)不一致。
      (數(shù)據(jù)庫表可以指定constrain, 關(guān)聯(lián)表刪除, 但代碼變量中需要程序員自己實(shí)現(xiàn))
       雙向引用的數(shù)據(jù)一致性問題,要特別注意。
       為什么要雙向引用?為了查找效率,而避免遍歷其中一方.
       這個(gè)問題本質(zhì)是數(shù)據(jù)一致性問題,編程中遇到的很多bug也歸結(jié)到這個(gè)問題,比如野指針,就是因?yàn)閿?shù)據(jù)結(jié)構(gòu)相互引用的操作不一致造成的。
       處理這個(gè)問題,個(gè)人經(jīng)驗(yàn)是,他們的attach,detach操作盡可能在同一個(gè)模塊,不要分散在多個(gè)地方隨意修改,所有修改都集中在同一級接口做。

       同理適用于new, delete, malloc, free這些分配,釋放,都集中在同一層的接口/模塊文件中做,debug起來也容易;非常反感在一個(gè)地方new, 然后不知道哪個(gè)模塊去delete, 很容易泄漏或者野指針, 無論如何,想辦法傳遞這些指針,一直傳到分配他所在的模塊文件中釋放,而且new和delete的接口代碼要靠近,方便查找問題。

7. 涉及多玩家,防止筆誤傳錯(cuò)參數(shù)
     經(jīng)典錯(cuò)誤: foreach(uid in team) some_func(usernum, xxx)   
     經(jīng)典錯(cuò)誤:有usernum和target兩個(gè)對象,調(diào)用函數(shù)搞混了。review時(shí)要仔細(xì)檢查

8. 特殊分支忘了return
     異常判斷等if分支忘了return。導(dǎo)致邏輯繼續(xù)往下走。這屬于筆誤問題,測試期間未必能留意的到。

9. 異步返回沒清變量
    對于異步操作,如果在返回時(shí)清變量,這時(shí)如果不能保證把變量清掉(比如期間玩家下線無法離線修改該變量),就會(huì)出刷。
    啟示:對于已獎(jiǎng)勵(lì)標(biāo)記,一定要保證各種情況下領(lǐng)獎(jiǎng)后能正確記錄。

10. 瞬爆容量上限
     case1:  網(wǎng)絡(luò)待發(fā)送隊(duì)列,因?yàn)樗查g大量請求,塞滿拋異常,導(dǎo)致流程受影響。
     case2:  大量連接請求,listen的accept沒有規(guī)定單次讀事件的accept,用了while(true), 導(dǎo)致爆機(jī)
                在listen fd的讀事件回調(diào)中, 通常會(huì)accept所有新的連接請求,如果用while(true)而不設(shè)一個(gè)上限,就有可能被攻擊(想象一下客戶端也用一個(gè)死循環(huán)來做connect)。
                一方面要限制單次接受的socket次數(shù), 另外各個(gè)狀態(tài)要有超時(shí)機(jī)制,踢掉不尋常的連接,以防被攻擊占盡資源。

     case3: 異步情況下,要限制操作者連續(xù)頻繁的操作。(比如在請求入口處增加最少時(shí)間間隔限制,避免玩家狂點(diǎn),形成雪崩效應(yīng))
                (同時(shí)要考慮用戶體驗(yàn),不要讓玩家死等,可以做一個(gè)提示跳轉(zhuǎn),或者等候的動(dòng)畫)

參考資料:
附上最近看的一篇文章
<Writing-reliable-online-game-services> 作者曾是魔獸爭霸和星際爭霸,battle.net的開發(fā)者,
里面講的point也是游戲里經(jīng)常遇到的可靠性問題。
http://www.codeofhonor.com/blog/wp-content/uploads/2012/04/Patrick-Wyatt-Writing-reliable-online-game-services.pdf



posted @ 2012-11-30 14:14 Daly 閱讀(2402) | 評論 (5)編輯 收藏

2012年8月5日 #

網(wǎng)游服務(wù)器多進(jìn)程架構(gòu)的思考

    by  Daly
    網(wǎng)游服務(wù)器程序優(yōu)化要解決的最主要矛盾無非就是在保證流暢游戲體驗(yàn)(響應(yīng)時(shí)間在可接受范圍)的前提下,容納更多的玩家,當(dāng)然還要保證開發(fā)的便捷性。一個(gè)靠譜的MMOG游戲服務(wù)器基本上都是多線程或多進(jìn)程的架構(gòu), 利用多個(gè)CPU核把串行處理變成并行處理,以容納更大的并發(fā)玩家規(guī)模。
    然而并行處理程序會(huì)使開發(fā)的復(fù)雜度增加,一不小心很容易出一些詭異bug。為什么這樣說呢?實(shí)際環(huán)境的大部分程序,函數(shù)的執(zhí)行結(jié)果與狀態(tài)數(shù)據(jù)相關(guān)(外部狀態(tài),全局?jǐn)?shù)據(jù)),并且函數(shù)執(zhí)行可能會(huì)改變這些狀態(tài)。如果把處理模塊拆成多進(jìn)程,進(jìn)程間的這些狀態(tài)數(shù)據(jù)的一致性和處理時(shí)序,會(huì)影響到結(jié)果的正確性。多進(jìn)程狀態(tài)數(shù)據(jù)的管理,讀寫和同步更新機(jī)制,便是本文要探討的主要問題。 
       如果函數(shù)能變成無狀態(tài)的(結(jié)果只與輸入?yún)?shù)相關(guān)),則分拆成多進(jìn)程毫無壓力。于是業(yè)界開始探討erlang這種函數(shù)式編程語言,并有已有實(shí)際游戲項(xiàng)目(參看:http://www.qingliangcn.com/) 。不過筆者覺得,erlang的無狀態(tài),本質(zhì)上是把狀態(tài)數(shù)據(jù)通過函數(shù)參數(shù)傳遞,這樣意味著頻繁而大量的數(shù)據(jù)復(fù)制和傳遞,是否更適合于MMORPG開發(fā)很難說,本文不予討論,可見文章末尾參考資料。下面探討一下狀態(tài)數(shù)據(jù)在多進(jìn)程之間的問題。

     為了容易描述,整個(gè)架構(gòu)如下圖
                      G
    client <--->║ <------> A
                     ║ <------> B

     其中G表示接入網(wǎng)關(guān),負(fù)責(zé)把client協(xié)議分發(fā)到內(nèi)網(wǎng)對應(yīng)處理進(jìn)程,A,B是負(fù)責(zé)不同功能的處理進(jìn)程,client表示客戶端,玩家狀態(tài)數(shù)據(jù)只有個(gè)v和w兩個(gè)。用reqA,reqB分別表示client對A, B的處理請求,respA, respB表示A,B返回給client的處理結(jié)果。
     游戲邏輯大部分情況下需要保證狀態(tài)數(shù)據(jù)的強(qiáng)一致性,基于過期的數(shù)據(jù)進(jìn)行處理會(huì)得到錯(cuò)誤的結(jié)果(分布式數(shù)據(jù)一致性的工程問題見文末的參考資料)。舉個(gè)有點(diǎn)蹩腳的例子,假設(shè)client先后發(fā)出reqA, reqB兩個(gè)請求,reqA是換武器,reqB是發(fā)起攻擊,變量v是攻擊輸出量(dps)。reqB在reqA之后發(fā)出,攻擊理應(yīng)是按穿上武器后的dps數(shù)值來計(jì)算的。但多進(jìn)程情況下,卻有可能reqB先于reqA處理(比如A進(jìn)程很忙),這時(shí)reqB的邏輯會(huì)基于還沒穿上裝備時(shí)的變量v來計(jì)算結(jié)果。下面分別討論幾種解決數(shù)據(jù)一致性問題的方案。
模式一:共享內(nèi)存
     適合于單機(jī)多進(jìn)程或多線程的模式。
     優(yōu)點(diǎn):數(shù)據(jù)只有一份,可以保證強(qiáng)一致性。
     缺點(diǎn):進(jìn)程無法擴(kuò)展到多臺(tái)服務(wù)器;
          需要加鎖,加鎖相當(dāng)于把處理串行化,還是有可能被某一個(gè)較忙的進(jìn)程卡住。如果精心設(shè)計(jì)和劃分?jǐn)?shù)據(jù),減少鎖的粒度可以提高性能,但細(xì)粒度的鎖(設(shè)計(jì)成類似MySQL的行級鎖),在涉及多個(gè)玩家數(shù)據(jù)的交互邏輯時(shí),稍有不慎又容易導(dǎo)致死鎖。隨手寫一個(gè):
        假設(shè)進(jìn)程A和B同樣執(zhí)行以下類似的邏輯
         foreach( user in mapA) {
              lock(user);
              lock(user‘s friend);
              do_something();
              unlock(user's friend);
              unlock(user_id);
         }
         由于遍歷的是map, 進(jìn)程A和B中的user順序有可能交叉, 假設(shè)交叉的兩個(gè)user互為friend,就可能死鎖了。
         參考資料[4]采用了這種模式的方案。
模式二:狀態(tài)數(shù)據(jù)只由一個(gè)進(jìn)程管理
      把狀態(tài)數(shù)據(jù)根據(jù)游戲邏輯進(jìn)行劃分,比如變量v只由A讀寫, 變量w只由B讀寫。假如A邏輯需要用到w,則通過異步請求B獲取w。
      優(yōu)點(diǎn):保證強(qiáng)一致性;數(shù)據(jù)只有一份,無需進(jìn)程間復(fù)制更新。
      缺點(diǎn):異步請求增加了響應(yīng)時(shí)間(嗯,又從并行變成了串行); 異步寫起來的代碼有點(diǎn)ugly,到處是callback, 回來要檢查上下文,不然又是詭異bug.
      適用范圍:如果狀態(tài)數(shù)據(jù)能比較好的劃分(即絕大多數(shù)情況下,某個(gè)數(shù)據(jù)只會(huì)在某個(gè)進(jìn)程的邏輯中用到),用這種方案比較適合,因?yàn)楹唵巍1热缤婕椅恢弥挥葾OI進(jìn)程管理,玩家好友由聊天進(jìn)程管理。
模式三:多個(gè)writer, 類似MVCC方案
      這是完全的分布式設(shè)計(jì)。每個(gè)進(jìn)程有自己版本的狀態(tài)數(shù)據(jù),進(jìn)程間可互相同步更新, 狀態(tài)數(shù)據(jù)v分別在A,B都有一份。互相update時(shí),根據(jù)版本信息進(jìn)行merge。 
      這種方案不能保證強(qiáng)一致性,而且merge時(shí)會(huì)有可能發(fā)生沖突,需要邏輯開發(fā)者仲裁這種沖突(比如按時(shí)間先后)。不同于互聯(lián)網(wǎng)應(yīng)用,游戲需要較強(qiáng)的數(shù)據(jù)一致性和實(shí)時(shí)性,這種方案比較復(fù)雜且不太可控。
模式四:Master-Slave模式
      這個(gè)是對模式二的一個(gè)擴(kuò)展,某個(gè)狀態(tài)數(shù)據(jù)還是只由一個(gè)進(jìn)程進(jìn)行寫操作,但其他進(jìn)程會(huì)維持一份cache進(jìn)行讀操作,比如變量v由進(jìn)程A管理,v的更新會(huì)同步到進(jìn)程B,進(jìn)程B邏輯如果要用到v,直接讀自己的cache就可以了。對于變量v
     特點(diǎn):這種方式也是不能保證強(qiáng)一致性,只能保證最終一致性。作為模式二的補(bǔ)充,有些數(shù)據(jù)不需要保證更新時(shí)序,根據(jù)過期數(shù)據(jù)進(jìn)行處理也可以接受(這個(gè)是代價(jià),需要權(quán)衡玩家體驗(yàn)),可以采取這種方式。而對于不能接受的,走模式二。某些需求reqA,reqB雖然先后發(fā)出,如果respA還沒反饋回來的話,即使邏輯上reqB先于reqA處理,在玩家體驗(yàn)上也是可以接受的。比如reqA穿裝備, 然后reqB攻擊,但是respA還沒返回,客戶端還是看作是沒穿上裝備,這時(shí)候按照老的屬性計(jì)算攻擊值是可接受的。廣域網(wǎng)幾百毫秒的延遲,reqB要晚于reqA + respA這種概率很小了,如果真的發(fā)生,服務(wù)器已經(jīng)很卡了。
    又比如聊天進(jìn)程,reqA離開場景,然后reqB發(fā)聊天消息往當(dāng)前場景頻道,需要知道當(dāng)前場景的玩家列表(假設(shè)場景玩家列表在AOI進(jìn)程管理),如果reqB先到達(dá)聊天進(jìn)程,拿到舊的場景玩家列表, 那么這個(gè)廣播就不準(zhǔn)確了。這種不一致性的代價(jià)可以忍受的話就沒問題(在這個(gè)聊天欄例子,在跳場景的瞬間發(fā)錯(cuò)人了也可以忍),實(shí)際情況,進(jìn)程間通信幾個(gè)毫秒,發(fā)生這種處理時(shí)序反轉(zhuǎn)的幾率其實(shí)非常小了。
綜上,如果要設(shè)計(jì)多進(jìn)程結(jié)構(gòu),個(gè)人比較推崇模式四。這時(shí)又引申出幾個(gè)問題:狀態(tài)數(shù)據(jù)如何合理劃分?何時(shí)更新?同步給誰?
如何劃分?
     有些功能很好劃分。比如聊天進(jìn)程,狀態(tài)數(shù)據(jù)只與好友列表有關(guān),這個(gè)需求可以忍受過期數(shù)據(jù),好友關(guān)系由主進(jìn)程修改,同步到聊天進(jìn)程。玩家position, 由AOI進(jìn)程管理,修改同步到主進(jìn)程,主進(jìn)程幾乎沒有需要用到position的邏輯。
    但有些數(shù)據(jù)就可能很糾結(jié),比如背包數(shù)據(jù)。玩家交易,在線獎(jiǎng)勵(lì),戰(zhàn)斗都需要修改背包物品數(shù)據(jù),而且必須保證強(qiáng)一致性,否則就可能出現(xiàn)丟失或物品復(fù)制,該由誰做這個(gè)數(shù)據(jù)的管理者呢?如果AOI進(jìn)程管理,物品使用效果可以馬上生效,但是交易和在線獎(jiǎng)勵(lì)也需要驗(yàn)證背包物品,這些邏輯也放到AOI進(jìn)程么,如果放,則又牽扯出更多的變量,如果不放,則需要退化成模式2的異步請求。如果放主進(jìn)程,則使用物品后產(chǎn)生的效果不能立刻同步到AOI進(jìn)程。可以經(jīng)過仔細(xì)對比,AOI與背包數(shù)據(jù)交互的頻率遠(yuǎn)高于主進(jìn)程,于是背包數(shù)據(jù)可由AOI進(jìn)程管理。
何時(shí)更新?
     兩種選擇:一有修改立馬發(fā)送更新給其他進(jìn)程;隊(duì)列buffer住所有更新,定時(shí)送出去(比如每2秒同步一次);既然是無法保證強(qiáng)一致性,后者性能容易優(yōu)化些。比如AOI進(jìn)程中的位置信息變化很頻繁,但主進(jìn)程對位置實(shí)時(shí)性不敏感(比如只用于持久化,掉線重上后的位置恢復(fù)),則更新間隔可以長一些,否則會(huì)有頻繁而大量的位置數(shù)據(jù)更新;定時(shí)更新也利于同步間隔內(nèi)數(shù)據(jù)修改的合并,減少同步量。
同步給誰?
     某類數(shù)據(jù)有修改時(shí),需要通知哪些進(jìn)程,意味著要維持一個(gè)映射表。可以在編碼階段,在數(shù)據(jù)定義時(shí)靜態(tài)寫死某類數(shù)據(jù)要通知哪一類功能進(jìn)程; 也可以在運(yùn)行期設(shè)計(jì)成pub-sub模式(或者叫observer模式), 動(dòng)態(tài)增刪訂閱者。筆者覺得前者可控一點(diǎn),因?yàn)檫M(jìn)程要用到哪些數(shù)據(jù),在編碼階段是可以清楚規(guī)劃的,根據(jù)這個(gè)原則把數(shù)據(jù)劃分成一個(gè)個(gè)模塊,比如玩家數(shù)據(jù)分為基本角色屬性,avatar, 位置/朝向, 好友數(shù)據(jù)....  然后決定歸屬。
    多進(jìn)程可以提升系統(tǒng)并發(fā)規(guī)模,但同時(shí)有各種異步調(diào)用和數(shù)據(jù)一致性問題,帶來的代價(jià)就是bug的風(fēng)險(xiǎn)增加(尤其團(tuán)隊(duì)水平不能保證個(gè)個(gè)都很高的情況下,一個(gè)菜鳥程序員就夠受了,還很難跟蹤),開發(fā)難度增大。這個(gè)需要仔細(xì)profile和實(shí)驗(yàn)確定瓶頸在哪,真的跑滿CPU或者卡IO才有必要分出去,想當(dāng)然的把模塊拆分很多進(jìn)程,設(shè)計(jì)看上去很優(yōu)雅也很牛逼,往往是麻煩的開始 ——> 開發(fā)效率降低,出bug意味著啥?加班,加班,深夜運(yùn)維的奪命追魂call... ...
參考資料
[1] 當(dāng)webgame邂逅erlang.  明朝網(wǎng)絡(luò)的慶亮。 http://www.slideshare.net/qingliangcn/webgameerlang-8241397#btnNext
[2] 陳杰談網(wǎng)游服務(wù)器后端技術(shù).  西山居陳杰的ppt, 講多進(jìn)程架構(gòu)下的尋路算法 http://timyang.net/architecture/game-backend/
[3] nosql ecosystem. 13節(jié)講述分布式系統(tǒng)的數(shù)據(jù)一致性問題
[4] 結(jié)構(gòu)化數(shù)據(jù)的共享內(nèi)存, 云風(fēng) http://blog.codingnow.com/2011/12/dev_note_6.html

posted @ 2012-08-05 17:01 Daly 閱讀(4327) | 評論 (3)編輯 收藏

2012年7月17日 #

網(wǎng)絡(luò)游戲不同類型的技術(shù)分類

    不同的游戲類型需要有不同的技術(shù)設(shè)計(jì),尤其服務(wù)器端,沒有一個(gè)通用游戲引擎可以適應(yīng)所有類型。所以大部分游戲的服務(wù)器端引擎都是根據(jù)產(chǎn)品需求手工打造,商業(yè)引擎通常也得經(jīng)過別扭的折騰改造才能用得比較好(比如Bigworld ^_^ )。 本文對常見的幾種網(wǎng)絡(luò)游戲的服務(wù)端技術(shù)做一個(gè)技術(shù)特點(diǎn)的分類。
    約束性能和容量規(guī)模的因素歸納起來是:數(shù)據(jù)共享域,消息廣播域,運(yùn)算共享域。這幾個(gè)因素涉及的對象數(shù)量會(huì)直接影響了架構(gòu)涉及,下面分別來說。
 
     分類特征:
     玩家數(shù)據(jù)總量,同時(shí)在線數(shù)
     這里是指,玩家登錄后,需要從多大規(guī)模的數(shù)據(jù)中讀取自己的數(shù)據(jù)。social game全局共享的角色數(shù)據(jù)(統(tǒng)一世界),隨著玩家數(shù)量增多線性增長,往往單機(jī)儲(chǔ)存不能滿足需求,需要分布式儲(chǔ)存技術(shù)。而對于傳統(tǒng)MMORPG,由于是分服(服務(wù)器之間是平衡世界,角色數(shù)據(jù)相互獨(dú)立),相當(dāng)于天然地用服務(wù)器id做了數(shù)據(jù)分區(qū)(而不需要像分布式儲(chǔ)存那樣考慮分區(qū)算法的擴(kuò)展性問題),除了登錄信息,沒有全局?jǐn)?shù)據(jù),單機(jī)儲(chǔ)存即可解決問題。
     AOI范圍與頻率
     這里指的是游戲過程中,即時(shí)廣播涉及的對象數(shù)量以及消息密度,比如同屏玩家數(shù)。競技和休閑類游戲通常比較小,而傳統(tǒng)MMORPG通常較大。
     范圍和頻率還影響client間傳輸消息的方式,通常有兩種:client間直傳(P2P); 中心服轉(zhuǎn)發(fā)。從延時(shí)來看,廣域網(wǎng)游戲這兩者區(qū)別到不大(前提是中心服不卡,其實(shí)可以看做一個(gè)路由器)。如果廣播范圍 x 頻率較大,中心服的帶寬成本很高(嗯嗯,帶寬是很貴的)。如果采用純P2P,則需要考慮客戶端作弊問題。當(dāng)然還可以用混合的方法,即中心服監(jiān)督下的P2P,比如有些競技游戲在服務(wù)端也做一層校驗(yàn),查出外掛的可能,當(dāng)然這個(gè)不容易實(shí)現(xiàn)得好。 大部分情況下,服務(wù)器監(jiān)督一切,最省心。

     AOI跳轉(zhuǎn)方式
     是指在不同運(yùn)算共享域和廣播域直接切換的方式,分為無縫和跳轉(zhuǎn)點(diǎn)。舉個(gè)例子,休閑游戲和競技游戲通常是玩家主動(dòng)點(diǎn)擊進(jìn)入或退出房間/頻道,不同房間/頻道分隔了廣播域。而即時(shí)制MMORPG(比如WOW)區(qū)域之間是無邊界的。這兩者區(qū)別影響運(yùn)算性能的擴(kuò)展性,即實(shí)現(xiàn)多進(jìn)程處理的技術(shù)難度。對于前者可以很容易實(shí)現(xiàn)多進(jìn)程分擔(dān)處理任務(wù)。后者的無縫AOI,要實(shí)現(xiàn)多進(jìn)程的話,在邊界處需要較復(fù)雜的進(jìn)程數(shù)據(jù)同步技術(shù)。
     實(shí)時(shí)性/同步要求
     網(wǎng)絡(luò)延時(shí)的前提下,同步方案主要是用戶體驗(yàn)和數(shù)據(jù)正確性之間的權(quán)衡。競技和動(dòng)作游戲強(qiáng)調(diào)打擊感和位置準(zhǔn)確性,需要很高的同步要求。很多游戲采用幀同步方案,即一旦對應(yīng)幀數(shù)據(jù)未到,卡住整個(gè)客戶端(dota的等待連線)。也有采用運(yùn)動(dòng)補(bǔ)償?shù)姆绞?也稱追影),即客戶端預(yù)判,當(dāng)和服務(wù)端位置不一致時(shí),通過加速等方式平滑追上。為了減少延時(shí)帶來的影響,一部分計(jì)算放在客戶端,關(guān)鍵計(jì)算等待服務(wù)器返回。在等待服務(wù)器返回結(jié)果的過程中,通常結(jié)合美術(shù)和技術(shù)手段"欺騙"玩家的視覺(比如起手動(dòng)作),達(dá)到較好的體驗(yàn)。

Social game
     玩法:策略經(jīng)營類,好友互動(dòng)
     玩家數(shù)量大,冷數(shù)據(jù)總量大 (海量玩家同一交互域),同時(shí)在線高;
     AOI范圍中。頻率低。消息在好友之間分發(fā)(好友數(shù)量一般在一百以內(nèi))
     實(shí)時(shí)性/同步要求:低,不需要實(shí)時(shí)。運(yùn)算較簡單(看成是海量數(shù)據(jù)的CURD應(yīng)用)
     技術(shù)特點(diǎn):跟微博,QQ群等傳統(tǒng)互聯(lián)網(wǎng)應(yīng)用比較接近:數(shù)據(jù)量大,AOI范圍中,實(shí)時(shí)要求低。主要難點(diǎn)在于讀寫規(guī)模大,總數(shù)據(jù)量大,cache熱度不明顯(無明顯熱數(shù)據(jù))。
     性能擴(kuò)展:依賴于分布式儲(chǔ)存和讀寫技術(shù),與一般社交網(wǎng)絡(luò)技術(shù)類似。由于需要預(yù)先加好友,設(shè)定好友數(shù)量上限可以限制數(shù)據(jù)廣播的規(guī)模。

休閑棋牌類游戲
     玩家數(shù)量大;冷數(shù)據(jù)總量大;但登錄后通常進(jìn)入房間。
     房間之間分隔了廣播域,游戲局之間玩家互相獨(dú)立(除了聊天頻道)。意味著較容易根據(jù)房間和游戲分服/進(jìn)程,性能擴(kuò)展容易。
     AOI范圍低(一局游戲的幾個(gè)人),實(shí)時(shí)性一般。運(yùn)算一般(棋牌算法計(jì)算)。
     架構(gòu)上通常分前端(登錄和房間邏輯)和后端(具體一局游戲),分服設(shè)計(jì)較容易。通常一個(gè)前端要對應(yīng)很多種不同類型的后端邏輯(各種類型游戲),需要制定一個(gè)容易開發(fā)和接入的框架。
     容量擴(kuò)展:由于游戲局的獨(dú)立性,分進(jìn)程/分服做運(yùn)算擴(kuò)展比較簡單。 通過分區(qū)分房間限制了數(shù)據(jù)廣播規(guī)模。

競技類游戲
     玩法:dota, FPS, 格斗動(dòng)作類
     AOI范圍低(10人以下),交互頻率高
     實(shí)時(shí)交互和同步要求極高(技術(shù)難點(diǎn))
     容量擴(kuò)展:通常與休閑類一樣,先進(jìn)入房間(有些叫頻道)限制數(shù)據(jù)廣播規(guī)模。不同房間互相獨(dú)立,因此也較容易通過增加進(jìn)程/服務(wù)器分散運(yùn)算規(guī)模。

即時(shí)制MMORPG
     通常技能有cooldown, 玩家之間可以穿插(沒有動(dòng)態(tài)碰撞檢測),同步要求低于動(dòng)作類和dota網(wǎng)游。單服同時(shí)在線人數(shù)有限(1w人左右),邏輯復(fù)雜, IO通常單機(jī)就可搞定。AOI通常是運(yùn)算瓶頸,要提高容量就要分進(jìn)程或分線程。對于區(qū)域間無縫世界,在邊界處的對象,由于互相可見且可戰(zhàn)斗,分管兩個(gè)區(qū)域的進(jìn)程間需要較復(fù)雜的同步機(jī)制。比如bigworld用的是對象代理技術(shù),即在原區(qū)域是real對象,對端區(qū)域建立一個(gè)ghost(代理對象), 對real對象的所有狀態(tài)改變即時(shí)同步到對端進(jìn)程,反之對ghost操作也同步到real。也就是說玩家A在兩個(gè)進(jìn)程都有自己的副本,且都可寫,需要借鑒分布式技術(shù)中,多Writer的數(shù)據(jù)一致性設(shè)計(jì)。
     對MMORPG來說,單服人數(shù)越高,游戲的社區(qū)性和人氣感就越強(qiáng), 但人數(shù)越多,就越容易卡住服務(wù)器。現(xiàn)在都是多核的世界,基本上都是多線程/進(jìn)程的架構(gòu)了,多writer/reader, 數(shù)據(jù)同步,鎖這些是常見技術(shù)考量點(diǎn)。一般功能模塊交互性不強(qiáng),分進(jìn)程/線程難度不大,但AOI這塊分進(jìn)程要比較折騰。

     題外話
     這兩年公司的校園招聘,程序員的title是虛擬世界架構(gòu)師(汗 -_-!)。真正的虛擬世界應(yīng)該是:數(shù)據(jù)規(guī)模大,AOI范圍大,實(shí)時(shí)交互。以上還沒有一種游戲同時(shí)符合幾個(gè)特征,都不同程度通過分區(qū)/分服/分房間/分場景/分頻道分隔了單個(gè)進(jìn)程的處理規(guī)模,單臺(tái)服務(wù)器的數(shù)據(jù)規(guī)模和帶寬規(guī)模。當(dāng)然,即使技術(shù)上可行,玩家腦子同時(shí)能處理的對象數(shù)比電腦要差多了(呃,試想數(shù)萬人同處一個(gè)場景,然后走來走去,這個(gè)有游戲性可言?),這時(shí)候瓶頸不在服務(wù)器,超密集的角色,客戶端的渲染效率變成瓶頸。

posted @ 2012-07-17 09:45 Daly 閱讀(2910) | 評論 (5)編輯 收藏

2012年7月2日 #

替代系統(tǒng)malloc/new--選擇合適的內(nèi)存跟蹤方案

 
替代系統(tǒng)自帶的malloc/new原因無非兩個(gè): 
reason 1. 做內(nèi)存profile或查找問題   
reason 2. 自定義的分配方案提高性能

不過文章[1]中說明了,替代全局new不是一個(gè)好做法. 其實(shí)要達(dá)到以上兩點(diǎn)目的,筆者認(rèn)為用valgrind工具鏈就可以了。

解決方案:
1. 用valgrind和massif
     valgrind的memcheck做內(nèi)存泄露和bug的查找, 里面的massif工具包做內(nèi)存性能profile, 足矣。比自己山寨的一個(gè)profiler要好。
     注意:tcmalloc目前還不能很好支持valgrind,  實(shí)測中jemalloc可以

2.  linux下C的程序可以用wrap的方式(相當(dāng)于python的decorator)
     編譯加上選項(xiàng):gcc -Wl,-wrap,malloc
     可以做到對malloc這個(gè)函數(shù),linker會(huì)調(diào)用__wrap_malloc代替之, 若要調(diào)用原來的malloc函數(shù)__real_malloc
     缺點(diǎn):依賴于編譯器支持; 對c++的new不起作用 --> 不實(shí)用
     啟示:這個(gè)方法作為function裝飾器,對于調(diào)試別的問題倒有幫助。(例如不改變函數(shù)的情況下,wrap一層,輸出些調(diào)試信息)
3. 用__malloc_hook
    參考: http://linux.die.net/man/3/__malloc_hook
     #include <malloc.h>
     void *(*__malloc_hook)(size_t size, const void *caller);
     缺點(diǎn):依賴GNU編譯工具鏈;  容易死循環(huán)(想利用原有malloc,要參考例子中,把原__malloc_hook變量保存起來使用,并恢復(fù)現(xiàn)場)

4. LD_PRELOAD注入.so ,替代原
     環(huán)境變量LD_PRELOAD指定程序運(yùn)行時(shí)優(yōu)先加載的動(dòng)態(tài)連接庫,這個(gè)動(dòng)態(tài)鏈接庫中的符號(hào)優(yōu)先級是最高的。標(biāo)準(zhǔn)C的各種函數(shù)都是存放在libc.so.6的文件中,在程序運(yùn)行時(shí)自動(dòng)鏈接。使用LD_PRELOAD后,自己編寫的malloc的加載順序高于glibc中的malloc,這樣就實(shí)現(xiàn)了替換。用法 LD_PRELOAD=" ./mymalloc.so"
      缺點(diǎn):在生產(chǎn)環(huán)境不現(xiàn)實(shí)。因?yàn)長D_PRELOAD相當(dāng)于庫注入,有安全性問題,是必須禁止的。(生產(chǎn)環(huán)境很多時(shí)候用-static連接)
5. 用宏或另外的函數(shù)替代new/malloc
   比如定義一個(gè)宏或者指定的函數(shù),規(guī)定所有的分配釋放都調(diào)用他。這樣相當(dāng)于給項(xiàng)目引入了額外的代碼規(guī)則(而且是一立項(xiàng)就要遵循這個(gè)規(guī)則,否則該方法無效),不能很自然的new/delete, 如果分配和釋放調(diào)用得不一致,會(huì)產(chǎn)生問題的。某產(chǎn)品組就是用宏,然后加上__FILE__, __LINE__之類的信息。

 有時(shí)候valgrind的效率是個(gè)問題(尤其生產(chǎn)環(huán)境),這種方案有其價(jià)值所在, 就是代碼看上去比較ugly罷了

   用宏的例子:
   #define _New(Type, Catergory)                    (Type*)MyMemController::New((new Type), #Type, 1, sizeof(Type),   Catergory, __FILE__, __LINE__, false)
   #define _NewArray(Type, N, Catergory)          (Type*)MyMemController::New((new Type[N]), #Type, N, sizeof(Type)*(N), Catergory, __FILE__, __LINE__, true)

   
MALLOC的替代品:
     自己寫一個(gè)malloc其實(shí)很復(fù)雜,要考慮線程安全等各種問題,性能到頭來可能更差。google 的tcmalloc,  facebook使用的jemalloc.   多線程下性能較好,可以考慮使用。
     缺點(diǎn):筆者嘗試過。tcmalloc不能正確用valgrind,只能用自帶gperftools(運(yùn)行中會(huì)core)
                 jemalloc可以使用valgrind,不過還沒完全驗(yàn)證是否都準(zhǔn)確。
tcmalloc相關(guān):
    在64位系統(tǒng)上要裝libunwind, 對x86-64架構(gòu)使用還有些問題

源碼包的INSTALL文檔里面也提到了這個(gè)問題。
 CAUTION: if you install libunwind from the url above, be aware that
   you may have trouble if you try to statically link your binary with
   perftools: that is, if you link with 'gcc -static -lgcc_eh ...'.
   This is because both libunwind and libgcc implement the same C++
   exception handling APIs, but they implement them differently on
   some platforms.  This is not likely to be a problem on ia64, but
   may be on x86-64.

主要是64位機(jī)frame-pointer的影響, 他的profile工具里的backtrace用libunwind這個(gè)庫,這個(gè)庫又有版本問題,各種囧啊....
筆者試過系統(tǒng)x86-64, freebsd,用靜態(tài)鏈接。實(shí)際用了一下,問題很多很折騰,等他fix了再說吧.

windows下可以參考:

jemalloc暫時(shí)未發(fā)現(xiàn)有什么兼容性問題,運(yùn)行得挺好的。
 
Reference
[1] <不要重載全局operator new>

[2] effective c++條款50:了解new和delete的合理替換時(shí)機(jī)

[3] 游戲引擎中的內(nèi)存分配策略
[4] 更好的內(nèi)存管理jemalloc
[5] tcmalloc官網(wǎng)(gperftools)

posted @ 2012-07-02 13:01 Daly 閱讀(7522) | 評論 (0)編輯 收藏

2012年7月1日 #

基于binlog的游戲數(shù)據(jù)儲(chǔ)存引擎

    最近組內(nèi)發(fā)表一篇小論文,是關(guān)于改進(jìn)游戲儲(chǔ)存系統(tǒng)的IO性能思路。老大原來早有相同的想法,并且已經(jīng)實(shí)現(xiàn)了大部分模塊,后來和老大一同努力,新的儲(chǔ)存引擎終于逐步完善。在外服環(huán)境跑了兩個(gè)多月,性能和可靠性得到了明顯的提升。具體的細(xì)節(jié)就不方便發(fā)表了,實(shí)踐證明,用binlog來做MMORPG的數(shù)據(jù)儲(chǔ)存是行得通的。

幾個(gè)事實(shí):
   1. 磁盤IO的瓶頸在尋道,順序?qū)懶阅鼙入S機(jī)寫性能高一個(gè)數(shù)量級。

目前典型硬盤的順序?qū)懭胨俣却蠹s是60MB/s , 而尋道時(shí)間在5~8ms (200/)。可以看到硬盤IO的主要瓶頸在于磁頭尋道,也就是隨機(jī)寫。在linux開發(fā)服(非虛擬機(jī),Xeon 3.0G 4/16G內(nèi)存)上做了一個(gè)benchmark

順序?qū)?/span>50MB: 700ms

5000個(gè)文件,每個(gè)10KB(50MB): 12

        10000次隨機(jī)寫,每次1KB(10MB): 21
   2. 游戲數(shù)據(jù)都是K-V數(shù)據(jù),關(guān)系查詢需求極少;k-v數(shù)據(jù)的update很頻繁(實(shí)測是每玩家每5秒一次修改)
   3. MMORPG單服的玩家同時(shí)在線數(shù)量是10K級別, 這個(gè)數(shù)量級可以有效估算binlog的規(guī)模,使得方案可行。

     一般MMORPG系統(tǒng)的存盤策略: 定時(shí)存盤。就是過一段時(shí)間(比如5分鐘)把在線有修改過的玩家數(shù)據(jù),整個(gè)snapshot存下去(mysql也好,文件系統(tǒng)也好)。這樣有兩個(gè)主要問題:一到保存點(diǎn),IO隨機(jī)寫暴增,玩家卡機(jī);如果系統(tǒng)down機(jī), 數(shù)據(jù)就會(huì)有幾分鐘的回檔。而性能和數(shù)據(jù)可靠性兩則是矛盾的,存盤間隔過小,玩家卡機(jī),過大,故障后數(shù)據(jù)回檔時(shí)間長。需知現(xiàn)在的MMORPG,貴價(jià)武器價(jià)值都成千上萬RMB,數(shù)據(jù)可靠性對游戲營運(yùn)影響還是很大的。
    so,   可以用定制的binlog來記錄玩家數(shù)據(jù),也就是說,不記錄整個(gè)snapshot,而是每個(gè)k-v變化時(shí)記錄opcode馬上寫入binlog文件, binlog的格式根據(jù)游戲情況可以高度定制,盡量減少空間。由于是順序?qū)懀阅芸梢苑浅8摺H绻鹍own機(jī),可以根據(jù)binlog來恢復(fù),基本上沒有回檔。不過要解決一個(gè)問題:binlog增長過大 --> 崩潰恢復(fù)時(shí)間過程 & binlog文件本身損壞的風(fēng)險(xiǎn)增大 & 磁盤空間用光。因此binlog需要有rotate機(jī)制, rotate的時(shí)候需要存一次在線玩家數(shù)據(jù)的snapshot, 這樣舊的binlog就可以存到遠(yuǎn)處或者丟棄。rotate的過程中需要考慮恢復(fù)時(shí)玩家數(shù)據(jù)一致性和完備性等等一系列細(xì)節(jié)問題,后來一一解決了。
    這是最近做的成就感的事。幾年沒寫blog了,筆記都記在evernote里,最近又想在公開的地方寫點(diǎn)東西,發(fā)個(gè)文紀(jì)念一下。


posted @ 2012-07-01 18:05 Daly 閱讀(2273) | 評論 (6)編輯 收藏

2010年6月18日 #

Nginx源碼學(xué)習(xí)(2) ---- 模塊化及配置

     摘要:   閱讀全文

posted @ 2010-06-18 16:15 Daly 閱讀(2519) | 評論 (0)編輯 收藏

山寨版小游戲~~~

     摘要: 實(shí)習(xí)做的兩個(gè)小游戲,山寨版的雷電和網(wǎng)絡(luò)對戰(zhàn)的休閑游戲。  閱讀全文

posted @ 2010-06-18 13:38 Daly 閱讀(821) | 評論 (1)編輯 收藏

Nginx源碼學(xué)習(xí)(1) ---- 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

     摘要: nginx的基礎(chǔ)數(shù)據(jù)額結(jié)構(gòu)分析  閱讀全文

posted @ 2010-06-18 12:27 Daly 閱讀(3800) | 評論 (1)編輯 收藏

2010年5月26日 #

高效的Timer實(shí)現(xiàn)

     摘要: 很多程序都需要處理一系列定時(shí)事件, 本文就見過的程序中,幾種實(shí)現(xiàn)Timer的方法。用到的數(shù)據(jù)結(jié)構(gòu)一般有鏈表, 堆, RB樹,hash table等,還有一些比較優(yōu)化的方法。  閱讀全文

posted @ 2010-05-26 20:44 Daly 閱讀(4367) | 評論 (2)編輯 收藏

2010年5月2日 #

資源和內(nèi)存管理學(xué)習(xí)總結(jié)

     摘要: 總結(jié)了幾種資源和內(nèi)存管理的實(shí)現(xiàn)思路。包括buddy算法,STL中的allocator實(shí)現(xiàn)思路,游戲中的資源管理  閱讀全文

posted @ 2010-05-02 00:02 Daly 閱讀(2277) | 評論 (1)編輯 收藏

僅列出標(biāo)題  下一頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精彩免费视频| 亚洲欧美在线观看| 亚洲欧美国产另类| 欧美日本一区二区三区| 亚洲精品国偷自产在线99热| 99视频超级精品| 欧美另类亚洲| 久久久精品国产免费观看同学| 在线亚洲伦理| 国产一区二区你懂的| 亚洲图片欧洲图片av| 亚洲精品一区二区三区99| 蜜臀91精品一区二区三区| 亚洲电影在线免费观看| 亚洲高清视频一区| 午夜影视日本亚洲欧洲精品| 亚洲精品黄色| 亚洲欧美日韩天堂一区二区| 激情五月婷婷综合| 国产精品久久久久久影院8一贰佰 国产精品久久久久久影视 | 你懂的视频一区二区| 亚洲精品乱码久久久久| 国产精品99久久久久久久久久久久 | 久久精品成人欧美大片古装| 欧美在线看片| 一区二区三区四区五区视频| 久久精品男女| 一区二区精品在线| 国产精品婷婷| 久久久国产一区二区| 美女亚洲精品| 亚洲精品永久免费| 欧美精品二区| 欧美成人xxx| 国产精品任我爽爆在线播放| 欧美一区二区三区婷婷月色 | 亚洲欧美日韩视频二区| 欧美视频在线不卡| 亚洲国内自拍| 亚洲一区激情| 99精品久久| 国产日韩欧美| 99精品欧美一区| 欧美日韩福利在线观看| 亚洲免费婷婷| 免费成人av资源网| 亚洲国产精品一区二区www在线| 一本色道久久综合亚洲91| 久久先锋影音av| 亚洲精品久久久久| 亚洲国产精彩中文乱码av在线播放| 国产欧美日韩精品在线| 国产精品日韩在线| 国产日韩av一区二区| 在线日韩电影| 亚洲一区二区三区激情| 欧美一区二区播放| 亚洲小说欧美另类婷婷| 欧美成人免费视频| 国产免费成人av| 国产日韩欧美亚洲| 狂野欧美性猛交xxxx巴西| 欧美中文字幕在线视频| 国产精品免费看片| 欧美午夜视频| 国产欧美日韩视频| 欧美激情一区二区三级高清视频 | 亚洲一二三四区| 亚洲区一区二| 久久综合一区二区| 久久久久久久波多野高潮日日| 在线精品视频免费观看| 久久一区视频| 玖玖视频精品| 亚洲欧洲精品一区| 99视频超级精品| 性欧美精品高清| 久久久久综合| 欧美日韩一区二区三区视频| 国产一区欧美日韩| 国产午夜精品全部视频播放| 亚洲福利小视频| 蜜桃av噜噜一区| 亚洲国产精品久久久久婷婷884 | 久久久99爱| 亚洲欧美国产制服动漫| av成人动漫| 亚洲视频免费| 亚洲香蕉成视频在线观看| 欧美freesex交免费视频| 国产主播喷水一区二区| 中文在线资源观看网站视频免费不卡 | 欧美精品粉嫩高潮一区二区| 国内精品一区二区三区| 亚洲免费观看| 亚洲精品一区在线| 欧美韩日亚洲| 欧美一区二区视频在线观看| 久久久国产一区二区三区| 午夜精品久久久久久久99樱桃| 久久久久成人精品| 噜噜噜噜噜久久久久久91| 欧美久久综合| 亚洲国产91精品在线观看| 亚洲国内精品在线| 国产精品毛片在线| 久久岛国电影| 亚洲欧美国产毛片在线| 国产精品高清免费在线观看| 在线视频日韩精品| 欧美激情精品久久久久久蜜臀 | 国产精品v一区二区三区 | 久久久999精品免费| 欧美日韩一区综合| 99国产精品久久久久久久成人热| 牛夜精品久久久久久久99黑人| 欧美成人免费播放| 亚洲欧美国产三级| 欧美在线看片| 午夜精品剧场| 久久久久.com| 亚洲精选大片| 久热爱精品视频线路一| 午夜精品久久久久久| 欧美日韩视频专区在线播放 | 欧美一区二区免费| 亚洲第一色中文字幕| 亚洲欧美日韩精品久久奇米色影视 | 欧美粗暴jizz性欧美20| 韩国一区二区在线观看| 久久久精品国产一区二区三区| 亚洲精品小视频在线观看| 亚洲在线免费| 午夜视频精品| 国产精品国产三级国产aⅴ浪潮| 久久―日本道色综合久久| 国产日韩精品视频一区| 欧美freesex交免费视频| 激情婷婷欧美| 亚洲欧洲av一区二区| 亚洲欧洲在线看| 久久精品女人的天堂av| 麻豆成人小视频| 性欧美8khd高清极品| 国产精品久久久久91| 欧美国产精品专区| 欧美在线免费播放| 亚洲欧洲日韩女同| 欧美日韩中文| 亚洲中字在线| 欧美电影在线播放| 在线午夜精品| 欧美午夜片在线观看| 欧美国产日本| 国产日韩在线看| 久久九九国产| 久久亚洲春色中文字幕| 亚洲免费在线视频| 亚洲国产导航| 亚洲欧洲中文日韩久久av乱码| 久久人人97超碰国产公开结果| 亚洲影音先锋| 性欧美在线看片a免费观看| 国产亚洲欧美日韩精品| 一个色综合av| 蜜桃精品久久久久久久免费影院| 久久久久久久久久久久久久一区| 日韩午夜在线电影| 99这里只有久久精品视频| 日韩一级不卡| 麻豆av一区二区三区| 欧美激情一区二区三区在线视频| 久久国产黑丝| 欧美福利视频| 国产一区二区在线观看免费播放| 欧美视频免费在线| 欧美精品在线观看| 国产麻豆9l精品三级站| 精品1区2区3区4区| 欧美视频福利| 国产日韩欧美中文在线播放| 你懂的一区二区| 欧美视频在线观看免费| 国产亚洲欧美激情| 亚洲精品中文字幕有码专区| 在线欧美日韩| 亚洲国产日韩在线一区模特| 亚洲综合第一页| 久久蜜桃av一区精品变态类天堂| 欧美亚洲日本一区| 欧美亚洲一区二区在线观看| 美女国内精品自产拍在线播放| 免费在线观看精品| 91久久国产综合久久91精品网站| 亚洲第一在线| 久久久久久国产精品mv| 国产九区一区在线| 亚洲精品欧美一区二区三区| 欧美1区3d| 欧美国产日韩亚洲一区|