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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        最近有朋友給我郵件問一些storm的問題,集中解答在這里。
    一、我有一個數據文件,或者我有一個系統里面有數據,怎么導入storm做計算?

    你需要實現一個Spout,Spout負責將數據emit到storm系統里,交給bolts計算。怎么實現spout可以參考官方的kestrel spout實現:
    https://github.com/nathanmarz/storm-kestrel

    如果你的數據源不支持事務性消費,那么就無法得到storm提供的可靠處理的保證,也沒必要實現ISpout接口中的ack和fail方法。

    二、Storm為了保證tuple的可靠處理,需要保存tuple信息,這會不會導致內存OOM?

    Storm為了保證tuple的可靠處理,acker會保存該節點創建的tuple id的xor值,這稱為ack value,那么每ack一次,就將tuple id和ack value做異或(xor)。當所有產生的tuple都被ack的時候, ack value一定為0。這是個很簡單的策略,對于每一個tuple也只要占用約20個字節的內存。對于100萬tuple,也才20M左右。關于可靠處理看這個:
    https://github.com/nathanmarz/storm/wiki/Guaranteeing-message-processing

    三、Storm計算后的結果保存在哪里?可以保存在外部存儲嗎?

    Storm不處理計算結果的保存,這是應用代碼需要負責的事情,如果數據不大,你可以簡單地保存在內存里,也可以每次都更新數據庫,也可以采用NoSQL存儲。storm并沒有像s4那樣提供一個Persist API,根據時間或者容量來做存儲輸出。這部分事情完全交給用戶。

    數據存儲之后的展現,也是你需要自己處理的,storm UI只提供對topology的監控和統計。

    四、Storm怎么處理重復的tuple?

    因為Storm要保證tuple的可靠處理,當tuple處理失敗或者超時的時候,spout會fail并重新發送該tuple,那么就會有tuple重復計算的問題。這個問題是很難解決的,storm也沒有提供機制幫助你解決。一些可行的策略:
    (1)不處理,這也算是種策略。因為實時計算通常并不要求很高的精確度,后續的批處理計算會更正實時計算的誤差。
    (2)使用第三方集中存儲來過濾,比如利用mysql,memcached或者redis根據邏輯主鍵來去重。
    (3)使用bloom filter做過濾,簡單高效。

    五、Storm的動態增刪節點

    我在storm和s4里比較里談到的動態增刪節點,是指storm可以動態地添加和減少supervisor節點。對于減少節點來說,被移除的supervisor上的worker會被nimbus重新負載均衡到其他supervisor節點上。在storm 0.6.1以前的版本,增加supervisor節點不會影響現有的topology,也就是現有的topology不會重新負載均衡到新的節點上,在擴展集群的時候很不方便,需要重新提交topology。因此我在storm的郵件列表里提了這個問題,storm的開發者nathanmarz創建了一個issue 54并在0.6.1提供了rebalance命令來讓正在運行的topology重新負載均衡,具體見:
    https://github.com/nathanmarz/storm/issues/54
    和0.6.1的變更:
    http://groups.google.com/group/storm-user/browse_thread/thread/24a8fce0b2e53246

    storm并不提供機制來動態調整worker和task數目。

    六、Storm UI里spout統計的complete latency的具體含義是什么?為什么emit的數目會是acked的兩倍?
    這個事實上是storm郵件列表里的一個問題。Storm作者marz的解答:
    The complete latency is the time from the spout emitting a tuple to that
    tuple being acked on the spout
    . So it tracks the time 
    for the whole tuple
    tree to be processed.

    If you dive into the spout component in the UI, you
    'll see that a lot of
    the emitted/transferred is on the __ack* stream. This is the spout
    communicating with the ackers which take care of tracking the tuple trees.


    簡單地說,complete latency表示了tuple從emit到被acked經過的時間,可以認為是tuple以及該tuple的后續子孫(形成一棵樹)整個處理時間。其次spout的emit和transfered還統計了spout和acker之間內部的通信信息,比如對于可靠處理的spout來說,會在emit的時候同時發送一個_ack_init給acker,記錄tuple id到task id的映射,以便ack的時候能找到正確的acker task。

    posted @ 2011-12-19 15:25 dennis 閱讀(14963) | 評論 (9)編輯 收藏

        原文:http://www.tkk7.com/killme2008/archive/2011/11/17/364112.html
        作者:dennis (killme2008@gmail.com)
        轉載請注明出處。

        最近一直在讀twitter開源的這個分布式流計算框架——storm的源碼,還是有必要記錄下一些比較有意思的地方。我按照storm的主要概念進行組織,并且只分析我關注的東西,因此稱之為淺析。       

    一、介紹
        Storm的開發語言主要是Java和Clojure,其中Java定義骨架,而Clojure編寫核心邏輯。源碼統計結果:
         180 text files.
         
    177 unique files.                                          
           
    7 files ignored.

    http:
    //cloc.sourceforge.net v 1.55  T=1.0 s (171.0 files/s, 46869.0 lines/s)
    -------------------------------------------------------------------------------
    Language                     files          blank        comment           code
    -------------------------------------------------------------------------------
    Java                           
    125           5010           2414          25661
    Lisp                            
    33            732            283           4871
    Python                           
    7            742            433           4675
    CSS                              
    1             12             45           1837
    ruby                             
    2             22              0            104
    Bourne Shell                     
    1              0              0              6
    Javascript                       
    2              1             15              6
    -------------------------------------------------------------------------------
    SUM:                           
    171           6519           3190          37160
    -------------------------------------------------------------------------------

        Java代碼25000多行,而Clojure(Lisp)只有4871行,說語言不重要再次證明是扯淡。
            
    二、Topology和Nimbus       
        Topology是storm的核心理念,將spout和bolt組織成一個topology,運行在storm集群里,完成實時分析和計算的任務。這里我主要想介紹下topology部署到storm集群的大概過程。提交一個topology任務到Storm集群是通過StormSubmitter.submitTopology方法提交:
    StormSubmitter.submitTopology(name, conf, builder.createTopology());
        我們將topology打成jar包后,利用bin/storm這個python腳本,執行如下命令:
    bin/storm jar xxxx.jar com.taobao.MyTopology args
        將jar包提交給storm集群。storm腳本會啟動JVM執行Topology的main方法,執行submitTopology的過程。而submitTopology會將jar文件上傳到nimbus,上傳是通過socket傳輸。在storm這個python腳本的jar方法里可以看到:
    def jar(jarfile, klass, *args):                                                                                                                               
       exec_storm_class(                                                                                                                                          
            klass,                                                                                                                                                
            jvmtype
    ="-client",                                                                                                                                    
            extrajars
    =[jarfile, CONF_DIR, STORM_DIR + "/bin"],                                                                                                    
            args
    =args,                                                                                                                                            
            prefix
    ="export STORM_JAR=" + jarfile + ";")
         將jar文件的地址設置為環境變量STORM_JAR,這個環境變量在執行submitTopology的時候用到:
    //StormSubmitter.java 
    private static void submitJar(Map conf) {
            
    if(submittedJar==null) {
                LOG.info(
    "Jar not uploaded to master yet. Submitting jar");
                String localJar 
    = System.getenv("STORM_JAR");
                submittedJar 
    = submitJar(conf, localJar);
            } 
    else {
                LOG.info(
    "Jar already uploaded to master. Not submitting jar.");
            }
        }
        通過環境變量找到jar包的地址,然后上傳。利用環境變量傳參是個小技巧。

        其次,nimbus在接收到jar文件后,存放到數據目錄的inbox目錄,nimbus數據目錄的結構
    -nimbus
         
    -inbox
             
    -stormjar-57f1d694-2865-4b3b-8a7c-99104fc0aea3.jar
             
    -stormjar-76b4e316-b430-4215-9e26-4f33ba4ee520.jar

         
    -stormdist
            
    -storm-id
               
    -stormjar.jar
               
    -stormconf.ser
               
    -stormcode.ser
         其中inbox用于存放提交的jar文件,每個jar文件都重命名為stormjar加上一個32位的UUID。而stormdist存放的是啟動topology后生成的文件,每個topology都分配一個唯一的id,ID的規則是“name-計數-時間戳”。啟動后的topology的jar文件名命名為storm.jar ,而它的配置經過java序列化后存放在stormconf.ser文件,而stormcode.ser是將topology本身序列化后存放的文件。這些文件在部署的時候,supervisor會從這個目錄下載這些文件,然后在supervisor本地執行這些代碼。
        進入重點,topology任務的分配過程(zookeeper路徑說明忽略root):
    1.在zookeeper上創建/taskheartbeats/{storm id} 路徑,用于任務的心跳檢測。storm對zookeeper的一個重要應用就是利用zk的臨時節點做存活檢測。task將定時刷新節點的時間戳,然后nimbus會檢測這個時間戳是否超過timeout設置。
    2.從topology中獲取bolts,spouts設置的并行數目以及全局配置的最大并行數,然后產生task id列表,如[1 2 3 4]
    3.在zookeeper上創建/tasks/{strom id}/{task id}路徑,并存儲task信息
    4.開始分配任務(內部稱為assignment), 具體步驟:
     (1)從zk上獲得已有的assignment(新的toplogy當然沒有了)
     (2)查找所有可用的slot,所謂slot就是可用的worker,在所有supervisor上配置的多個worker的端口。
     (3)將任務均勻地分配給可用的worker,這里有兩種情況:
     (a)task數目比worker多,例如task是[1 2 3 4],可用的slot只有[host1:port1 host2:port1],那么最終是這樣分配
    {1: [host1:port1] 2 : [host2:port1]
             
    3 : [host1:port1] 4 : [host2:port1]}
    ,可以看到任務平均地分配在兩個worker上。
    (b)如果task數目比worker少,例如task是[1 2],而worker有[host1:port1 host1:port2 host2:port1 host2:port2],那么首先會將woker排序,將不同host間隔排列,保證task不會全部分配到同一個worker上,也就是將worker排列成
    [host1:port1 host2:port1 host1:port2 host2:port2]
    ,然后分配任務為
    {1: host1:port1 , 2 : host2:port2}

    (4)記錄啟動時間
    (5)判斷現有的assignment是否跟重新分配的assignment相同,如果相同,不需要變更,否則更新assignment到zookeeper的/assignments/{storm id}上。
    5.啟動topology,所謂啟動,只是將zookeeper上/storms/{storm id}對應的數據里的active設置為true。
    6.nimbus會檢查task的心跳,如果發現task心跳超過超時時間,那么會重新跳到第4步做re-assignment。

    posted @ 2011-12-01 21:48 dennis 閱讀(15217) | 評論 (10)編輯 收藏


        所謂兵馬未動,糧草先行,準備將storm用在某個項目中做實時數據分析。無論任何系統,一定要有監控系統并存,當故障發生的時候你能第一個知道,而不是讓別人告訴你,那處理故障就很被動了。

        因此我寫了這么個項目,取名叫storm-monitor,放在了github上

         https://github.com/killme2008/storm-monitor

        主要功能如下:
    1.監控supervisor數目是否正確,當supervisor掛掉的時候會發送警告。
    2.監控nimbus是否正常運行,monitor會嘗試連接nimbus,如果連接失敗就認為nimbus掛掉。
    3.監控topology是否正常運行,包括它是否正常部署,是否有運行中的任務。

        當故障發生的時候通過alarm方法警告用戶,開放出去的只是簡單地打日志。因為每個公司的告警接口不一樣,所以你需要自己擴展,修改alarm.clj即可。我們這兒就支持旺旺告警和手機短信告警。

        基本的原理很簡單,對supervisor和topology的監控是通過zookeeper來間接地監控,通過定期查看path是否存在。對nimbus的監控是每次起一個短連接連上去,連不上去即認為掛掉。

        整個項目也是用clojure寫。你的機器需要安裝leinexec插件,然后將你的storm.yaml拷貝到conf目錄下,編輯monitor.yaml設定監控參數如檢查間隔等,最后啟動start.sh腳本即可。默認日志輸出在logs/monitor.log。

    posted @ 2011-12-01 21:02 dennis 閱讀(10533) | 評論 (0)編輯 收藏


        在豆瓣發了一些牢騷,索性多說一些我個人對人對事的偏見,既然是偏見,就不會讓人舒服,事先聲明是扯淡,不想浪費時間的人略過。

    1.我們要遠離新浪微博,新浪微博跟twitter不一樣,twitter是為了讓每個人的信息的更好更快地傳播而設計的,而新浪微博是為了讓權威的聲音更好更快地傳播而設計的。迷戀上新浪微博,你要么是權威,要么是跟隨權威。成為權威的,免不了沾沾自喜,真以為自己成了“權威”。更可怕的是你不可避免地要生活在相互吹捧和喧囂中。

    2.在編寫代碼之外,我們可能需要更多的手藝傍身,例如木匠或者廚師,以免在亂世的時候因為不需要程序員而餓死。ps.計算彈道軌跡的程序員除外。

    3.據說真正的牛人從不跳槽,作為大多數不是牛人,以及已經遠離牛人行列的我們(跳槽超過3次以上),跳槽仍然是你提升自己的有效途徑,無論是薪水還是技術。

    4.寫簡歷的技巧,我慢慢領悟到了,少點技術術語,多點成效和應用,打動了HR過了第一關之后,再去跟技術人員扯淡。

    5.簡歷要定時更新,你可以理解成定時提醒下獵頭和HR,關注我啊,關注我啊。

    6.強烈地擁抱文本化,配置文本化(沒人會腦殘地用二進制當配置文件吧?),協議文本化,婚姻文本化。

    7.一切不以加薪為目的的挽留,都是耍流氓,這不是我的原創。

    8.有趣比實用重要,沒趣味的東西,給錢也不去做(好吧,我說假話)。

    9.對新潮的東西保持一點警惕,如果這個東西三個月后還有人在談論,那可以關注下

    10.代碼永遠比文檔、博客真實和靠譜,閱讀代碼習慣了,跟閱讀文檔沒啥區別。

    11.少關注博客和新聞,戒掉看google reader的習慣。現在更多地看maillist上的討論和問題,真正重要的東西你永遠不會錯過。

    12.不追求完美,等你完美的時候別人已經是事實標準。

    13.大型的技術聚會不是為技術人員準備的,這是大公司給員工的度假福利和領導們的吹水時間。只有在小型的技術聚會上才能看到一些有價值的東西,任何稍微跟商業沾一點邊的幾乎都沒有太大價值,我說的是國內。

    14.80%的分享都只對演講者有益,該sb的還是sb,該牛b的還是牛b。最有效的分享是結對編程和結對review。分享和培訓最大的意義是讓行政們覺的自己的存在價值很大。

    15.國內翻譯國外經典>國內原創精品>國外原版,這個原則對英語好的人除外。

    16.極其討厭要求強制縮進的語言,比如python。

    17.標榜是一種人生態度,裝B裝久了你就真牛B了。

    18.憑啥不造輪子,你們造輪子舒坦了,爽快了,就不讓別人造了。我造輪子我快樂。

    19.偏見不全是壞事,壞的是不愿意改變偏見。


        扯淡時間結束。

    posted @ 2011-11-30 22:50 dennis 閱讀(4465) | 評論 (14)編輯 收藏

    今天看到的一個演示TCP慢啟動和滑動窗口機制的動畫,很形象
    osischool.com

    posted @ 2011-11-16 07:34 dennis 閱讀(6564) | 評論 (3)編輯 收藏

    Items\Projects
    Yahoo! s4
    Twitter Storm
    協議
    Apache license 2.0
    Eclipse Public License 1.0
    開發語言
    Java
    Clojure,Java,Clojure編寫了核心代碼
    結構
    去中心化的對等結構
    有中心節點nimbus,但非關鍵
    通信
    可插拔的通訊層,目前是基于UDP的實現 基于facebook開源的thrift框架
    事件/Stream
    <K,A>序列,用戶可自定義事件類 提供Tuple類,用戶不可自定義事件類,
    但是可以命名field和注冊序列化器
    處理單元 Processing Elements,內置PE處理
    count,join和aggregate等常見任務
    Bolt,沒有內置任務,提供IBasicBolt處理
    自動ack
    第三方交互
    提供API,Client Adapter/Driver,第三方客戶端輸入或者輸出事件 定義Spout用于產生Stream,沒有標準輸出API
    持久化 提供Persist API規范,可根據頻率或者次數做
    持久化
    無特定API,用戶可自行選擇處理
    可靠處理 無,可能會丟失事件 提供對事件處理的可靠保證(可選)
    路由EventType + Keyed attribute + value匹配
    內置count,join和aggregate標準任務
    Stream Groupings:
    Shuffle,Fields,All,Global,None,Direct
    非常靈活的路由方式
    多語言支持 暫時只支持Java多語言支持良好,本身支持Java,Clojure,
    其他非JVM語言通過thrift和進程間通訊
    Failover
     部分支持,數據無法failover 部分支持,數據同樣無法failover
    Load Balance
    不支持 不支持
     并行處理 取決于節點數目,不可調節 可配置worker和task數目,storm會盡量將worker和task均勻分布
    動態增刪節點不支持
     支持
    動態部署
     不支持 支持
    web管理 不支持 支持
    代碼成熟度 半成品 成熟
    活躍度 低 活躍
    編程 編程 + XML配置
      純編程
    參考文檔 http://docs.s4.io/https://github.com/nathanmarz/storm/wiki/
    http://xumingming.sinaapp.com/category/storm/ (非常好的中文翻譯)

    posted @ 2011-11-08 22:25 dennis 閱讀(13172) | 評論 (14)編輯 收藏

    clj-xmemcached

        Clj-xmemcached is an opensource memcached client for clojure wrapping xmemcached. Xmemcached is an opensource high performance memcached client for java.

    Leiningen Usage

    To include clj-xmemcached,add:

         [clj-xmemcached "0.1.1"]
    

    to your project.clj.

    Usage

    Create a client

    (use [clj-xmemcached.core])
    (def client (xmemcached 
    "host:port"))
    (def client (xmemcached 
    "host1:port1 host2:port2" :protocol "binary"))

    Then we create a memcached client using binary protocol to talk with memcached servers host1:port1 and host2:port2. Valid options including:

      :name       Client's name
      :protocol  Protocol to talk with memcached,a string value in text,binary or kestrel,default is text protocol.
      :hash          Hash algorithm,a string value in consistent or standard,default is standard hash.
      :timeout    Operation timeout in milliseconds,default is five seconds.
      :pool          Connection pool size,default is one.
    

    Store items


    (xset client "key" "dennis")
    (xset client 
    "key" "dennis" 100)
    (xappend client 
    "key" " zhuang")
    (xprepend client 
    "key" "hello,")

    The value 100 is the expire time for the item in seconds.Store functions include xset,xadd,xreplace,xappend and xprepend.Please use doc to print documentation for these functions.

    Get items

    (xget client "key")
    (xget client 
    "key1" "key2" "key3")
    (xgets client 
    "key")

    xgets returns a value including a cas value,for example:

      {:value "hello,dennis zhuang", :class net.rubyeye.xmemcached.GetsResponse, :cas 396}

    And bulk get returns a HashMap contains existent items.

    Increase/Decrease numbers


    (xincr client "num" 1)
    (xdecr client 
    "num" 1)
    (xincr client 
    "num" 1 0)

    Above codes try to increase/decrease a number in memcached with key "num",and if the item is not exists,then set it to zero.

    Delete items

    (xdelete client "num")

    Compare and set

    (xcas client "key" inc)

    We use inc function to increase the current value in memcached and try to compare and set it at most Integer.MAX_VALUE times. xcas can be called as:

     (xcas client key cas-fn max-times)

    The cas-fn is a function to return a new value,set the new value to

    (cas-fn current-value)

    Shutdown

    (xshutdown client)

    Flush

    (xflush client)
    (xflush client (InetSocketAddress. host port))

    Statistics

    (xstats client)

    Example

    Please see the example code in example/demo.clj

    License

    Copyright (C) 2011-2014 dennis zhuang[killme2008@gmail.com]

    Distributed under the Eclipse Public License, the same as Clojure.

    posted @ 2011-10-30 13:03 dennis 閱讀(3171) | 評論 (0)編輯 收藏


        將自己在googlecode和github上的所有項目過了一遍,整理一張列表,列下一些還有點價值和用處的項目,都不是什么great job,純粹是為了工作需要或者樂趣寫的東西,看官要是有興趣也可以瞧瞧。

     一 Java相關

    1.Xmemcached,還算是比較多人使用的一個java memcached client,優點是效率和易用性,缺點是代碼寫的不怎么樣,兩年前發展到現在的東西,以后還會繼續維護。

    2.HS4J,看handlersocket的時候順手寫的客戶端,我們公司內部某些項目在用,可能還有其他公司外的朋友在用,后來同事聚石貢獻了一個擴展項目hs4j-kit,更易于使用,他寫的代碼很優雅漂亮,推薦一看。暫時沒有精力維護。

    3.Aviator,一個很初級的表達式執行引擎,行家看到肯定要笑話我。不過語法上很符合我自己的口味,我們自己的項目在用,也有幾個朋友在用,會繼續維護。

    4.Jevent,一個玩具,其實是模仿libevent的一個java實現,對nio或者libevent的實現機制感興趣的還可以看看。

    5. Kilim,我fork的kilim實現,修改了nio調度器,使用多個reactor做調度效率更高,并添加了一個HttpClient的實現。

    二 Android項目

    學習android完全是玩票性質,有3個項目,對初學android開發的可能有點參考價值。

    1.WhetherWeather,一個天氣預報和告警的widget插件,UI太丑了。
    2.UniqRecorder,寫來記錄兒子體重變化的小工具,可以自定義項目和生成曲線圖,我自己還在用。
    3.UniqTask,最近寫的殺進程工具,絕對輕量級,沒廣告,也是我自己在用。

    三 Clojure項目

    1.cscheme,一個用clojure實現的scheme解釋器,基于sicp這本書的解釋器實現。
    2.clojure-control,類似node-control的分布式部署和管理的DSL實現,挺好玩的,也有朋友在用,我自己還用不上,sunny有寫了個很方便的lein插件node-control

    clojure還寫了一堆爛尾項目,就不拿出來惡心人了。

    四 其他

    1.node-zk-browser,一個展現和管理zookeeper的web應用,我們自己在用,基于node.js實現。
    2.erlwsh,一個erlang的web shell實現,可以在瀏覽器里做erlang編程,被一些開源項目比如membase用到了。

        寫這些東西對我自己最有好處,如果能順便給他人帶來好處,那是額外的好處。最近正處于我自己一生中也許是最大的轉折關頭,不能更新blog了,最后,祈求諸天神佛能帶來奇跡。

    posted @ 2011-10-09 20:23 dennis 閱讀(6573) | 評論 (15)編輯 收藏


        xmemcached緊急發布1.3.5版本,主要是修復兩個相對嚴重的bug:

    Issue 154: 在重連本地memcached的時候,有可能出現重連無法成功的情況,導致連接丟失,詳情見這里
    Issue 155: 重連導致文件句柄數超過限制的bug,這是由于重連失敗情況下沒有合理關閉socket引起的,詳情見這里

        如果你使用maven,簡單升級版本即可:
     <dependency>
          
    <groupId>com.googlecode.xmemcached</groupId>
          
    <artifactId>xmemcached</artifactId>
          
    <version>1.3.5</version>
     
    </dependency>


        下載地址:http://code.google.com/p/xmemcached/downloads/list

        此版本推薦升級,最后感謝兩位老外開發者的幫助: ilkinulasMrRubato

    posted @ 2011-10-01 15:11 dennis 閱讀(4193) | 評論 (6)編輯 收藏

        好吧,我知道現在是凌晨4點了,寫完這個就睡覺。

        我一直很不爽android的ES任務管理器,它的廣告設置的地方非常惡心,就放在kill鍵的下面,而且每次都突然跳出來,讓你很容易錯誤點擊。我很佩服他們能想出這種提高點擊率的辦法,但是又無比鄙視這種做法。今天(哦,不是昨天)晚上在twitter上說了,我想自己寫個任務管理器,類似ES任務管理器,并且沒有廣告。那好吧,說干就干,奮斗了一個晚上,終于搞出了成果,這就是隆重登場的UniqTask,先看看運行時截圖:



        這是運行在我的GS2上的截圖。

        UniqTask的功能跟ES任務管理器的功能完全一致,可以記錄kill的歷史,每次啟動UniqTask的時候自動標記過去kill過的進程。但是UniqTask完全綠色無毒,絕對沒有廣告,咔咔。

        許久沒寫android程序,拿起手來不是很順利,折騰到現在才搞定,我將代碼放到了github上,也提供了APK下載,非常歡迎試用啊。

        源碼地址:
        https://github.com/killme2008/UniqTask
        APK下載:
        https://github.com/killme2008/UniqTask/blob/master/UniqTask.apk

        白天還有重要的事情要處理,睡覺去了。

    posted @ 2011-09-20 04:10 dennis 閱讀(3103) | 評論 (5)編輯 收藏

    僅列出標題
    共56頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    主站蜘蛛池模板: 香蕉视频亚洲一级| 国产精品亚洲专区在线观看| 国产精品亚洲专区无码不卡| 青草草色A免费观看在线| 亚洲熟妇色自偷自拍另类| 91av在线免费视频| 亚洲欧洲第一a在线观看| 外国成人网在线观看免费视频| 亚洲an天堂an在线观看| 久久精品无码专区免费东京热| 亚洲AV本道一区二区三区四区| 久久国产精品免费网站| 亚洲视频一区在线观看| 999久久久免费精品国产| 亚洲av专区无码观看精品天堂 | 深夜a级毛片免费视频| 亚洲精品456播放| 久久久久久久国产免费看| 国产亚洲综合成人91精品| 一区二区三区在线免费看| 亚洲乱人伦精品图片| 日本免费一区尤物| 一级毛片免费在线观看网站| 国产AV无码专区亚洲AVJULIA| 最近免费中文字幕大全免费版视频| 亚洲精品国产福利片| 日韩午夜免费视频| 成人av片无码免费天天看| 亚洲日韩区在线电影| 成人一a毛片免费视频| 有码人妻在线免费看片| 亚洲AV日韩精品久久久久| 国产乱码免费卡1卡二卡3卡| 亚洲欧美在线x视频| 亚洲AV无码久久精品色欲| 成熟女人牲交片免费观看视频 | 久久精品一本到99热免费| 亚洲性无码一区二区三区| 国产精品亚洲产品一区二区三区| 小日子的在线观看免费| 亚洲AV无码AV吞精久久|