国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

簡單幾步,實現(xiàn) Redis 查詢 “附近的人”

共 22236字,需瀏覽 45分鐘

 ·

2022-11-22 11:42

程序員的成長之路
互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
關(guān)注


閱讀本文大概需要 12 分鐘。

來自:juejin.cn/post/6844903966061363207

前言:針對“附近的人”這一位置服務(wù)領(lǐng)域的應(yīng)用場景,常見的可使用PG、MySQL和MongoDB等多種DB的空間索引進(jìn)行實現(xiàn)。而Redis另辟蹊徑,結(jié)合其有序隊列zset以及geohash編碼,實現(xiàn)了空間搜索功能,且擁有極高的運行效率。
本文將從源碼角度對其算法原理進(jìn)行解析,并推算查詢時間復(fù)雜度。
要提供完整的“附近的人”服務(wù),最基本的是要實現(xiàn)“增”、“刪”、“查”的功能。以下將分別進(jìn)行介紹,其中會重點對查詢功能進(jìn)行解析。

操作命令

自Redis 3.2開始,Redis基于geohash和有序集合提供了地理位置相關(guān)功能。Redis Geo模塊包含了以下6個命令:
  • GEOADD: 將給定的位置對象(緯度、經(jīng)度、名字)添加到指定的key;
  • GEOPOS: 從key里面返回所有給定位置對象的位置(經(jīng)度和緯度);
  • GEODIST: 返回兩個給定位置之間的距離;
  • GEOHASH: 返回一個或多個位置對象的Geohash表示;
  • GEORADIUS: 以給定的經(jīng)緯度為中心,返回目標(biāo)集合中與中心的距離不超過給定最大距離的所有位置對象;
  • GEORADIUSBYMEMBER: 以給定的位置對象為中心,返回與其距離不超過給定最大距離的所有位置對象。
其中,組合使用GEOADD和GEORADIUS可實現(xiàn)“附近的人”中“增”和“查”的基本功能。
要實現(xiàn)微信中“附近的人”功能,可直接使用GEORADIUSBYMEMBER命令。其中“給定的位置對象”即為用戶本人,搜索的對象為其他用戶。
不過本質(zhì)上,GEORADIUSBYMEMBER = GEOPOS + GEORADIUS,即先查找用戶位置再通過該位置搜索附近滿足位置相互距離條件的其他用戶對象。
以下會從源碼角度入手對GEOADD和GEORADIUS命令進(jìn)行分析,剖析其算法原理。
Redis geo操作中只包含了“增”和“查”的操作,并沒有專門的“刪除”命令。主要是因為Redis內(nèi)部使用有序集合(zset)保存位置對象,可用zrem進(jìn)行刪除。
在Redis源碼geo.c的文件注釋中,只說明了該文件為GEOADD、GEORADIUS和GEORADIUSBYMEMBER的實現(xiàn)文件(其實在也實現(xiàn)了另三個命令)。從側(cè)面看出其他三個命令為輔助命令。

GEOADD

使用方式

GEOADD key longitude latitude member [longitude latitude member ...]
將給定的位置對象(緯度、經(jīng)度、名字)添加到指定的key。
其中,key為集合名稱,member為該經(jīng)緯度所對應(yīng)的對象。在實際運用中,當(dāng)所需存儲的對象數(shù)量過多時,可通過設(shè)置多key(如一個省一個key)的方式對對象集合變相做sharding,避免單集合數(shù)量過多。
成功插入后的返回值:
(integer) N
其中N為成功插入的個數(shù)。

源碼分析

/* GEOADD key long lat name [long2 lat2 name2 ... longN latN nameN] */
void geoaddCommand(client *c) {

//參數(shù)校驗
    /* Check arguments number for sanity. */
    if ((c->argc - 2) % 3 != 0) {
        /* Need an odd number of arguments if we got this far... */
        addReplyError(c, "syntax error. Try GEOADD key [x1] [y1] [name1] "
                         "[x2] [y2] [name2] ... ");
        return;
    }

//參數(shù)提取Redis
    int elements = (c->argc - 2) / 3;
    int argc = 2+elements*2/* ZADD key score ele ... */
    robj **argv = zcalloc(argc*sizeof(robj*));
    argv[0] = createRawStringObject("zadd",4);
    argv[1] = c->argv[1]; /* key */
    incrRefCount(argv[1]);

//參數(shù)遍歷+轉(zhuǎn)換
    /* Create the argument vector to call ZADD in order to add all
     * the score,value pairs to the requested zset, where score is actually
     * an encoded version of lat,long. */

    int i;
    for (i = 0; i < elements; i++) {
        double xy[2];

    //提取經(jīng)緯度
        if (extractLongLatOrReply(c, (c->argv+2)+(i*3),xy) == C_ERR) {
            for (i = 0; i < argc; i++)
                if (argv[i]) decrRefCount(argv[i]);
            zfree(argv);
            return;
        }
    
    //將經(jīng)緯度轉(zhuǎn)換為52位的geohash作為分值 & 提取對象名稱
        /* Turn the coordinates into the score of the element. */
        GeoHashBits hash;
        geohashEncodeWGS84(xy[0], xy[1], GEO_STEP_MAX, &hash);
        GeoHashFix52Bits bits = geohashAlign52Bits(hash);
        robj *score = createObject(OBJ_STRING, sdsfromlonglong(bits));
        robj *val = c->argv[2 + i * 3 + 2];

    //設(shè)置有序集合的對象元素名稱和分值
        argv[2+i*2] = score;
        argv[3+i*2] = val;
        incrRefCount(val);
    }

//調(diào)用zadd命令,存儲轉(zhuǎn)化好的對象
    /* Finally call ZADD that will do the work for us. */
    replaceClientCommandVector(c,argc,argv);
    zaddCommand(c);
}
通過源碼分析可以看出Redis內(nèi)部使用有序集合(zset)保存位置對象,有序集合中每個元素都是一個帶位置的對象,元素的score值為其經(jīng)緯度對應(yīng)的52位的geohash值。
double類型精度為52位;
geohash是以base32的方式編碼,52bits最高可存儲10位geohash值,對應(yīng)地理區(qū)域大小為0.6*0.6米的格子。換句話說經(jīng)Redis geo轉(zhuǎn)換過的位置理論上會有約0.3*1.414=0.424米的誤差。

算法小結(jié)

簡單總結(jié)下GEOADD命令都干了啥:
1、參數(shù)提取和校驗;
2、將入?yún)⒔?jīng)緯度轉(zhuǎn)換為52位的geohash值(score);
3、調(diào)用ZADD命令將member及其對應(yīng)的score存入集合key中。

GEORADIUS

使用方式

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] [STORE key] [STORedisT key]
以給定的經(jīng)緯度為中心,返回目標(biāo)集合中與中心的距離不超過給定最大距離的所有位置對象。
范圍單位:m | km | ft | mi --> 米 | 千米 | 英尺 | 英里
額外參數(shù):
  • WITHDIST:在返回位置對象的同時,將位置對象與中心之間的距離也一并返回。距離的單位和用戶給定的范圍單位保持一致。
  • WITHCOORD:將位置對象的經(jīng)度和維度也一并返回。
  • WITHHASH:以 52 位有符號整數(shù)的形式,返回位置對象經(jīng)過原始 geohash 編碼的有序集合分值。這個選項主要用于底層應(yīng)用或者調(diào)試,實際中的作用并不大。
  • ASC|DESC:從近到遠(yuǎn)返回位置對象元素 | 從遠(yuǎn)到近返回位置對象元素。- COUNT count:選取前N個匹配位置對象元素。(不設(shè)置則返回所有元素) - STORE key:將返回結(jié)果的地理位置信息保存到指定key。- STORedisT key:將返回結(jié)果離中心點的距離保存到指定key。
由于 STORE 和 STORedisT 兩個選項的存在,GEORADIUS 和 GEORADIUSBYMEMBER 命令在技術(shù)上會被標(biāo)記為寫入命令,從而只會查詢(寫入)主實例,QPS過高時容易造成主實例讀寫壓力過大。
為解決這個問題,在 Redis 3.2.10 和 Redis 4.0.0 中,分別新增了 GEORADIUS_RO 和 GEORADIUSBYMEMBER_RO兩個只讀命令。
不過,在實際開發(fā)中筆者發(fā)現(xiàn) 在java package Redis.clients.jedis.params.geo 的 GeoRadiusParam 參數(shù)類中并不包含 STORE 和 STORedisT 兩個參數(shù)選項,在調(diào)用georadius時是否真的只查詢了主實例,還是進(jìn)行了只讀封裝。感興趣的朋友可以自己研究下。
成功查詢后的返回值:
不帶WITH限定,返回一個member list,如:
["member1","member2","member3"]
帶WITH限定,member list中每個member也是一個嵌套list,如:
[
 ["member1", distance1, [longitude1, latitude1]]
 ["member2", distance2, [longitude2, latitude2]]
]

源碼分析

此段源碼較長,看不下去的可直接看中文注釋,或直接跳到小結(jié)部分
/* GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC]
 *                               [COUNT count] [STORE key] [STORedisT key]
 * GEORADIUSBYMEMBER key member radius unit ... options ... */

void georadiusGeneric(client *c, int flags) {
    robj *key = c->argv[1];
    robj *storekey = NULL;
    int stoRedist = 0/* 0 for STORE, 1 for STORedisT. */

//根據(jù)key獲取有序集合
    robj *zobj = NULL;
    if ((zobj = lookupKeyReadOrReply(c, key, shared.null[c->resp])) == NULL ||
        checkType(c, zobj, OBJ_ZSET)) {
        return;
    }

//根據(jù)用戶輸入(經(jīng)緯度/member)確認(rèn)中心點經(jīng)緯度
    int base_args;
    double xy[2] = { 0 };
    if (flags & RADIUS_COORDS) {
  ……
    }

//獲取查詢范圍距離
    double radius_meters = 0, conversion = 1;
    if ((radius_meters = extractDistanceOrReply(c, c->argv + base_args - 2,
                                                &conversion)) < 0) {
        return;
    }

//獲取可選參數(shù) (withdist、withhash、withcoords、sort、count)
    int withdist = 0, withhash = 0, withcoords = 0;
    int sort = SORT_NONE;
    long long count = 0;
    if (c->argc > base_args) {
        ... ...
    }

//獲取 STORE 和 STORedisT 參數(shù)
    if (storekey && (withdist || withhash || withcoords)) {
        addReplyError(c,
            "STORE option in GEORADIUS is not compatible with "
            "WITHDIST, WITHHASH and WITHCOORDS options");
        return;
    }

//設(shè)定排序
    if (count != 0 && sort == SORT_NONE) sort = SORT_ASC;

//利用中心點和半徑計算目標(biāo)區(qū)域范圍
    GeoHashRadius georadius =
        geohashGetAreasByRadiusWGS84(xy[0], xy[1], radius_meters);

//對中心點及其周圍8個geohash網(wǎng)格區(qū)域進(jìn)行查找,找出范圍內(nèi)元素對象
    geoArray *ga = geoArrayCreate();
    membersOfAllNeighbors(zobj, georadius, xy[0], xy[1], radius_meters, ga);

//未匹配返空
    /* If no matching results, the user gets an empty reply. */
    if (ga->used == 0 && storekey == NULL) {
        addReplyNull(c);
        geoArrayFree(ga);
        return;
    }

//一些返回值的設(shè)定和返回
    ……
    geoArrayFree(ga);
}
上文代碼中最核心的步驟有兩個,一是“計算中心點范圍”,二是“對中心點及其周圍8個geohash網(wǎng)格區(qū)域進(jìn)行查找”。
對應(yīng)的是geohashGetAreasByRadiusWGS84membersOfAllNeighbors兩個函數(shù)。
我們依次來看:
  • 計算中心點范圍:
// geohash_helper.c
GeoHashRadius geohashGetAreasByRadiusWGS84(double longitude, double latitude,
                                           double radius_meters)
 
{
    return geohashGetAreasByRadius(longitude, latitude, radius_meters);
}

//返回能夠覆蓋目標(biāo)區(qū)域范圍的9個geohashBox
GeoHashRadius geohashGetAreasByRadius(double longitude, double latitude, double radius_meters) {
//一些參數(shù)設(shè)置
    GeoHashRange long_range, lat_range;
    GeoHashRadius radius;
    GeoHashBits hash;
    GeoHashNeighbors neighbors;
    GeoHashArea area;
    double min_lon, max_lon, min_lat, max_lat;
    double bounds[4];
    int steps;

//計算目標(biāo)區(qū)域外接矩形的經(jīng)緯度范圍(目標(biāo)區(qū)域為:以目標(biāo)經(jīng)緯度為中心,半徑為指定距離的圓)
    geohashBoundingBox(longitude, latitude, radius_meters, bounds);
    min_lon = bounds[0];
    min_lat = bounds[1];
    max_lon = bounds[2];
    max_lat = bounds[3];

//根據(jù)目標(biāo)區(qū)域中心點緯度和半徑,計算帶查詢的9個搜索框的geohash精度(位)
//這里用到latitude主要是針對極地的情況對精度進(jìn)行了一些調(diào)整(緯度越高,位數(shù)越小)
    steps = geohashEstimateStepsByRadius(radius_meters,latitude);

//設(shè)置經(jīng)緯度最大最小值:-180<=longitude<=180, -85<=latitude<=85
    geohashGetCoordRange(&long_range,&lat_range);
    
//將待查經(jīng)緯度按指定精度(steps)編碼成geohash值
    geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash);
    
//將geohash值在8個方向上進(jìn)行擴(kuò)充,確定周圍8個Box(neighbors)
    geohashNeighbors(&hash,&neighbors);
    
//根據(jù)hash值確定area經(jīng)緯度范圍
    geohashDecode(long_range,lat_range,hash,&area);

//一些特殊情況處理
    ……

//構(gòu)建并返回結(jié)果    
    radius.hash = hash;
    radius.neighbors = neighbors;
    radius.area = area;
    return radius;
}
  • 對中心點及其周圍8個geohash網(wǎng)格區(qū)域進(jìn)行查找:
// geo.c
//在9個hashBox中獲取想要的元素
int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, double radius, geoArray *ga) {
    GeoHashBits neighbors[9];
    unsigned int i, count = 0, last_processed = 0;
    int debugmsg = 0;

//獲取9個搜索hashBox
    neighbors[0] = n.hash;
    ……
    neighbors[8] = n.neighbors.south_west;

//在每個hashBox中搜索目標(biāo)點
    for (i = 0; i < sizeof(neighbors) / sizeof(*neighbors); i++) {
        if (HASHISZERO(neighbors[i])) {
            if (debugmsg) D("neighbors[%d] is zero",i);
            continue;
        }

 //剔除可能的重復(fù)hashBox (搜索半徑>5000KM時可能出現(xiàn))
        if (last_processed &&
            neighbors[i].bits == neighbors[last_processed].bits &&
            neighbors[i].step == neighbors[last_processed].step)
        {
            continue;
        }

 //搜索hashBox中滿足條件的對象    
        count += membersOfGeoHashBox(zobj, neighbors[i], ga, lon, lat, radius);
        last_processed = i;
    }
    return count;
}


int membersOfGeoHashBox(robj *zobj, GeoHashBits hash, geoArray *ga, double lon, double lat, double radius) {
//獲取hashBox內(nèi)的最大、最小geohash值(52位)
    GeoHashFix52Bits min, max;
    scoresOfGeoHashBox(hash,&min,&max);

//根據(jù)最大、最小geohash值篩選zobj集合中滿足條件的點
    return geoGetPointsInRange(zobj, min, max, lon, lat, radius, ga);
}


int geoGetPointsInRange(robj *zobj, double min, double max, double lon, double lat, double radius, geoArray *ga) {

//搜索Range的參數(shù)邊界設(shè)置(即9個hashBox其中一個的邊界范圍)
    zrangespec range = { .min = min, .max = max, .minex = 0, .maxex = 1 };
    size_t origincount = ga->used;
    sds member;

//搜索集合zobj可能有ZIPLIST和SKIPLIST兩種編碼方式,這里以SKIPLIST為例,邏輯是一樣的
    if (zobj->encoding == OBJ_ENCODING_ZIPLIST) {
        ……
    } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        zskiplist *zsl = zs->zsl;
        zskiplistNode *ln;

 //獲取在hashBox范圍內(nèi)的首個元素(跳表數(shù)據(jù)結(jié)構(gòu),效率可比擬于二叉查找樹),沒有則返0
        if ((ln = zslFirstInRange(zsl, &range)) == NULL) {
            /* Nothing exists starting at our min.  No results. */
            return 0;
        }

 //從首個元素開始遍歷集合
        while (ln) {
            sds ele = ln->ele;
  //遍歷元素超出range范圍則break
            /* Abort when the node is no longer in range. */
            if (!zslValueLteMax(ln->score, &range))
                break;
  //元素校驗(計算元素與中心點的距離)
            ele = sdsdup(ele);
            if (geoAppendIfWithinRadius(ga,lon,lat,radius,ln->score,ele)
                == C_ERR) sdsfree(ele);
            ln = ln->level[0].forward;
        }
    }
    return ga->used - origincount;
}

int geoAppendIfWithinRadius(geoArray *ga, double lon, double lat, double radius, double score, sds member) {
    double distance, xy[2];

//解碼錯誤, 返回error
    if (!decodeGeohash(score,xy)) return C_ERR; /* Can't decode. */

//最終距離校驗(計算球面距離distance看是否小于radius)
    if (!geohashGetDistanceIfInRadiusWGS84(lon,lat, xy[0], xy[1],
                                           radius, &distance))
    {
        return C_ERR;
    }

//構(gòu)建并返回滿足條件的元素
    geoPoint *gp = geoArrayAppend(ga);
    gp->longitude = xy[0];
    gp->latitude = xy[1];
    gp->dist = distance;
    gp->member = member;
    gp->score = score;
    return C_OK;
}

算法小結(jié)

拋開眾多可選參數(shù)不談,簡單總結(jié)下GEORADIUS命令是怎么利用geohash獲取目標(biāo)位置對象的:
1、參數(shù)提取和校驗;
2、利用中心點和輸入半徑計算待查區(qū)域范圍。這個范圍參數(shù)包括滿足條件的最高的geohash網(wǎng)格等級(精度) 以及 對應(yīng)的能夠覆蓋目標(biāo)區(qū)域的九宮格位置;(后續(xù)會有詳細(xì)說明)
3、對九宮格進(jìn)行遍歷,根據(jù)每個geohash網(wǎng)格的范圍框選出位置對象。進(jìn)一步找出與中心點距離小于輸入半徑的對象,進(jìn)行返回。
直接描述不太好理解,我們通過如下兩張圖在對算法進(jìn)行簡單的演示:
圖片
圖片
令左圖的中心為搜索中心,綠色圓形區(qū)域為目標(biāo)區(qū)域,所有點為待搜索的位置對象,紅色點則為滿足條件的位置對象。
在實際搜索時,首先會根據(jù)搜索半徑計算geohash網(wǎng)格等級(即右圖中網(wǎng)格大小等級),并確定九宮格位置(即紅色九宮格位置信息);再依次查找計算九宮格中的點(藍(lán)點和紅點)與中心點的距離,最終篩選出距離范圍內(nèi)的點(紅點)。

算法分析

為什么要用這種算法策略進(jìn)行查詢,或者說這種策略的優(yōu)勢在哪,讓我們以問答的方式進(jìn)行分析說明。
為什么要找到滿足條件的最高的geohash網(wǎng)格等級?為什么用九宮格?
這其實是一個問題,本質(zhì)上是對所有的元素對象進(jìn)行了一次初步篩選。 在多層geohash網(wǎng)格中,每個低等級的geohash網(wǎng)格都是由4個高一級的網(wǎng)格拼接而成(如圖)。
圖片
換句話說,geohash網(wǎng)格等級越高,所覆蓋的地理位置范圍就越小。當(dāng)我們根據(jù)輸入半徑和中心點位置計算出的能夠覆蓋目標(biāo)區(qū)域的最高等級的九宮格(網(wǎng)格)時,就已經(jīng)對九宮格外的元素進(jìn)行了篩除。
這里之所以使用九宮格,而不用單個網(wǎng)格,主要原因還是為了避免邊界情況,盡可能縮小查詢區(qū)域范圍。試想以0經(jīng)緯度為中心,就算查1米范圍,單個網(wǎng)格覆蓋的話也得查整個地球區(qū)域。而向四周八個方向擴(kuò)展一圈可有效避免這個問題。
如何通過geohash網(wǎng)格的范圍框選出元素對象?效率如何?
首先在每個geohash網(wǎng)格中的geohash值都是連續(xù)的,有固定范圍。所以只要找出有序集合中,處在該范圍的位置對象即可。以下是有序集合的跳表數(shù)據(jù)結(jié)構(gòu):
圖片
其擁有類似二叉查找樹的查詢效率,操作平均時間復(fù)雜性為O(log(N))。且最底層的所有元素都以鏈表的形式按序排列。
所以在查詢時,只要找到集合中處在目標(biāo)geohash網(wǎng)格中的第一個值,后續(xù)依次對比即可,不用多次查找。
九宮格不能一起查,要一個個遍歷的原因也在于九宮格各網(wǎng)格對應(yīng)的geohash值不具有連續(xù)性。只有連續(xù)了,查詢效率才會高,不然要多做許多距離運算。
綜上,我們從源碼角度解析了Redis Geo模塊中 “增(GEOADD)” 和 “查(GEORADIUS)” 的詳細(xì)過程。并可推算出Redis中GEORADIUS查找附近的人功能,時間復(fù)雜度為:O(N+log(M))
其中N為指定半徑范圍內(nèi)的位置元素數(shù)量,而M則是被九宮格圈住計算距離的元素的數(shù)量。結(jié)合Redis本身基于內(nèi)存的存儲特性,在實際使用過程中有非常高的運行效率。
<END>

推薦閱讀:

一個網(wǎng)站部署的完整流程(包教包會)

巧用 HTTP 協(xié)議,設(shè)計一個基 于B/S 架構(gòu)的緩存框架!

互聯(lián)網(wǎng)初中高級大廠面試題(9個G)

內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬并發(fā)、消息隊列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!

?戳閱讀原文領(lǐng)??!                                  朕已閱 

瀏覽 39
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 日韩中文字幕电影| 久久青青婷婷| 影音先锋天堂| 天天操天天操天天| 成人毛片18女人毛片真水| 日本三级片中文字幕| 国产天天操| 老司机AV| 一级黄色片免费| 黄色电影av| 亚洲三级无码视频| 黄片免费视频| 搡BBBB搡BBB搡我瞎了| 日本九九视频| 免费日韩一级| 国产高清无码网站| 久久精品国产亚洲AV麻豆痴男| 日逼视频免费观看| 午夜不卡视频| 人人草大香蕉| 成年人国产| 蜜臂AV| 亚洲一级免费在线观看| www久久久| 成人网站在线观看视频| 成人a视频| 97视频国产| 亚洲综合二区| AV超碰| 欧美性爱精品一区| 成人免费无遮挡无码黄漫视频| av资源站| 欧美操b| 91porn在线观看| 亚洲色a| 吴梦梦| 蜜桃一区二区中午字幕| 天天干天天操| 华女与黑人91A∨| 91九色在线| 97视频国产| 免费在线观看一区| A片操逼| 国产亚洲99久久精品| 黄片免费视频| 国产自偷自拍| 亚洲精品福利视频| 日韩va中文字幕无码免费| 色婷婷一区二区三区久久| 97九色| 亚洲性爱小说网址| 啪啪视频m3u8| 激情乱伦网站| 亚洲视频456| 99精品在线| 热99精品| 操逼高清无码| 成人国产精品视频| 国产在线拍偷自揄拍无码一区二区 | 午夜精品人妻无码| 在线视频一区二区| 18禁看网站| 伊人免费视频在线观看| 91久久精品国产91久久公交车| 视色视频在线观看| 婷婷大香蕉| 日韩精品人妻一区二区| 久久久婷婷婷| 亚洲一级在线观看| 国产欧美综合视频| 日韩人妻精品无码| 亚洲日本高清| 天天爽天天搞| 国产亚洲中文| 国产三级麻豆| 国产又粗又猛又爽又黄91精品 | 一区二区三区免费在线观看| 国产成人精品一区| 青青草原成人视频| 91国产精品在线| 婷婷情色| 国产人成| 国产高清无码免费在线观看| 蜜臀av网站| 丰满人妻一区二区三区精品高清| 欧美日韩亚洲一区二区三区| 尻屄电影| 狠狠操一区| 九九九在线观看视频| 亚洲中文字幕在线观看视频网站| 浪潮在线观看完整版| 丁香婷婷色五月| 色婷婷久久综合久色| 亚洲天堂网在线观看| 蜜桃Av噜噜一区二区| 自拍偷拍视频网站| 北条麻妃高清无码| 欧美性猛交XXXX乱大交蜜桃| 国产人人看| 亚洲综合免费观看高清完整版| 欧洲操逼视频| 国产操比视频| 成人免费在线| 国产精品偷拍| 亚洲中文字幕视频在线观看| 亚洲无码黄片| 亚洲小说区图片区| 色性网| 丝袜足交视频| 成人网| 翔田千里av| 最好看的MV中文字幕国语| 中文无码在线视频| 国产黄在线观看| 久在线观看| 日韩午夜福利视频| 日本大香蕉视频| 日本不卡一区二区三区| 黄色小视频免费看| 日韩AV毛片| 成人A片在线观看| 日韩色情片| 四川w搡BBB搡wBBB搡| 国产有码| 欧美视频一区二区三区四区| 婷婷五月天在线观看| 日韩一级A片| mm131亚洲国产精品久久| 欧美城综合在线观看网| 88国产精品| 日韩网站在线| 黄色高清视频在线观看| 18性XXXXX性猛交| 日韩午夜在线观看| 淫香淫色天天影视| 国产av网站大全| 成人片毛片| 日本国产在线| 97精品人人妻人人| 亚洲AV无码精品| 99久久久久久| 久久精品视频免费| 操逼毛片| 天天操天天干欧美精品| 国产精品日韩欧美| 日韩无码一卡二卡| 男女啪啪啪网站| 成人不卡在线| 国产丝袜在线| 成人在线不卡| 无码一二三四| 久久伊| 18禁网站| 亚洲国产精品成人综合色五月| 国产精品18进进出出17c| 拍拍AV| 国产免费性爱视频| 99久免费视频| 色情网站在线| 911国产精品| AV天堂无码| 九九性爱视频| 日本三级无码| 丁香六月婷婷| 日本a一级片| 成人亚洲精品一区二区三区| 九色丨蝌蚪丨老版熟女| 日韩av第一页| 91精品在线免费观看| 中文字幕不卡视频| 99色热| 亚洲av电影在线观看| 99久久国内精品成人免费| 免费操b视频| 色婷婷欧美在线播放内射| 日韩成人免费在线| 国产家庭乱伦| 91精品国产aⅴ一区二区| 西西4444www大胆无| 蜜臀色欲AV无码人妻| av一区二区三区| 成人性生活影视av| 91丨PORN首页| 大香蕉黄色片| 亚洲无码在线免费视频| 黄网免费在线观看| 欧美精产国品一二三区别电影| 囯产精品久久久久久久久久久久久久| 有免费的欧美操逼视频吗| 日本一级黄| 中日韩特黄A片免费视频| 日韩中文在线视频| 亚洲无码综合| 在线日韩中文字幕| 日本一区二区三区四区在线观看 | 波多野结衣无码一区二区| 老太色HD色老太HD-百度| 四虎麻豆| 欧美第一夜| 影音先锋麻豆| 中文字幕首页| AA片网站| 99久热在线精品视频| 久肏| 在线黄色网| 国产精品蜜| 亚洲成色A片77777在线小说| 亚洲A网| 国产乱子伦视频国产印度| 密臀av在线| 伊人国产女| 性爱av在线| 91麻豆国产| 日韩无码成人电影| 日韩在线免费观看视频| 婷婷激情五月| 涩久久久| 日韩电影免费在线观看| 夜夜撸夜夜操| 欧美性爱内射| 激情AV在线观看| 69成人精品国产| 怡红院欧美| 中文字幕乱码无码人妻系列蜜桃| 日本一级黄色| 亚洲国产精品精JIZZ老师| 黄色电影AV| 豆花视频一区二区| 欧美性生交18XXXXX无码| 中文字幕观看| 中文字幕在线观看1| 日韩性爱网址| 91综合久久| 色婷婷激情| 黄色成人视频在线观看| 国偷自产视频一区二区久| 久久精品苍井空免费一区| 国产成人免费做爰视频| 久久人妻熟女中文字幕av蜜芽| 美女黄色视频永费在线观看网站| AⅤ天堂| 欧美成人在线免费视频| 69成人精品国产| 操美女影院| 精品国精品自拍自在线| 久久国产99| 乱子伦国产精品| 大香蕉伊人成人网| 日韩欧美群交| 久久亚洲av| 日韩精品在线免费观看| 尤物视频入口| 国产操逼免费视频| 国产又爽又黄免费网站在线观看 | 中国一级黄色A片| 波多野结衣与黑人| 91久久精品视频| 波多野结衣黄色视频| 俺来也俺去| 久久精品秘一区二区三免费 | 久久久性爱| 欧美一级特黄A片免费观看| 性生活无码| 99在线视频免费观看| 日韩无码18| 一级片黄片| 在线午夜福利| 白浆四溢av| 久草网视频| 午夜久久久久久久久久久久91| 日本在线免费| 亚洲欧洲精品成人久久曰影片| 日韩高清无码片| 亚洲无码影音先锋| 综合色综合| 中文字幕在线中文| 欧美人操逼| 3D动漫精品啪啪一区二区| ww免费视频| 日韩无码激情| 久久久综合网| 97人人色| 热99精品| 免费视频久久久| 又黄又爽无遮挡| 嫩草人人精品免费| 波多野结衣无码AV专区| 日本少妇BBW| 欧美成人一区二区三区| 中国毛片视频| 人妻二区| 麻豆MD传媒MD0071| 日本黄色视频在线免费观看| 色婷婷影院| 手机AV网站| www.亚洲视频| 伊人久久久| 四库影库| 日韩性做爰免费A片AA片| 亚洲成人黄色| 欧美大鸡巴在线观看| 特级黄色视频| 91丨豆花丨成人熟女| 影音先锋国产在线| 成人欧美一区二区三区黑人免费 | 1级毛片| 亚洲视频欧洲视频| 精品人妻一区二区三区在线视频不卡 | 在线成人免费视频| 女人自慰在线观看| 熟女老阿V8888AV| 欧洲激情网| 久久久久久久极品内射| 五月涩| 做爱激情视频网站| 日韩中出视频| 色中文字幕| 尻屄视频网站| 99超碰在线观看| 天堂v在线观看| 第一页在线观看| 亚洲操操操| 六月婷婷在线| 欧美日韩无码| 微拍福利一区二区| 亚洲成人五月天| 欧美中文字幕| 欧日韩在线| 麻豆偷拍| 亚洲成人AV| 大鸡巴视频在线观看| 自拍一区在线观看| 五月婷婷六月色| 视频一视频二在线视频| 日日搔av一区二区三区| 久久久精品人妻| 欧美不卡在线观看| 国产av黄色| 自慰一区| 中文字幕在线观看高清| 精品孕妇一级A片免费看| 在线a | 亚洲色视频| 影音先锋中文字幕av| 亚洲无码三区| 北岛玲丝袜办公室高跟| 欧美视频免费在线观看| 在线观看黄色| 精品视频久久久| 韩国成人啪啪无码高潮| 国产思思99re99在线观看| 亚洲无码精品在线观看| 婷婷五月激情中文字幕| 99xxxxx| 91色色网| 3d动漫精品H区XXXXX区| 精品一区二区三区蜜桃臀www| 精品乱子伦一区二区三区在线播放 | 国产在线小电影| 欧美日韩亚洲另类| 亚洲精品无码久久| 免费无码婬片AAAAA片| 91成人小电影| 深爱开心激情| 亚洲清高毛无码毛片| 蜜桃无码视频小说网站| 国产一级a毛一级a做免费高清视频 | 大肉大捧视频免费观看| 碰碰97| 日韩日韩日韩日韩日韩| 特级西西WWW888| 久久久久久久艹| 7799精品视频| 免费色色视频| 国产人妖视频| 日韩中文字幕视频在线观看| 激情视频网站| 极品少妇av| 99亚洲精品| 特黄色视频| 操操影院| 91丨九色丨国产在线| 日韩一级片| 高清无码日本| 2019中文字幕在线| 在线观看免费成人网站| 中文字幕日韩无码片| 69网站| 日本中文字幕乱伦| 婷婷五月天成人电影| 国产一级乱伦| 青草青草| 91亚洲国产精品| 黄色视频网站免费| 亚洲成人777| 日韩欧美在线视频| 99久久精品国产一区二区成人| 嫩草视频在线观看免费网站| 先锋成人AV| 久久国产精品在线| 大香伊人中文字幕精品| 成人一级黄色电影| 色婷婷电影| 日本国产欧美| 一区在线视频| 精品一区二区三区视频| 成人免费毛片果冻日本| 国产高清无码一区二区| 少妇搡BBBB搡BBB搡造水多, | 亚洲欧洲精品视频| 亚洲AV网站| 麻豆激情视频| 乱伦a片| 97人妻人人揉人人躁人人 | 三级无码片| 欧美一在线一综合| 日韩亚洲欧美在线观看| 操逼操逼操| 国产成人小视频| 深爱激情五月婷婷| 东京热免费视频| 成人精品一区二区区别解析| 人妻少妇被猛烈进入中文字幕| 九九黄片| A级视频免费观看| 黄视频免费在线观看| 亚洲无码一卡二卡| aaa免费| 免费内射视频| 精品一区二区免费视频| 亚洲在线免费| 91毛片在线观看| 亚洲精品天堂无码| 理论片熟女奶水哺乳| 18害羞勿进网站国产| 日韩福利| 婷婷五月一区| 久久免费毛片| 久久久精品人妻| 山西真实国产乱子伦| 夜夜网站| 超碰精品在线| 99视频在线精品| 在线综合国产欧美| 欧美群交在线观看| 免费看黄色的网站| 欧洲三级片| 超碰9999| 婷婷日韩在线| 国产大鸡吧| 欧美午夜成人一区二区三区| 干干影院| 内射视频在线观看| 探花在线综合| 操小逼视频| 婷婷操| 97人妻人人澡人| 韩国成人无码视频| 婷婷久久综合久色综| 色老板在线观看视频| 国产性爱电影网| 人人肏| 99草在线视频| 五月天亚洲激情| www.第四色| 久久夜色精品国产噜噜亚洲AV| 欧美自拍视频| 精品一区二区视频| 豆花视频久久| 亚洲视频网址| 无码人妻一区二区一牛影视| 日韩WWW| 成人黄网站免费观看| 豆花成人社区,视频| 污网站免费观看| 国产精品九九视频| 欧美日皮视频| 超碰碰碰碰| 欧美成人综合一区| 欧美高清无码| 国产精品成人无码a无码| 久久99精品国产.久久久久久| 欧美性视频网站| 久久少妇视频| 精品动漫3D一区二区三区免费版 | 五月天激情爱爱| 亚洲xxxxx| 人人射网站| 天天三级片| 97成人视频| 欧美成人高清视频| 麻豆午夜福利视频| 天天色免费视频| 国产成人精品一区二区三区| 色吧久久| 成人影片在线观看18| 久久成人精品| 亚洲小说欧美激情另类A片小说 | 亚洲精品无码中文| 亚洲天堂在线播放| 国产最新视频| 亚洲aⅤ| 欧美三级不卡| 日韩不卡在线| 五月伊人激情| 91在线无码精品在线看| 久久精品视频播放| 大香蕉av在线| 亚洲成人精品视频| 亚洲XXXXX| 特黄A级毛片| 亚洲成人免费视频| 91视频内射| 日比视频网站| 丰满人妻一区二区三区精品高清| 在线免费黄片| 91成人一区二区三区| 中文字幕手机在线视频| 亚洲一区视频在线| 成人精东影业JDAV3密友| 日韩在线视频网站| 激情成人五月天| 国产欧美综合一区二区| 亚洲人在线观看| av无码高清| 五月天激情性爱| 成人一区在线观看| 日夜夜操| 91熟女丰满原味| 成人免费网站| 婷婷五月丁香色| 国产精品同| 德国肥妇熟妇BBwBBw| 欧美一区二区在线观看| 亚洲无码AV一区二区三区| 中文字幕av免费观看| 一级色色| 青青青在线| 久久久国产精品视频| 躁BBB躁BBB躁BBBBB乃 | 成人午夜婬片A片| 一級免費网站| 夜夜骚精品人妻av一区| av日韩无码| 亚洲色偷精品一区二区三区| 新BBWBBWBBWBBW| 国产三级片视频在线观看| 人妻日韩精品中文字幕| 中国一级A片| 玖玖99视频| 91九色TS另类国产人妖| 三级99| 大吊妞| 国产福利av| 婷婷五月天国产| 亚洲男人天堂视频| 成年人黄色在线观看| 婷婷五月18永久免费视频| 五月天网址| 2025中文字幕| 成人免看一级a一片A片| 一本无码中文字幕| 日本99视频| 西西人体大胆ww4444图片 | 亚洲AV成人无码久久精品麻豆| 操逼在线播放| 91精品国产乱码香蕉黄瓜草莓| 亚洲丰满熟妇| 日韩欧美国产成人| 成人毛片在线播放免费| 在线观看黄色片| 天天综合天天干| 日本在线视频一区二区| 69人妻人人澡人人爽久久| 日韩无码福利| 国产精品H| 韩国毛片基地久久| 黑人一级片| 日韩综合色| 黄色视频在线观看国产| 激情婷婷综合| 97国产精品手机| 亚洲AV无码成人精品区h麻豆| 夫妻无码| 狼友视频在在观看| 一级片日韩| 成人视频无码| 九九精品视频在线播放| 五月婷婷网| 91人妻中文字幕| 91久久精品一区二区三区| 欧洲肥胖BBBBBBBBBB| 精品无码国产一区二区三区51安| 91天堂| 亚洲AV成人精品一区二区三区| 91久久免费视频| 99国产精品久久久久久久成人| 亚洲无码人妻在线| 宅男看片| 天天爽夜夜爽精品成人免费| 97超碰人人| 免费一级a片| 五月丁香婷中文| 中文有码视频| AV在线一区二区三区| 亚洲天堂视频在线播放| 亚洲真人无码| 国产精品欧美日韩| 欧美成人精品A片免费一区99 | 久久露脸国语精品国产91| 免费人成年激情视频在线观看| 免费看操逼| 亚洲综合免费观看| 操逼操逼操逼操逼| 免费无码AV| JULIA超乳JULIA无码| 欧美老妇操逼视频| 另类老妇奶性BBWBBwBBw| 日韩精品中文字幕在线观看| 日本绿色精品视频| 久久系列观看完整指南| 国产操逼免费看| 午夜3D动漫AV| 91热| 操逼视频大全| 伊人无码视频| 亚洲色图在线视频| 成人做爰黄AAA片免费直播岛国 | 亚洲内射无码| 黄色一级片免费在线观看| 婷婷五月999| 日韩99在线观看| 一线天嫩穴少妇| 激情丁香五月| 日本中文在线| 人人插人人操| 亚洲第一av| 亚洲色情在线观看| 性无码一区二区三区无码免费| 国模一区二区| 久热福利| 伊人看片| 黄色免费看视频| 亚欧洲精品在线视频| 天堂久久久久| 五月黄色电影| 天天日天天色天天干| 四虎成人在线| 激情人妻网站| 欧美午夜影院| 91亚洲一区| 人人摸人人摸人人| 伊人成人网视频| 日本一区二区三区视频在线观看 | 午夜福利av在线| 777免费观看成人电影视频| 免费看欧美日黄片| 操噜噜噜噜噜插| 亚洲免费网站| 东京热无码视频| 男女日皮视频| 豆花视频在线| 污网站在线观看| 人人色人人| 午夜黄色| 天堂一区| 欧美激情网| 免费观看黄色视频| 91熟女视频| 黄色一级视频| 日本操逼在线播放| 欧美黄色大香蕉| 伊人久久福利视频| 日本性爱中文字幕| 黄色视频在线免费观看高清视频| 六月婷婷深爱| 午夜AV大片| 午夜色色影院| 久久爱91| 婷婷五月天丁香成人社区| 小黄片在线免费观看| 亚洲无码在线高清| 九九伊人大香蕉| 国产熟妇搡BBBB搡BBBB搡| 性性性性性XXXXX| 一级婬片A片AAAAA毛片| 国产欧美综合三级伦| 日韩三级黄色| 爱搞搞搞搞| 日韩在线观看av| 精品国产va久久久久久久| 蜜臀AV网| NP玩烂了公用爽灌满视频播放| 人人澡超碰碰| 天天操人人| 黄色综合网| 久久久久久高清毛片一级| 国产综合精品久久久久成人AV| 五月香婷婷| 中文AV在线播放| 亚洲va国产va天堂va久久| 91站街农村熟女露脸| 97精品人妻一区二区三区| 99国产在线| 极品美女援交在线| 欧美性猛交一区二区三区精品| 成人网站视频在线免费观看| 高清毛片AAAAAAAAA片| 亚洲色男人天堂| 国产主播AV| 国产在线一区二区三区四区| 北条麻妃一区二区三区在线播放| 黄色电影天堂网| 成人A片免费视频| 天天射网| 婷婷五月天无码| 操逼操逼操逼操逼| 黄色小视频免费看| 狠狠的日| AAAA毛片视频| 成人乱码一区二区三区| 伊人久久大香蕉视频| 91丨熟女丨露脸| 国内超碰| 欧美热热| 超碰97免费在线| 乱伦网址| 91丨人妻丨偷拍| 伊人99| 久操视频在线| 欧美成人性爱网址| 亚洲最新AV在线| 成年人免费毛片| 激情婷婷网| 东方AV在线免费观看| 婷婷五月天网址| 日韩一级黄色| 国产乱子伦-区二区三区| 色婷婷一区二区三区四区五区精品视| 体内射精免费视频| 熟妇操逼视频| 国产aaaaaaaaaa| 亚洲精品一二| 日韩精品免费观看| 五月天国产精品| 日逼视频免费观看| 四川美女网久草| 欧美精品一区二区三区蜜臀| 久久五月天综合| 偷拍久久久| 日韩欧美在线不卡| www.激情五月天| 大香蕉精品视频在线| 欧美一区二区无码视频| 天天干强奸视频在线综合| 操B视频在线免费观看| 五月天综合久久| 91亚洲精品在线| 五月激情六月| 91精片| 一区二区三区无码免费| 2021无码| 国产AV大全| 国产喷水ThePorn| 综合av| 成人小说亚洲一区二区三区| 东方av在| 日韩AV综合| 五月天中文字幕| 蜜挑视频一区二区三区| 婚闹不堪入目A片| 亚洲成人av在线播放| 欧美色视频一区二区三区在线观看 | 国产视频999| 成人亚洲AV| 在线h片| 黄色视频在线观看网站| 手机AV网站| 欧亚一区二区| 国产毛片一区| 97人妻精品一区二区三区视频| 亚洲大片| 欧美黄色大香蕉| 亚洲综合成人在线| 日韩AV无码一区二区| 成人午夜av| 最新中文字幕在线视频| 蜜柚av| 日韩AV一区二区在线观看| 综合合一品道| 五月天乱伦小说| 国产一级片免费观看| 山东熟妇搡BBBB搡BBBB| 一級免費网站| 免费无码婬片aaaa| 欧美一级视频在线观看| 欧美性爱无码| 国产操逼网| 国产一区2区| 豆花视频在线看| 四川婬妇BBw搡BBBB搡| 高清国产AV| 免费看欧美成人A片| 最新亚洲无码在线观看| 91人妻人人澡人人爽人妻| 日本特级片| 做爱网站| 国产精品久久免费视频| 91久久久青青青青草| 操欧美美女| 三级片在线观看视频| 国产九九精品| 欧美黄色成人视频| 黄色电影网站在线观看| 黄色电影A片| 日韩在线欧美在线| av一卡二卡| 中文字幕精品人妻| 午夜福利欧美| 一级黄色AV片| 免费三级怡红院| 你操综合| 精品中文字幕在线观看| 亚洲中文自拍| 日韩在线成人中文字幕亚洲| AⅤ在线| 亚洲色五月| 伊人五月婷婷| 国产精品国产三级国产AⅤ中文 | 蜜桃av色偷偷av老熟女| 黄色免费网站| 俺去啦俺去也| 77久久| 午夜精品18| 无码日韩AV| 99久久精品国产成人一区二区| 很很干在线视频| 天堂资源网| 亚洲日日干| 日比视频网站| 黑人操白人| 午夜福利手机在线| 亚洲精品成人网站| 欧美一级aaa| 国精产品一区二区三区| 亚洲国产成人av| 亚洲天堂av网| 成人自拍视频在线观看| 2019中文字幕在线| 伊人久久精品| 大香蕉伊人在线网| 五月天福利导航| 国产福利美女网站| 奇米色婷婷| 北条麻妃高清无码| 健身房被教练3p喷水了| 亚洲第一色婷婷| 四季AV一区二区夜夜嗨| 国精产品秘一区二区-| 青青操青青干| 亚洲黄色免费| 91久久精品日日躁夜夜躁国产| 天天操视频网站| 人人摸人人操人人射| 五月丁香影院| 在线观看一区二区视频| 草逼视频免费看| 天天色av| 亚洲图片在线播放| 97国产精品视频人人做人人爱| a视频免费在线观看| 人人做人人爽| 亚洲婷婷综合网| 亚洲无码99| 国产操逼免费看| 无码六区| 人妻无码在线视频| 无码在线视频免费观看| 国产性猛交╳XXX乱大交| 91啪啪视频| 日本国产高清| 草逼视频免费看| 白浆在线| 亚洲一区二区三区免费视频| 免费无码婬片AAAA片老婦| 91综合娱乐| www.射| 日本熟妇高潮BBwBBwBBw| 中文字幕免费高清| 国产免费观看AV| 成人小视频18| 日韩综合色视频导航| 成人午夜啪免费视频在线观看软件| 五月伊人激情| 北条麻妃无码一区三区| 西西人体视频| 91国产爽黄| 日韩无码波多野结衣| 群交无码| 91中文字幕|