精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Mongodb源碼分析之balancer(均衡)分析

數據庫 其他數據庫 MongoDB
在之前的Mongodb源碼分析之Mongos分析中,介紹了mongos的啟動流程,在那篇文章的結尾,介紹了mongos使用balancer來進行均衡,今天就繼續講其實現方式。

在之前的Mongodb源碼分析之Mongos分析中,介紹了mongos的啟動流程,在那篇文章的結尾,介紹了mongos使用balancer來進行均衡,今天就繼續講其實現方式。

首先我們看一下Balancer及相關實現策略的類圖:

 

可以看到Balancer類里包含一個BalancerPolicy,其指向一個均衡策略,該策略會實現查找并收集要遷移的chunk。

這里先看一下Balancer的類定義,如下:

  1. //balace.h  
  2. class Balancer : public BackgroundJob {  
  3. public:  
  4. Balancer();  
  5. virtual ~Balancer();  
  6. // BackgroundJob methods  
  7. virtual void run();  
  8. virtual string name() const { return "Balancer"; }  
  9.  
  10. private:  
  11. typedef BalancerPolicy::ChunkInfo CandidateChunk;  
  12. typedef shared_ptr<CandidateChunk> CandidateChunkPtr;  
  13.  
  14. //mongos名稱(hostname:port)  
  15. string _myid;  
  16.  
  17. // Balancer 啟動時間  
  18. time_t _started;  
  19.  
  20. // 前移的chunks數量  
  21. int _balancedLastTime;  
  22.  
  23. // 均衡策略(確定要遷移的chunks)  
  24. BalancerPolicy* _policy;  
  25.  
  26. //初始化,檢查balancer 能否鏈接到servers.該方法可能拋出網絡異常  
  27. bool _init();  
  28.  
  29. /**  
  30.  * 收集關于shards及chunks的信息,以及可能需要遷移的chunks  
  31.  * @param conn: 指向config server(s)連接  
  32.  * @param candidateChunks (IN/OUT): 可能需要遷移的chunks  
  33.  */ 
  34. void _doBalanceRound( DBClientBase& conn, vector<CandidateChunkPtr>* candidateChunks );  
  35.  
  36. /**  
  37.  * 逐個遷移chunk.并返回最終遷移的chunk數量  
  38.  * @param candidateChunks 可能需要遷移的chunks  
  39.  * @return number of chunks effectively moved  
  40.  */ 
  41. int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks );  
  42.  
  43. /*在config server(s)中標記并前balancer為活動狀態.*/ 
  44. void _ping( DBClientBase& conn );  
  45.  
  46. //當configdb中的所有服務均可用時,返回true  
  47. bool _checkOIDs();  
  48. }; 

可以看出balancer繼承自BackgroundJob,所以它是以后臺方式運行的。了解了該類的方法和屬性之后,下面我們著手看一下mongos主函數中啟動balancer.go()的調用流程。因為balancer繼承自BackgroundJob,所以還要看一下BackgroundJob里go()方法的執行代碼, 如下:

  1. //background.cpp 線程方式運行下面的jobBody方法  
  2. BackgroundJob& BackgroundJob::go() {  
  3. boost::thread t( boost::bind( &BackgroundJob::jobBody , this, _status ) );  
  4. return *this;  
  5. }  
  6.  
  7. ////background.cpp. Background object can be only be destroyed after jobBody() ran  
  8. void BackgroundJob::jobBody( boost::shared_ptr<JobStatus> status ) {  
  9. ....  
  10. const string threadName = name();  
  11. if( ! threadName.empty() )  
  12. setThreadName( threadName.c_str() );  
  13.  
  14. try {  
  15. run();//到這里,mongos開始執行子類balancer中的run方法  
  16. }  
  17. ....  
  18.  
  19. if( status->deleteSelf )  
  20. delete this;  

上面代碼最終會將執行流程轉到balancer類的run()方法,如下

  1. void Balancer::run() {  
  2.  
  3. /* this is the body of a BackgroundJob so if we throw   
  4. here we're basically ending the balancer thread prematurely */ 
  5. while ( ! inShutdown() ) {  
  6.  
  7. if ( ! _init() ) {//檢查balancer是否鏈到config server和其它shard上  
  8. log() << "will retry to initialize balancer in one minute" << endl;  
  9. sleepsecs( 60 );  
  10. continue;  
  11. }  
  12.  
  13. break;  
  14. }  
  15. //構造鏈接串信息  
  16. ConnectionString config = configServer.getConnectionString();  
  17. //聲明分布式鎖  
  18. DistributedLock balanceLock( config , "balancer" );  
  19.  
  20. while ( ! inShutdown() ) {//一直循環直到程序中斷或關閉  
  21.  
  22. try {  
  23.  
  24. // 判斷chunk均衡功能是否有效  
  25. if ( ! grid.shouldBalance() ) {  
  26. log(1) << "skipping balancing round because balancing is disabled" << endl;  
  27. sleepsecs( 30 );  
  28. continue;  
  29. }  
  30.  
  31. //從鏈接池中獲取一個鏈接對象,如無鏈接則直接創建。更多內容詳見connpool.cpp文件的  
  32. //DBClientBase* DBConnectionPool::get(const string& host) 方法.  
  33. ScopedDbConnection conn( config );  
  34.  
  35. _ping( conn.conn() );//標識鏈到config server的balancer為活動(live)狀態  
  36. if ( ! _checkOIDs() ) {  
  37. uassert( 13258 , "oids broken after resetting!" , _checkOIDs() );  
  38. }  
  39.  
  40. //重載Shard集合信息(shard 狀態)  
  41. Shard::reloadShardInfo();  
  42.  
  43. //聲明balance鎖對象balanceLock  
  44.  
  45. dist_lock_try lk( &balanceLock , "doing balance round" );  
  46. if ( ! lk.got() ) {  
  47. log(1) << "skipping balancing round because another balancer is active" << endl;  
  48. conn.done();  
  49.  
  50. sleepsecs( 30 ); // no need to wake up soon  
  51. continue;  
  52. }  
  53.  
  54. log(1) << "*** start balancing round" << endl;  
  55.  
  56. vector<CandidateChunkPtr> candidateChunks;  
  57. //獲取在shard集合中建議遷移的chunk信息(包含要遷移到的目標shard信息)  
  58. _doBalanceRound( conn.conn() , &candidateChunks );  
  59. if ( candidateChunks.size() == 0 ) {//是否有要移動的chunk  
  60. log(1) << "no need to move any chunk" << endl;  
  61. }  
  62. else//開始遷移并返回最終遷移數量 {  
  63. _balancedLastTime = _moveChunks( &candidateChunks );  
  64. }  
  65.  
  66. log(1) << "*** end of balancing round" << endl;  
  67. conn.done();//將conn放到鏈接池中(為其它后續操作使用)  
  68.  
  69. sleepsecs( _balancedLastTime ? 5 : 10 );  
  70. }  
  71. catch ( std::exception& e ) {  
  72. log() << "caught exception while doing balance: " << e.what() << endl;  
  73.  
  74. // Just to match the opening statement if in log level 1  
  75. log(1) << "*** End of balancing round" << endl;  
  76.  
  77. sleepsecs( 30 ); // sleep a fair amount b/c of error  
  78. continue;  
  79. }  
  80. }  

上面方法中主要是先構造鏈接串,進而構造連接實例(注:這里使用了鏈接池的概念,我會在后續章節中專門介紹其實現機制)。之后刷新sharding中的相關信息(確保其有效性),之后調用_doBalanceRound()方法來收集可能要遷移的chunk(s)信息并最終完成遷移(使用_moveChunks方法)。

下面我們就著重看一下這兩個方法的具體實現.

首先是_doBalanceRound方法:

  1.    //balance.cpp  
  2. void Balancer::_doBalanceRound( DBClientBase& conn, vector<CandidateChunkPtr>* candidateChunks ) {  
  3. assert( candidateChunks );  
  4.  
  5. // 1. 通過查詢ShardsNS::collections來檢查是否有可用sharded集合來均衡chunk  
  6. auto_ptr<DBClientCursor> cursor = conn.query( ShardNS::collection , BSONObj() );  
  7. vector< string > collections;  
  8. while ( cursor->more() ) {  
  9. BSONObj col = cursor->next();  
  10.  
  11. // sharded collections will have a shard "key".  
  12. if ( ! col["key"].eoo() )  
  13. collections.push_back( col["_id"].String() );  
  14. }  
  15. cursor.reset();  
  16.  
  17. if ( collections.empty() ) {  
  18. log(1) << "no collections to balance" << endl;  
  19. return;  
  20. }  
  21.  
  22. //獲取一個需要均衡的shard信息列表,表中shard信息包括maxsize, currsiez, drain, hsopsqueued  
  23. vector<Shard> allShards;  
  24. Shard::getAllShards( allShards );  
  25. if ( allShards.size() < 2) {  
  26. log(1) << "can't balance without more active shards" << endl;  
  27. return;  
  28. }  
  29. //獲取allShards的相應狀態信息交綁定到shardLimitMap相應元素中,該shardLimitMap是一個從shardId到對象(BSONObj)的映射  
  30. map< string, BSONObj > shardLimitsMap;  
  31. for ( vector<Shard>::const_iterator it = allShards.begin(); it != allShards.end(); ++it ) {  
  32. const Shard& s = *it;  
  33. ShardStatus status = s.getStatus();  
  34.    
  35. //最大值 (單位:兆字節, 0為不限制)  
  36.  
  37. BSONObj limitsObj = BSON( ShardFields::maxSize( s.getMaxSize() ) <<     
  38.  LimitsFields::currSize( status.mapped() ) << //當前時間狀態的信息  
  39.  hardFields::draining( s.isDraining() )  << //當前的shard是否正在被移除  
  40.  LimitsFields::hasOpsQueued( status.hasOpsQueued() )//是否有回寫的隊列信息  
  41. );  
  42.  
  43. shardLimitsMap[ s.getName() ] = limitsObj;  
  44. }  
  45.  
  46. //遍歷collections集合,根據均衡策略(balancing policy) ,檢查是否有要遷移的chunk信息  
  47. for (vector<string>::const_iterator it = collections.begin(); it != collections.end(); ++it ) {  
  48. const string& ns = *it;//集合的名空間  
  49. map< string,vector<BSONObj> > shardToChunksMap;//從shardId 到chunks 的映射  
  50. cursor = conn.query( ShardNS::chunk , QUERY( "ns" << ns ).sort( "min" ) );  
  51. while ( cursor->more() ) {  
  52. BSONObj chunk = cursor->next();  
  53. //以chunk所屬的shard為標識,獲取一個chunks的集合來收集位于同一shard的chunk  
  54. vector<BSONObj>& chunks = shardToChunksMap[chunk["shard"].String()];  
  55. chunks.push_back( chunk.getOwned() );  
  56. }  
  57. cursor.reset();  
  58.  
  59. if (shardToChunksMap.empty()) {  
  60. log(1) << "skipping empty collection (" << ns << ")";  
  61. continue;  
  62. }  
  63.  
  64. for ( vector<Shard>::iterator i=allShards.begin(); i!=allShards.end(); ++i ) {  
  65. // this just makes sure there is an entry in shardToChunksMap for every shard  
  66. Shard s = *i;  
  67. shardToChunksMap[s.getName()].size();  
  68. }  
  69. //找出要遷移的chunk,包括源及目標(要遷移到的)chunk的起始地址  
  70. CandidateChunk* p = _policy->balance( ns , shardLimitsMap , shardToChunksMap , _balancedLastTime /*number of moved chunks in last round*/);  
  71.    if ( p ) candidateChunks->push_back( CandidateChunkPtr( p ) );//存到要均衡的chunk集合中  
  72. }  

上面的_doBalanceRound方法主要構造shardLimitsMap,shardToChunksMap這兩個實例對象集合(map<>類型),其中:

shardLimitsMap:用于收集shard集合中一些“起數量限制”作用的參數,如maxsize,draining,hasOpsQueued等,因為這幾個參數如果超出范圍或為true時,相應shard 是不可以提供遷移服務的。
shardToChunksMap:用于收集當前shard中的chunk信息,以便后面的遍歷操作。

收集了這些信息之后,通過調用 _policy->balance()方法來找出可能需要遷移的chunk().

#p#

下面就看一下該均衡策略的具體實現(具體內容參見注釋):

  1. //balacer_policy.cpp  
  2. BalancerPolicy::ChunkInfo* BalancerPolicy::balance( const string& ns,  
  3. const ShardToLimitsMap& shardToLimitsMap,  
  4. const ShardToChunksMap& shardToChunksMap,  
  5. int balancedLastTime ) {  
  6. pair<string,unsigned> min("",numeric_limits<unsigned>::max());  
  7. pair<string,unsigned> max("",0);  
  8. vector<string> drainingShards;  
  9. //遍歷shard集合,找到min,max的匹配對象,以及draining的Shard信息  
  10. for (ShardToChunksIter i = shardToChunksMap.begin(); i!=shardToChunksMap.end(); ++i ) {  
  11.  
  12. // 遍歷shard,并查看其容量或可用空間是否被耗盡  
  13. const string& shard = i->first;  
  14. BSONObj shardLimits;  
  15. ShardToLimitsIter it = shardToLimitsMap.find( shard );  
  16. if ( it != shardToLimitsMap.end() ) shardLimits = it->second;//獲取shard的信息,包括maxsize, currsiez, drain, hsopsqueued  
  17. const bool maxedOut = isSizeMaxed( shardLimits );//shard是否已滿  
  18. const bool draining = isDraining( shardLimits );//shard是否移除  
  19. const bool opsQueued = hasOpsQueued( shardLimits );//shard是否有寫回隊列  
  20.  
  21. //是否合適接收chunk,滿足下面三個條件之一,則視為不合適  
  22. // + maxed out shards  
  23. // + draining shards  
  24. // + shards with operations queued for writeback  
  25. const unsigned size = i->second.size();//獲取當前shard里的chunk數  
  26. if ( ! maxedOut && ! draining && ! opsQueued ) {  
  27. if ( size < min.second ) {//如果當前shard中chunk數與min比較,找出最小size的shard  
  28. min = make_pair( shard , size );  
  29. }  
  30. }  
  31.  
  32. // 檢查shard 是否應該遷移(chunk donor)  
  33. // Draining shards 比 overloaded shards優先級低  
  34. if ( size > max.second ) {  
  35. max = make_pair( shard , size );//找出最大size的shard  
  36. }  
  37. if ( draining && (size > 0)) {  
  38. drainingShards.push_back( shard );  
  39. }  
  40. }  
  41.  
  42. // 如果chunk沒有合適的shard接收, 意味著上面循環中都是類以draining等情況  
  43. if ( min.second == numeric_limits<unsigned>::max() ) {  
  44. log() << "no availalable shards to take chunks" << endl;  
  45. return NULL;  
  46. }  
  47.  
  48. log(1) << "collection : " << ns << endl;  
  49. log(1) << "donor  : " << max.second << " chunks on " << max.first << endl;  
  50. log(1) << "receiver   : " << min.second << " chunks on " << min.first << endl;  
  51. if ( ! drainingShards.empty() ) {  
  52. string drainingStr;  
  53. joinStringDelim( drainingShards, &drainingStr, ',' );//用逗號將drainingShards連接起來  
  54. log(1) << "draining   : " << ! drainingShards.empty() << "(" << drainingShards.size() << ")" << endl;  
  55. }  
  56.  
  57. // 通過優先級解決不均衡問題.  
  58. const int imbalance = max.second - min.second;//找出shard中最不均衡的size的差距  
  59. const int threshold = balancedLastTime ? 2 : 8;  
  60. string from, to;  
  61. if ( imbalance >= threshold /*臨界點*/) {  
  62. from = max.first;//將shard中chunk最多的作為源  
  63. to = min.first;//將shard中chunk最小的作為要遷移的目的地  
  64. }  
  65. else if ( ! drainingShards.empty() ) {  
  66. //對于那些draining的shard,隨機取出其中一個  
  67. from = drainingShards[ rand() % drainingShards.size() ];  
  68. to = min.first;  
  69. }  
  70. else {  
  71. // 如已均衡,則返回  
  72. return NULL;  
  73. }  
  74.  
  75. //找出要遷移的chunk集合的起始位置  
  76. const vector<BSONObj>& chunksFrom = shardToChunksMap.find( from )->second;  
  77. const vector<BSONObj>& chunksTo = shardToChunksMap.find( to )->second;//找出要遷移到的chunk集合目標位置  
  78. BSONObj chunkToMove = pickChunk( chunksFrom , chunksTo );//最終選出(校正)要遷移的chunk的起始位置  
  79. log() << "chose [" << from << "] to [" << to << "] " << chunkToMove << endl;  
  80. //返回上面balaner的操作結果來執行后續的移動chunk操作  
  81. return new ChunkInfo( ns, to, from, chunkToMove );  

上面方法通過計算各個shard中的當前chunk數量來推算出那個shard相對較空,并將其放到to(目標shard),之后對可能要遷移的chunk進行校驗,這里使用了pickChunk()方法,該方法具體實現如下:

  1. //balancer_policy.cpp  
  2. //找出需要被遷移的chunk, 這里要考慮to端可能比from端chunks更多的情況  
  3. BSONObj BalancerPolicy::pickChunk( const vector<BSONObj>& from, const vector<BSONObj>& to ) {  
  4. // It is possible for a donor ('from') shard to have less chunks than a recevier one ('to')  
  5. // if the donor is in draining mode.  
  6. if ( to.size() == 0 )//如果目標位置為空,表示可以將from中數據全部遷移過去  
  7. return from[0];  
  8. /**wo='well ordered'.  fields must be in same order in each object.  
  9.    Ordering is with respect to the signs of the elements  
  10.    and allows ascending / descending key mixing.  
  11.    @return  <0 if l<r. 0 if l==r. >0 if l>r  
  12. */  
  13. //如果要遷移的chunk中最小值與目標位置的最大值相同,表示可以將from中數據全部遷移過去  
  14. if ( from[0]["min"].Obj().woCompare( to[to.size()-1]["max"].Obj() , BSONObj() , false ) == 0 )  
  15. return from[0];  
  16. //如果要遷移的chunk中最大值與目標位置的最小值相同,表示可以將from中最后一個chunk遷移過去  
  17. if ( from[from.size()-1]["max"].Obj().woCompare( to[0]["min"].Obj() , BSONObj() , false ) == 0 )  
  18. return from[from.size()-1];  
  19.  
  20. return from[0];  

完成了校驗之后,得到的就是真正要遷移的chunk的啟始地址,之后就可以進行遷移了。到這里,我們還要將執行流程跳回到Balancer::run()方法里,看一下最終完成遷移工作的方法movechunk()的實現流程:

  1. //balance.cpp文件  
  2. int Balancer::_moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) {  
  3. //最終遷移的chunk數  
  4. int movedCount = 0;  
  5. //遍歷要遷移chunks并逐一開始遷移  
  6. for ( vector<CandidateChunkPtr>::const_iterator it = candidateChunks->begin(); it != candidateChunks->end(); ++it ) {  
  7. const CandidateChunk& chunkInfo = *it->get();  
  8. //獲取當前chunk要使用的db配置信息  
  9. DBConfigPtr cfg = grid.getDBConfig( chunkInfo.ns );  
  10. assert( cfg );  
  11. //聲明ChunkManager使用它來  
  12. ChunkManagerPtr cm = cfg->getChunkManager( chunkInfo.ns );  
  13. assert( cm );  
  14. //獲取要遷移的chunk起始地址  
  15. const BSONObj& chunkToMove = chunkInfo.chunk;  
  16. ChunkPtr c = cm->findChunk( chunkToMove["min"].Obj() );  
  17. //下面判斷執行兩次,防止執行split之后,系統在reload 情況下chunk可能出現min,max不一致情況  
  18. if ( c->getMin().woCompare( chunkToMove["min"].Obj() ) || c->getMax().woCompare( chunkToMove["max"].Obj() ) ) {  
  19. // 這里主要防止別處執行 split 操作造成負作用  
  20. cm = cfg->getChunkManager( chunkInfo.ns , true /* reload */);  
  21. assert( cm );  
  22.  
  23. c = cm->findChunk( chunkToMove["min"].Obj() );  
  24. if ( c->getMin().woCompare( chunkToMove["min"].Obj() ) || c->getMax().woCompare( chunkToMove["max"].Obj() ) ) {  
  25. log() << "chunk mismatch after reload, ignoring will retry issue cm: " 
  26.   << c->getMin() << " min: " << chunkToMove["min"].Obj() << endl;  
  27. continue;  
  28. }  
  29. }  
  30.  
  31. BSONObj res;  
  32. //將chunk, 從當前的shard ,移動到指定的shard,并累加遷移數量  
  33. if ( c->moveAndCommit( Shard::make( chunkInfo.to ) , Chunk::MaxChunkSize , res ) ) {  
  34. movedCount++;  
  35. continue;  
  36. }  
  37. //如遷移不成功,記入日志  
  38. // the move requires acquiring the collection metadata's lock, which can fail  
  39. log() << "balacer move failed: " << res << " from: " << chunkInfo.from << " to: " << chunkInfo.to  
  40.   << " chunk: " << chunkToMove << endl;  
  41. //chunk是否達到允許移動的最大尺寸,如果是,則對當前shard執行split操作  
  42. if ( res["chunkTooBig"].trueValue() ) {  
  43. // reload just to be safe  
  44. cm = cfg->getChunkManager( chunkInfo.ns );  
  45. assert( cm );  
  46. c = cm->findChunk( chunkToMove["min"].Obj() );  
  47.  
  48. log() << "forcing a split because migrate failed for size reasons" << endl;  
  49.  
  50. res = BSONObj();  
  51. //對當前的shards進行分割(獲取適合的分割點),該方法有些復雜,我會抽時間寫文章介紹  
  52. c->singleSplit( true , res );  
  53. log() << "forced split results: " << res << endl;  
  54.  
  55. // TODO: if the split fails, mark as jumbo SERVER-2571  
  56. }  
  57. }  
  58.  
  59. return movedCount;  

上面代碼就是依次遍歷要遷移的chunk,分別根據其ns信息獲取相應的ChunkManager(該類主要執行chunk的管理,比如CRUD等),之后就通過該ChunkManager找出當前chunk中最小的值(min:參見chunk.h文件,我這里把min,max理解為當前chunk中最小和最大記錄對象信息)chunk信息,并開始遷移。

按照慣例,這里還是用一個時序列來大體回顧一下balancer的執行流程,如下:

 

好了,今天的內容就先到這里了。

原文鏈接:http://www.cnblogs.com/daizhj/archive/2011/05/23/mongos_balancer_source_code.html

【編輯推薦】

  1. Mongodb源碼分析之Mongos分析
  2. Mongodb源碼分析--內存文件映射(MMAP)
  3. 走進MongoDB的世界 展開MongoDB的學習之旅
  4. 淺析Mongodb源碼之游標Cursor
  5. 野心勃勃的NoSQL新貴 MongoDB應用實戰

 

責任編輯:艾婧 來源: 博客園
相關推薦

2011-05-26 10:05:48

MongoDB

2011-04-29 13:40:37

MongoDBCommand

2021-07-06 09:29:38

Cobar源碼AST

2024-06-13 07:55:19

2021-03-23 09:17:58

SpringMVCHttpServletJavaEE

2023-02-26 08:42:10

源碼demouseEffect

2012-09-20 10:07:29

Nginx源碼分析Web服務器

2010-05-04 16:59:52

DNS負載均衡

2011-04-25 17:15:39

MongodbMMAP

2020-07-28 08:54:39

內核通信Netlink

2022-01-06 07:06:52

KubernetesResourceAPI

2017-01-12 14:52:03

JVMFinalRefere源碼

2022-08-27 08:02:09

SQL函數語法

2009-07-08 13:22:30

JDK源碼分析Set

2022-05-30 07:36:54

vmstoragevmselect

2021-09-05 07:35:58

lifecycleAndroid組件原理

2012-09-06 10:07:26

jQuery

2023-11-09 09:08:38

RibbonSpring

2023-03-30 13:32:51

負載均衡器HDFS

2014-08-26 11:11:57

AsyncHttpCl源碼分析
點贊
收藏

51CTO技術棧公眾號

欧美年轻男男videosbes| 日本一区二区在线不卡| 欧美黑人又粗大| 亚洲av无码一区二区三区网址| 欧亚av在线| 欧美国产日韩一二三区| 91传媒视频免费| 国产精品100| 国产精品久久久久久久久久10秀 | 欧美极品美女视频网站在线观看免费 | 亚洲精品在线免费播放| 国产一区亚洲二区三区| 国产在线69| 不卡一区二区在线| 国产有码一区二区| 日韩美女视频网站| 91亚洲国产| 亚洲毛片一区二区| 免费人成视频在线播放| 欧美日韩美女| 亚洲图片欧美色图| 一区二区av| 无码国产精品96久久久久| 麻豆精品一区二区综合av| 91精品国产成人www| www.5588.com毛片| 欧美影院天天5g天天爽| 欧美一级日韩一级| 孩娇小videos精品| 国产精品伦理| 午夜成人在线视频| 国产一二三区在线播放| 北岛玲一区二区三区| 97国产一区二区| 国产91免费视频| 国产女人爽到高潮a毛片| 视频一区视频二区在线观看| 98精品国产自产在线观看| 蜜臀av午夜精品久久| 卡一精品卡二卡三网站乱码| 日韩一区二区影院| 亚洲一区在线不卡| 黑人巨大精品| 激情av一区二区| 亚洲国产精品成人天堂| 精品一性一色一乱农村| 亚洲精选视频免费看| 中文字幕不卡每日更新1区2区| 国产精品毛片一区二区三区四区| 97久久精品人人澡人人爽| 国产伦精品一区二区三区四区视频 | 欧美一区二区三区视频免费播放| 亚洲激情在线观看视频| 天堂久久午夜av| 色婷婷综合久久久久中文一区二区 | 痴汉一区二区三区| 国产精品毛片一区视频播| 麻豆视频一区二区| 成人国产精品久久久| 一级做a爱片久久毛片| 蜜臀久久久99精品久久久久久| 国产精品三级美女白浆呻吟| 亚洲熟妇无码久久精品| 狠狠色丁香久久婷婷综| 91免费在线视频| www.好吊色| 成人97人人超碰人人99| 精品在线一区| 久久久pmvav| 中文字幕欧美日韩一区| 制服国产精品| 青青草原av在线| 亚洲综合免费观看高清完整版在线 | 欧美三级网页| 国内精品久久久| 国产精品免费av一区二区| 国产欧美日韩亚洲一区二区三区| 欧美亚洲国产视频| 最新国产中文字幕| 韩国一区二区在线观看| 国产欧美韩日| 国产精品久久久久一区二区国产 | 国内精品不卡在线| 动漫精品视频| 男人的天堂在线视频| 中文字幕免费在线观看视频一区| 三级网在线观看| www555久久| 日本精品一区二区三区高清| 爱爱爱爱免费视频| 都市激情亚洲| 一区二区欧美久久| 青娱乐国产在线视频| 性一交一乱一区二区洋洋av| 国产精品日韩在线| 国产色综合视频| 久久综合久久鬼色中文字| 一区二区免费电影| 久久www人成免费看片中文| 色狠狠桃花综合| 亚洲成人av免费观看| 亚洲另类av| 欧美日韩爱爱视频| 波多野结衣视频网址| 国产九九视频一区二区三区| 欧美系列一区| 日本高清成人vr专区| 欧洲精品中文字幕| 岛国精品资源网站| 亚洲一区二区三区无吗| 国产成人亚洲综合| 黄色aaa大片| 国产精品成人一区二区三区夜夜夜 | 91精品久久香蕉国产线看观看| 日本在线视频1区| 亚洲黄一区二区三区| 少妇激情一区二区三区| 精品成人自拍视频| 麻豆成人在线看| 午夜一级黄色片| 99这里都是精品| 国产制服91一区二区三区制服| 欧美日韩在线精品一区二区三区激情综合| 欧美不卡视频一区| 亚洲色图综合区| 久久精品国产久精国产| 欧美二区三区在线| 免费高潮视频95在线观看网站| 日韩一区二区在线观看| 美女网站视频色| 日日嗨av一区二区三区四区| 精品国产乱码久久久久| 污污网站在线观看| 日韩一级片在线观看| 亚洲综合第一区| 老司机一区二区三区| 精品久久久久久中文字幕动漫| 午夜小视频福利在线观看| 欧美巨大另类极品videosbest| 先锋影音av在线| 日韩一区欧美二区| 久久精品日韩| 午夜久久中文| 亚洲免费视频在线观看| 日韩黄色一级大片| 99精品国产热久久91蜜凸| 日韩精品在线观看av| 亚洲一区二区三区在线免费| 久久躁日日躁aaaaxxxx| 国产毛片久久久久| 亚洲欧洲中文日韩久久av乱码| 日本中文字幕二区| 天天影视欧美综合在线观看| 亚洲free性xxxx护士白浆| 麻豆免费在线观看| 欧美精品乱人伦久久久久久| 无码人妻精品中文字幕| 国产一二精品视频| 777久久精品一区二区三区无码| 国产精品亚洲四区在线观看| 欧美日韩ab片| 日日夜夜精品免费| 色综合欧美在线视频区| 色欲AV无码精品一区二区久久| 日本不卡一二三区黄网| 中文字幕一区二区三区四区五区 | 精品久久久久久综合日本| 345成人影院| 亚洲最新在线视频| 国产又粗又大又爽视频| 亚洲精品五月天| 国产婷婷在线观看| 老妇喷水一区二区三区| 一区高清视频| 国产精品网在线观看| 91成人在线视频| 懂色一区二区三区| 制服丝袜亚洲色图| 日韩成人一区二区三区| 久久日韩粉嫩一区二区三区| 日韩爱爱小视频| 国产精品videossex久久发布| 欧美国产视频在线观看| 国产亚洲高清在线观看| 久久久久免费精品国产| 男人天堂网在线观看| 6080亚洲精品一区二区| 欧美精品亚洲精品日韩精品| 国产欧美精品一区二区三区四区 | 91亚洲精品久久久蜜桃网站| 精品久久久久久中文字幕2017| 女主播福利一区| 日韩久久不卡| 99久久人爽人人添人人澡| 国产精品aaaa| 丰乳肥臀在线| 中文字幕日韩av电影| 亚洲精品一级片| 欧美亚洲国产一区在线观看网站 | 激情久久久久久久| 台湾成人av| 久久香蕉精品香蕉| 成人xvideos免费视频| av日韩亚洲| 欧美激情a∨在线视频播放| 二区在线视频| 亚洲精品97久久| 国产又粗又猛又爽又黄视频| 狠狠综合久久av一区二区小说| 中文字幕亚洲欧美日韩| 久久精品亚洲一区二区三区浴池 | 久久婷婷五月综合色国产香蕉| 999国产精品999久久久久久| 欧美精品二区三区四区免费看视频 | 欧美亚洲综合网| 日本中文字幕免费| 亚洲欧美日韩国产手机在线 | 五月天国产精品| 色欲一区二区三区精品a片| 久久久久久97三级| 日韩 中文字幕| 成人看片黄a免费看在线| 中文字幕视频三区| 日韩精品一区第一页| 播放灌醉水嫩大学生国内精品| 欧美精品午夜| 国产三级中文字幕| 欧美好骚综合网| 亚洲欧美综合一区| 日本成人小视频| 日本一区二区三区www| 你微笑时很美电视剧整集高清不卡| 国产成人精品福利一区二区三区| 国产亚洲高清一区| 亚洲www在线观看| 91国产一区| 国产视频观看一区| 日日夜夜精品| 亚洲a成v人在线观看| 欧美一级做a| 国产美女主播一区| 国产原创一区| 国产日产欧美a一级在线| 久久91视频| 成人国产精品日本在线| 国产精品视频一区二区三区综合 | 日韩欧美在线精品| 国产伦精品一区二区三区四区免费| 成人免费直播在线| 国产精品theporn88| 国产精品欧美大片| 精品伊人久久大线蕉色首页| 人妖一区二区三区| 欧美色欧美亚洲另类七区| 欧美人与牛zoz0性行为| 日本高清不卡一区二区三| 成人羞羞视频播放网站| 亚洲综合视频一区| 91国语精品自产拍| 国产传媒久久久| 亚洲美女啪啪| 毛片一区二区三区四区| 爽好多水快深点欧美视频| 69久久久久久| 国产精品99久久久久久似苏梦涵 | 97国产精品视频人人做人人爱| 蜜桃av在线| 国产精品video| 综合久久伊人| 国产精品乱码| 国产欧美一区| 99re99热| 亚洲精品字幕| 午夜免费高清视频| 国产裸体歌舞团一区二区| 少妇激情一区二区三区视频| 久久先锋资源网| 国产老头老太做爰视频| 亚洲一区二区中文在线| 中文字幕黄色片| 在线成人免费观看| 日本高清视频免费观看| 亚洲天堂免费观看| 99久久精品免费观看国产| 69久久夜色精品国产7777| 黄色精品视频| 高清国语自产拍免费一区二区三区| 亚洲精品一级二级三级| 99精品一级欧美片免费播放| 久久成人免费| 国产探花一区二区三区| 久久久欧美精品sm网站| 欧美在线视频第一页| 黄色成人av网| 精品人妻少妇嫩草av无码专区| 亚洲精品一区二三区不卡| 国产在线观看av| 国产国语videosex另类| 午夜日韩影院| 亚洲高清在线观看一区| 亚洲精品欧洲| 亚洲制服中文字幕| 国产亚洲欧美在线| 国产一级在线视频| 欧美日韩大陆在线| 色视频在线观看福利| 欧美xxxx综合视频| 精品国产美女a久久9999| 国产欧美日韩综合精品二区| 欧美hd在线| 成人免费观看毛片| 成人黄色一级视频| 人妻人人澡人人添人人爽| 色欧美片视频在线观看| 色婷婷av一区二区三区之红樱桃 | 四虎永久国产精品| 先锋影音久久| 国产+高潮+白浆+无码| 亚洲婷婷综合久久一本伊一区| 波多野结衣av无码| 亚洲欧美激情视频| 美女91在线看| 国产精品日韩欧美一区二区三区 | 国产精品久久久久久久久久久久久久久久 | 在线看女人毛片| 国产精品爽爽爽爽爽爽在线观看| 亚洲三级网址| 成人免费毛片网| eeuss影院一区二区三区| 欧美日韩精品亚洲精品| 欧美一区二区网站| 大地资源网3页在线观看| 国产精品自拍偷拍| 欧美亚洲在线日韩| 亚洲三级视频网站| 国产欧美日韩不卡| 中文字幕+乱码+中文| 亚洲午夜国产成人av电影男同| 无遮挡爽大片在线观看视频 | 久蕉依人在线视频| 国产成人一区三区| 成人短片线上看| 成人精品视频一区二区| 久久久不卡网国产精品二区| 手机看片久久久| 亚洲人成电影网站色www| 亚洲校园激情春色| 日本一区视频在线播放| 日韩精品1区2区3区| 欧美激情 一区| 欧美日韩亚洲高清一区二区| 最近高清中文在线字幕在线观看| 国产欧美精品在线| 亚洲网色网站| 久久无码专区国产精品s| 亚洲电影一区二区| 午夜影院免费体验区| 欧洲亚洲妇女av| 欧美亚洲国产激情| 亚洲一二三不卡| 亚洲一二三专区| 午夜黄色小视频| 国产97在线亚洲| 欧美电影一区| 国产精品91av| 狠狠干狠狠久久| av基地在线| 98国产高清一区| 免费在线亚洲| 成人无码av片在线观看| 777久久久精品| 超碰在线资源| 日韩精品在在线一区二区中文| 黑人精品欧美一区二区蜜桃| 国产精品美女毛片真酒店| 亚洲女人天堂色在线7777| 国产精品4hu.www| www.18av.com| 久久精品日韩一区二区三区| 亚洲专区第一页| 国产69精品久久久久99| 国产日韩欧美一区二区三区| 中文字幕第一页在线视频| 亚洲一区二区综合| jzzjzzjzz亚洲成熟少妇| 亚洲iv一区二区三区| 国产精品资源| 三级全黄做爰视频| 亚洲女人天堂成人av在线| 国产精品白丝久久av网站| 欧美一区二区三区爽大粗免费| 国产精品第四页| 免费播放片a高清在线观看| 96成人在线视频| 日韩精品免费专区| xxxx 国产| 日韩性生活视频| 一区二区三区日本久久久| 久久精品无码一区二区三区毛片| 欧美性猛交99久久久久99按摩|