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

緩存監(jiān)控治理在游戲業(yè)務的實踐和探索

數(shù)據(jù)庫
通過對 Redis 和 Caffeine 的緩存監(jiān)控快速發(fā)現(xiàn)和定位問題降低故障的影響面。

一、緩存監(jiān)控的背景

  • 游戲業(yè)務中存在大量的高頻請求尤其是對熱門游戲而言,而應對高并發(fā)場景緩存是一個常見且有效的手段。
  • 游戲業(yè)務中大量的采用遠程緩存(Redis)和本地緩存(Caffeine)組合方式來應對大流量的場景。
  • 在整個緩存使用的實踐過程中,基于真實線上案例和日常緩存運維痛點沉淀了一些緩存監(jiān)控治理的有效案例供分享。

二、遠程緩存的監(jiān)控介紹

2.1 監(jiān)控的方案

2.1.1 監(jiān)控目的

  • 從宏觀來講監(jiān)控本質(zhì)目的是為了及時發(fā)現(xiàn)定位并解決問題,在成本可控的前提下監(jiān)控維度盡可能豐富。
  • 聚焦到 Redis 的維度,除了 Server 本身的監(jiān)控指標(如請求量、連接數(shù)外),還需要監(jiān)控更多偏業(yè)務的指標。
  • Redis 目前最常見的問題包括:熱點 Key 問題,大 Key 問題,超負載的大請求量問題。
  • 聚焦上述的問題,在基于 Redis 的原生監(jiān)控指標基礎上,補充更多的包含業(yè)務屬性的監(jiān)控。

2.1.2 監(jiān)控方案

  • 目前從監(jiān)控的維度進行分析,希望能做到既能針對某個 key 的熱點監(jiān)控,又能針對某一類相同前綴的 key 做聚合趨勢監(jiān)控。前者目的是發(fā)現(xiàn)熱點 key,后者目的是從趨勢維度監(jiān)控緩存的實際訪問量。
  • Redis 的具體 key的監(jiān)控由 Redis 自研團隊集成到 redis server 側實現(xiàn)監(jiān)控,分類上歸屬為 Redis Server 側的監(jiān)控,這部分不在本篇分享中具體展開。
  • Redis 的某類相同前綴的 key 的聚合監(jiān)控由業(yè)務側通過Aspect 攔截器攔截并上報埋點實現(xiàn),其中 key 的設計需要遵循便于聚合的原則,分類上歸屬為 Redis 的業(yè)務側的監(jiān)控。

2.1.3 監(jiān)控大盤

圖片

【Redis Server系統(tǒng)監(jiān)控指標】

說明:

  • 上圖監(jiān)控 Redis Server 的原生指標,具體可以參考 Redis 官方文檔 
    http://doc.redisfans.com/server/info.html
  • 上述指標用來評估 Redis Server 本身的負載情況,并基于此考慮是否需要橫向和縱向擴容。

圖片

【Redis 業(yè)務維度前綴監(jiān)控指標】

說明:

  • 上圖監(jiān)控的業(yè)務維度按照某類 key 的前綴進行聚合的指標,評估各類的 Redis 的 key 的讀寫指標。
  • 上述指標用來評估業(yè)務對 Redis 緩存使用的合理性,如發(fā)現(xiàn)某個前綴 key 的寫入量太大(緩存應該是讀多寫少場景)就需要思考緩存設計的合理性。

2.2 監(jiān)控的實現(xiàn)

  • 業(yè)務維度按照某類 key 的前綴進行聚合的功能,關鍵的實現(xiàn)邏輯包括:一類業(yè)務需要統(tǒng)一前綴 key 并在末尾拼接變量;通過切面攔截 redis 的讀寫并上報埋點。
  • 統(tǒng)一前綴 key 是指:如果業(yè)務A是按照用戶維度進行緩存 Key 的設計,那么 Key 的形態(tài)應該是 Prefix:UserId,Prefix 是業(yè)務場景的前綴,UserId 是用戶維度的動態(tài)值。
  • 切面攔截是指:針對指定的Redis操作(包括常見的 Set 等),進行攔截并匹配前綴進行埋點上報。

2.2.1 前綴 key 設計

Redis Key 的設計

public class RedisKeyConstants {


    public static final String    REDIS_GAMEGROUP_NEW_KEY              = "newgamegroup";
    public static final String    REDIS_GAMEGROUP_DETAIL_KEY          = "gamegroup:detail";
    public static final String    REDIS_KEY_IUNIT_STRATEGY_COUNT      = "activity:ihandler:strategy:count";
    public static final String    CONTENT_DISTRIBUTE_CURRENT          = "content:distribute:current";
    public static final String    RECOMMEND_NOTE                      = "recommend:note";
}




public class RedisUtils {


    public static final String    COMMON_REDIS_KEY_SPLIT    = ":";


    public static String buildRedisKey(String key, Object... params) {
        if (params == null || params.length == 0) {
            return key;
        }


        for (Object param : params) {
            key += COMMON_REDIS_KEY_SPLIT + param;
        }


        return key;
    }
}

左右滑動查看完整代碼

說明:

  • 在常量定義 RedisKeyConstants 中按照不同的業(yè)務區(qū)分了不同的業(yè)務場景的前綴 Key。
  • 在 RedisUtils#buildRedisKey 中將業(yè)務的前綴和動態(tài)變化的參數(shù)進行拼接,中間通過分隔符進行連接。
  • 分割符的引入是為了后續(xù)切面攔截時候進行逆向切割獲取前綴使用。

2.2.2 監(jiān)控實現(xiàn)

@Slf4j
@Aspect
@Order(0)
@Component
public class RedisMonitorAspect {
    private static final String PREFIX_CONFIG = "redis.monitor.prefix";
    private static final Set<String> PREFIX_SET = new HashSet<>();
    @Resource
    private MonitorComponent monitorComponent;
    static {
        // 更新前綴匹配的名單
        String prefixValue = VivoConfigManager.getString(PREFIX_CONFIG, "");
        refreshConf(prefixValue);
        // 增加配置變更的回調(diào)
        VivoConfigManager.addListener(new VivoConfigListener() {
            @Override
            public void eventReceived(PropertyItem propertyItem, ChangeEventType changeEventType) {
                if (StringUtils.equalsIgnoreCase(propertyItem.getName(), PREFIX_CONFIG)) {
                    refreshConf(propertyItem.getValue());
                }
            }
        });
    }
    /**
     * 更新前綴匹配的名單
     * @param prefixValue
     */
    private static void refreshConf(String prefixValue) {
        if (StringUtils.isNotEmpty(prefixValue)) {
            String[] prefixArr = StringUtils.split(prefixValue, ",");
            Arrays.stream(prefixArr).forEach(item -> PREFIX_SET.add(item));
        }
    }
    @Pointcut("execution(* com.vivo.joint.dal.common.redis.dao.RedisDao.set*(..))")
    public void point() {
    }
    @Around("point()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //業(yè)務邏輯異常情況直接拋到業(yè)務層處理
        Object result = pjp.proceed();
        try {
            if (VivoConfigManager.getBoolean("joint.center.redis.monitor.switch", true)) {
                Object[] args = pjp.getArgs();
                if (null != args && args.length > 0) {
                    String redisKey = String.valueOf(args[0]);
                    if (VivoConfigManager.getBoolean("joint.center.redis.monitor.send.log.switch", true)) {
                        LOGGER.info("更新redis的緩存 {}", redisKey);
                    }
                    String monitorKey = null;
                    // 先指定前綴匹配
                    if (!PREFIX_SET.isEmpty()) {
                        for (String prefix : PREFIX_SET) {
                            if (StringUtils.startsWithIgnoreCase(redisKey, prefix)) {
                                monitorKey = prefix;
                                break;
                            }
                        }
                    }
                    if (StringUtils.isEmpty(monitorKey) && StringUtils.contains(redisKey, ":")) {
                        // 需要考慮前綴的格式,保證數(shù)據(jù)寫入不能膨脹
                        monitorKey = StringUtils.substringBeforeLast(redisKey, ":");
                    }
                    monitorComponent.sendRedisMonitorData(monitorKey);
                }
            }
        } catch (Exception e) {
        }
        return result;
    }
}
printf("hello world!");

說明:

  • 通過 Aspect 的切面功能對 Redis 的指定操作進行攔截,如上圖中的 Set 操作等,可以按需擴展到其他操作(包括 get 命令等)。
  • 針對前綴 key 的提取支持兩個維度,默認場景和自定義場景,其中處理優(yōu)先級為 自定義場景 > 默認場景
  • 默認場景是指如 Redis 的 Key 為 A:B:C:UserId,從后往前尋找后向第一個分割符進行分割,A:B:C:UserId 分割后的根據(jù)前綴 A:B:C 進行聚合后數(shù)據(jù)埋點上報。
  • 自定義場景如 Redis的 Key 為 A:B:UserId,通過配置自定義的前綴 A:B 來匹配,A:B:C:UserId 根據(jù)自定義的前綴分割后根據(jù)前綴 A:B 進行聚合后數(shù)據(jù)埋點上報。
  • 考慮自定義場景的靈活性,相關的自定義前綴通過配置中心實時生效。

2.3 監(jiān)控的案例

public static final String REDISKEY_USER_POPUP_PLAN = "popup:user:plan";
  
    public PopupWindowPlan findPlan(FindPlanParam param) {
        String openId = param.getOpenId();
        String imei = param.getImei();
        String gamePackage = param.getGamePackage();
        Integer planType = param.getPlanType();
        String appId = param.getAppId();




        // 1、獲取緩存的數(shù)據(jù)
        PopupWindowPlan cachedPlan = getPlanFromCache(openId, imei, gamePackage, planType);
        if (cachedPlan != null) {
            monitorPopWinPlan(cachedPlan);
        
            return cachedPlan;
        }


        // 2、未命中換成后從持久化部分獲取對應的 PopupWindowPlan 對象


        // 3、保存到Redis換成
      setPlanToCache(openId, imei, gamePackage, plan);


        return cachedPlan;
    }


    // 從緩存中獲取數(shù)據(jù)的邏輯
    private PopupWindowPlan getPlanFromCache(String openId, String imei, String gamePackage, Integer planType) {


        String key = RedisUtils.buildRedisKey(RedisKeyConstants.REDISKEY_USER_POPUP_PLAN, openId, imei, gamePackage, planType);
        String cacheValue = redisDao.get(key);
        if (StringUtils.isEmpty(cacheValue)) {
            return null;
        }


        try {
            PopupWindowPlan plan = objectMapper.readValue(cacheValue, PopupWindowPlan.class);
            return plan;
        } catch (Exception e) {
        }


        return null;
    }


    // 保存數(shù)據(jù)到緩存當中
    private void setPlanToCache(String openId, String imei, String gamePackage, PopupWindowPlan plan, Integer planType) {


        String key = RedisUtils.buildRedisKey(RedisKeyConstants.REDISKEY_USER_POPUP_PLAN, openId, imei, gamePackage, planType);
        try {
            String serializedStr = objectMapper.writeValueAsString(plan);
            redisDao.set(key, serializedStr, VivoConfigManager.getInteger(ConfigConstants.POPUP_PLAN_CACHE_EXPIRE_TIME, 300));
        } catch (Exception e) {
        }
    }

左右滑動查看完整代碼

說明:

  • 如監(jiān)控實現(xiàn)部分所述,通過 Redis Key 的前綴聚合監(jiān)控,能夠發(fā)現(xiàn)某一類業(yè)務場景的 Redis 的寫請求數(shù),進而發(fā)現(xiàn) Redis 的無效使用場景。
  • 上述案例是典型的Redis的緩存使用場景:1.訪問 Redis 緩存;2.若命中則直接返回結果;3、如未命中則查詢持久化存儲獲取數(shù)據(jù)并寫入 Redis 緩存。
  • 從業(yè)務監(jiān)控的大盤發(fā)現(xiàn)前綴 popup:user:plan 存在大量的 set 操作命令,按照緩存讀多寫少的原則,該場景標明該緩存的設計是無效的。
  • 通過業(yè)務分析后,發(fā)現(xiàn)在游戲的業(yè)務場景中 用戶維度+游戲維度 不存在5分鐘重復訪問緩存的場景,確認緩存的無效。
  • 確認緩存無效后,刪除相關的緩存邏輯,降低了 Redis Server 的負載后并進一步提升了接口的響應時間。

三、本地緩存的監(jiān)控介紹

3.1 監(jiān)控的方案

3.1.1 監(jiān)控目的

  • 從宏觀來講監(jiān)控本質(zhì)目的是為了及時發(fā)現(xiàn)定位并解決問題,在成本可控的前提下監(jiān)控維度盡可能豐富。
  • 聚焦到 Caffeine 的維度,監(jiān)控指標包括緩存的請求次數(shù)、命中率,未命中率等指標。
  • Caffeine 目前最常見的問題是:緩存設置不合理導致緩存穿透引發(fā)的系統(tǒng)問題。

3.1.2 監(jiān)控方案

  • 目前從監(jiān)控的維度進行分析,按照機器維度+緩存實例進行監(jiān)控指標采集,其中監(jiān)控指標的采集基于 Caffeine 的 recordStats 功能開啟。
  • 基于 caffeine 的原生能力定制的 vivo-caffeine 集成了單機器維度+單緩存實例的指標數(shù)據(jù)的采集和上報功能。
  • vivo-caffeine 上報的數(shù)據(jù)會按照單機器+單緩存實例維度進行大盤展示,支持全量指標的查詢功能。
  • vivo-caffeine 的上報的數(shù)據(jù)和公司級的告警功能相結合,例如針對緩存未命中率進行監(jiān)控就能很快發(fā)現(xiàn)緩存穿透的問題。

3.1.3 監(jiān)控大盤

圖片

圖片

【Caffeine 系統(tǒng)監(jiān)控指標】

說明:

  • vivo-caffeine 按照單機器 + 緩存實例維度進行監(jiān)控數(shù)據(jù)的上報并進行展示。
  • 所有的系統(tǒng)指標都支持查詢并以圖片的形式進行展示。

3.2 監(jiān)控的實現(xiàn)

public final class Caffeine<K, V> {
 
  /**
   * caffeine的實例名稱
   */
  String instanceName;
 
  /**
   * caffeine的實例維護的Map信息
   */
  static Map<String, Cache> cacheInstanceMap = new ConcurrentHashMap<>();
 
  @NonNull
  public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
    requireWeightWithWeigher();
    requireNonLoadingCache();
 
    @SuppressWarnings("unchecked")
    Caffeine<K1, V1> self = (Caffeine<K1, V1>) this;
    Cache localCache =  isBounded() ? new BoundedLocalCache.BoundedLocalManualCache<>(self) : new UnboundedLocalCache.UnboundedLocalManualCache<>(self);
 
    if (null != localCache && StringUtils.isNotEmpty(localCache.getInstanceName())) {
      cacheInstanceMap.put(localCache.getInstanceName(), localCache);
    }
 
    return localCache;
  }
}




static Cache<String, List<String>> accountWhiteCache = Caffeine.newBuilder().applyName("accountWhiteCache")
            .expireAfterWrite(VivoConfigManager.getInteger("trade.account.white.list.cache.ttl", 10), TimeUnit.MINUTES)
            .recordStats().maximumSize(VivoConfigManager.getInteger("trade.account.white.list.cache.size", 100)).build();

左右滑動查看完整代碼

說明:

  • Caffeine 的按緩存實例進行指標采集的前提是需要全局維護緩存實例和對應的 instanceName 之間的關聯(lián)關系。
  • Caffeine 在緩存創(chuàng)建的時候會設置實例的名稱,通過 applyName 方法設置實例名稱。
public static StatsData getCacheStats(String instanceName) {
 
    Cache cache = Caffeine.getCacheByInstanceName(instanceName);
 
    CacheStats cacheStats = cache.stats();
    StatsData statsData = new StatsData();
 
    statsData.setInstanceName(instanceName);
    statsData.setTimeStamp(System.currentTimeMillis()/1000);
    statsData.setMemoryUsed(String.valueOf(cache.getMemoryUsed()));
    statsData.setEstimatedSize(String.valueOf(cache.estimatedSize()));
    statsData.setRequestCount(String.valueOf(cacheStats.requestCount()));
    statsData.setHitCount(String.valueOf(cacheStats.hitCount()));
    statsData.setHitRate(String.valueOf(cacheStats.hitRate()));
    statsData.setMissCount(String.valueOf(cacheStats.missCount()));
    statsData.setMissRate(String.valueOf(cacheStats.missRate()));
    statsData.setLoadCount(String.valueOf(cacheStats.loadCount()));
    statsData.setLoadSuccessCount(String.valueOf(cacheStats.loadSuccessCount()));
    statsData.setLoadFailureCount(String.valueOf(cacheStats.loadFailureCount()));
    statsData.setLoadFailureRate(String.valueOf(cacheStats.loadFailureRate()));
 
    Optional<Eviction> optionalEviction = cache.policy().eviction();
    optionalEviction.ifPresent(eviction -> statsData.setMaximumSize(String.valueOf(eviction.getMaximum())));
 
    Optional<Expiration> optionalExpiration = cache.policy().expireAfterWrite();
    optionalExpiration.ifPresent(expiration -> statsData.setExpireAfterWrite(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));
 
    optionalExpiration = cache.policy().expireAfterAccess();
    optionalExpiration.ifPresent(expiration -> statsData.setExpireAfterAccess(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));
 
    optionalExpiration = cache.policy().refreshAfterWrite();
    optionalExpiration.ifPresent(expiration -> statsData.setRefreshAfterWrite(String.valueOf(expiration.getExpiresAfter(TimeUnit.SECONDS))));
 
    return statsData;
}

左右滑動查看完整代碼

說明:

  • 監(jiān)控指標的采集基于 Caffeine 原生的統(tǒng)計功能 CacheStats。
  • 所有采集的指標封裝成一個統(tǒng)計對象 StatsData 進行上報。
public static void sendReportData() {
 
    try {
        if (!VivoConfigManager.getBoolean("memory.caffeine.data.report.switch", true)) {
            return;
        }
 
        // 1、獲取所有的cache實例對象
        Method listCacheInstanceMethod = HANDLER_MANAGER_CLASS.getMethod("listCacheInstance", null);
        List<String> instanceNames = (List)listCacheInstanceMethod.invoke(null, null);
        if (CollectionUtils.isEmpty(instanceNames)) {
            return;
        }
 
        String appName = System.getProperty("app.name");
        String localIp = getLocalIp();
        String localPort = String.valueOf(NetPortUtils.getWorkPort());
        ReportData reportData = new ReportData();
        InstanceData instanceData = new InstanceData();
        instanceData.setAppName(appName);
        instanceData.setIp(localIp);
        instanceData.setPort(localPort);
 
        // 2、遍歷cache實例對象獲取緩存監(jiān)控數(shù)據(jù)
        Method getCacheStatsMethod = HANDLER_MANAGER_CLASS.getMethod("getCacheStats", String.class);
        Map<String, StatsData> statsDataMap = new HashMap<>();
        instanceNames.stream().forEach(instanceName -> {
 
            try {
                StatsData statsData = (StatsData)getCacheStatsMethod.invoke(null, instanceName);
 
                statsDataMap.put(instanceName, statsData);
            } catch (Exception e) {
 
            }
        });
 
        // 3、構建上報對象
        reportData.setInstanceData(instanceData);
        reportData.setStatsDataMap(statsDataMap);
 
        // 4、發(fā)送Http的POST請求
        HttpPost httpPost = new HttpPost(getReportDataUrl());
        httpPost.setConfig(requestConfig);
 
        StringEntity stringEntity = new StringEntity(JSON.toJSONString(reportData));
        stringEntity.setContentType("application/json");
        httpPost.setEntity(stringEntity);
 
        HttpResponse response = httpClient.execute(httpPost);
        String result = EntityUtils.toString(response.getEntity(),"UTF-8");
        EntityUtils.consume(response.getEntity());
 
        logger.info("Caffeine 數(shù)據(jù)上報成功 URL {} 參數(shù) {} 結果 {}", getReportDataUrl(), JSON.toJSONString(reportData), result);
    } catch (Throwable throwable) {
        logger.error("Caffeine 數(shù)據(jù)上報失敗 URL {} ", getReportDataUrl(), throwable);
    }
}

左右滑動查看完整代碼

說明:

  • 每個應用單獨的部署的服務作為一個采集點,進行指標的采集和上報。
  • 采集過程是獲取當前部署的應用下的所有緩存實例并進行指標的采集封裝。
  • 整體上報采用 Http 協(xié)議進行上報并最終展示到監(jiān)控平臺。

3.3 監(jiān)控的案例

圖片

說明:

  • 某次線上問題發(fā)生時發(fā)現(xiàn)突然多出了大量的 Redis 的請求,但是無法具體定位請求的 Redis 的前綴 key,設想如果接入了 Redis 的業(yè)務監(jiān)控,問題來源就能很快定位。
  • 在后續(xù)的問題排查中發(fā)現(xiàn)某個 Caffeine 的本地緩存因為大小設置過小導致大量的本地請求緩存穿透導致 Redis 的請求量突增,最終導致 Redis 的服務接近崩潰。
  • 針對本地緩存穿透的場景,如果采用 Caffeine 的本地緩存監(jiān)控方案,能夠從緩存的命中率指標和緩存的未命中率指標突增突降中發(fā)現(xiàn)問題根源。

四、結束語

  • 本篇內(nèi)容是基于線上真實案例分享游戲業(yè)務側在緩存監(jiān)控治理方面的有效實踐,監(jiān)控治理本身是一個未雨綢繆的過程。在沒有線上問題發(fā)生時看似不重要,但一旦發(fā)生無法快速定位問題又會導致問題的放大,因此完善的緩存監(jiān)控整理其實是非常有必要的。
  • Redis 的前綴 key 的監(jiān)控思路是游戲業(yè)務服務端在優(yōu)化Redis 的使用效率的過程中發(fā)現(xiàn)的一個較好的實踐,逐步延伸后發(fā)現(xiàn)這是一個很好的監(jiān)控手段,能夠通過突增的趨勢快速定位問題。
  • 基于 Caffeine 的原生能力定制的監(jiān)控指標采集是游戲業(yè)務服務端在探索 Caffeine 可視化過程中進行的一個探索落地,將整個緩存實例的運行態(tài)進行完整呈現(xiàn),為業(yè)務穩(wěn)定性貢獻力量。
  • 相信業(yè)內(nèi)同仁會有更多更好的實踐,相互分享共同進步,共勉。
責任編輯:龐桂玉 來源: vivo互聯(lián)網(wǎng)技術
相關推薦

2015-09-23 10:25:41

Docker英雄聯(lián)盟Docker實踐

2023-03-15 18:34:26

資源治理數(shù)據(jù)治理業(yè)務線

2024-10-15 08:14:51

2016-01-12 11:38:19

智能化運維運維業(yè)務

2023-10-27 12:16:23

游戲發(fā)行平臺SOP

2021-12-08 10:35:04

開源監(jiān)控Zabbix

2015-08-17 09:39:33

智能運維百度監(jiān)控

2022-05-13 11:24:09

數(shù)據(jù)美團

2023-12-21 14:02:11

AIGC趣丸科技素材

2022-12-26 16:34:51

開源云原生

2021-08-09 10:21:42

云原生Dubbo3.0 服務治理

2019-04-30 09:00:33

SQL數(shù)據(jù)庫Apache Flin

2020-08-20 07:54:58

Node多線程解密

2024-07-25 14:04:16

2019-04-09 15:02:36

OpenResty騰訊游戲營銷技術

2023-02-07 07:03:39

2022-04-28 09:36:47

Redis內(nèi)存結構內(nèi)存管理

2025-01-15 09:16:10

2023-06-23 15:17:32

數(shù)據(jù)分析

2024-10-16 20:31:25

點贊
收藏

51CTO技術棧公眾號

电影91久久久| 三级av在线播放| 五月婷婷六月综合| 欧美www视频| 俄罗斯av网站| 二区在线视频| 国产成人综合在线播放| 1769国内精品视频在线播放| 男人的天堂av网| 日韩精品三级| 欧洲视频一区二区| 女人被男人躁得好爽免费视频| 天堂a中文在线| 激情小说亚洲一区| 欧美整片在线观看| 老湿机69福利| 精品国产91久久久久久浪潮蜜月| 日韩一区二区三免费高清| 国产麻花豆剧传媒精品mv在线| 成人短视频在线观看| 久久影音资源网| 亚洲综合av影视| 337p粉嫩色噜噜噜大肥臀| 中文字幕一区二区三区欧美日韩| 亚洲午夜精品视频| 无码av免费精品一区二区三区| 日韩天堂在线| 午夜天堂影视香蕉久久| 在线视频欧美一区| 国产中文字幕在线播放| 菠萝蜜视频在线观看一区| 国产精品一区二区久久久| 日韩在线观看第一页| 综合激情视频| 久久精品国产亚洲精品| 国产又大又粗又爽的毛片| 成人资源在线播放| 欧美一区二区大片| 亚洲精品自拍网| 桃花岛成人影院| 黑人巨大精品欧美一区二区三区| 日本aa在线观看| 婷婷色在线播放| 成人免费在线视频| 亚洲欧美成人一区| 国产一级片在线播放| 91在线精品一区二区| 国产精品日韩高清| 亚洲卡一卡二卡三| 粉嫩绯色av一区二区在线观看| 97久久夜色精品国产九色 | 亚洲三级电影在线观看| 久久视频在线观看免费| 国产中文字幕久久| 色综合久久一区二区三区| 亚洲一区第一页| 国产女主播喷水高潮网红在线| 色狼人综合干| 精品爽片免费看久久| 亚洲av成人片色在线观看高潮 | 这里只有精品视频在线观看| 一区二区三区视频在线观看免费| 欧美暴力调教| 在线精品视频免费播放| 在线视频日韩一区| 欧美午夜三级| 欧美男人的天堂一二区| 日韩 国产 一区| 日本亚州欧洲精品不卡| 精品精品国产高清a毛片牛牛| 无码人妻丰满熟妇区毛片蜜桃精品| 久久精品九色| 亚洲国产毛片完整版| 911亚洲精选| 欧美sss在线视频| 亚洲精品在线观看www| 精品欧美一区二区久久久| 欧美理论视频| 欧美裸体xxxx极品少妇| 日韩精品――中文字幕| 日韩精品亚洲一区二区三区免费| 国产欧美一区二区三区久久 | 日韩免费小视频| 欧美视频在线一区二区三区| 手机av在线网站| 欧美精品国产白浆久久久久| 一本一本久久a久久精品牛牛影视 一本色道久久综合亚洲精品小说 一本色道久久综合狠狠躁篇怎么玩 | 国产偷国产偷精品高清尤物 | 国内一区二区在线视频观看| 男女网站在线观看| 中文字幕一区二区日韩精品绯色| 成人毛片100部免费看| 欧美aa免费在线| 欧美视频自拍偷拍| 国产精品久久久久久在线观看| 香蕉精品久久| 欧美成人一区在线| 久久久久久在线观看| 久久99蜜桃精品| 精品日韩电影| 欧美日韩xx| 欧美视频二区36p| 性鲍视频在线观看| 国产欧美久久一区二区三区| 美女久久久久久久久久久| 国产午夜免费福利| 国产精品亚洲一区二区三区妖精| 精品一区二区三区自拍图片区 | 国产一级免费大片| 在线日韩网站| 欧美精品久久久久a| 在线播放国产一区| 91蜜桃视频在线| 国产又粗又长又爽视频| 成人精品动漫| 亚洲美女av在线播放| 久久艹精品视频| 蜜桃av一区二区| 久久艳妇乳肉豪妇荡乳av| 97影院秋霞午夜在线观看| 日本福利一区二区| 国产精品无码在线| 中文字幕一区二区三区在线视频 | 小早川怜子一区二区三区| 一区二区美女| 97色伦亚洲国产| 亚洲xxx在线| 亚洲视频一区二区在线| 丁香婷婷激情网| 亚洲精品国产setv| 国外成人在线播放| www.久久精品.com| 亚洲欧美偷拍另类a∨色屁股| 欧美日韩亚洲自拍| 免费av一区| 2019日本中文字幕| 欧美自拍偷拍一区二区| 亚洲综合视频在线观看| 日韩视频在线观看一区二区三区| 青青一区二区三区| 国产精品老牛影院在线观看| 国产私人尤物无码不卡| 日韩欧美精品中文字幕| 色呦呦一区二区| 99精品国产99久久久久久福利| 99国产超薄丝袜足j在线观看| 免费av不卡| 337p亚洲精品色噜噜噜| 国产精品99久久久久久成人| 激情综合网最新| 欧美日韩午夜爽爽| 日韩视频一二区| 欧美激情视频一区| 色婷婷激情五月| 精品久久久久久亚洲国产300 | 国产区精品在线| 一区二区三区日韩欧美| 免费观看一区二区三区| 红桃视频国产一区| 国内精品**久久毛片app| 丝袜老师在线| 亚洲人成毛片在线播放| 国产精品露脸视频| 国产精品第一页第二页第三页| 欧美激情第3页| 欧美在线黄色| 国产亚洲情侣一区二区无| 老牛影视精品| 国产亚洲精品91在线| 一级黄色短视频| 一区二区三区加勒比av| 动漫美女无遮挡免费| 性高湖久久久久久久久| 天天综合色天天综合色hd| 亚洲精品自拍| 久久久久久国产免费| 男人的天堂在线视频| 欧美久久一区二区| 久草中文在线视频| 国产丝袜美腿一区二区三区| 欧美美女性视频| 亚洲视频日本| 九九九九精品| 国产精品麻豆成人av电影艾秋| 久久亚洲精品一区二区| 天堂а√在线8种子蜜桃视频 | 亚洲天堂av网站| 日韩成人精品在线| 亚洲乱码日产精品bd在线观看| 精品亚洲精品| 国产在线观看一区二区三区| 黄页网站在线| 亚洲情综合五月天| www香蕉视频| 色美美综合视频| 九九视频免费观看| 亚洲国产精品精华液2区45| 日本少妇xxxx软件| 日韩二区三区在线观看| 日本黄色片一级片| 精品免费av| 狠狠色狠狠色综合人人| 日韩一区二区三免费高清在线观看| 国产自产2019最新不卡| 亚洲xxx视频| 无遮挡在线观看| 久久久成人精品| 日本免费一区二区三区最新| 欧美一区二区二区| 亚洲精品毛片一区二区三区| 伊人开心综合网| 国产农村妇女精品一区| av中文字幕一区| 亚洲黄色av片| 日本亚洲天堂网| wwwwww欧美| 午夜精品一区二区三区国产 | 1769国内精品视频在线播放| 成人影院在线观看| 中文字幕日韩欧美| 欧美日韩在线中文字幕| 亚洲成人久久一区| 国产肥老妇视频| 欧美人体做爰大胆视频| 国产一区二区视频免费| 欧美日韩国产精品一区| wwwav国产| 日韩一区欧美小说| 国产精品www爽爽爽| 久久久久久97三级| 野外性满足hd| 91亚洲精品久久久蜜桃| 日本道中文字幕| 成人免费观看男女羞羞视频| 在线免费观看av网| 麻豆精品在线看| 日本xxxx黄色| 青青草国产精品亚洲专区无| av片中文字幕| 老司机久久99久久精品播放免费| 热99这里只有精品| 一本久久综合| 成人黄色av片| 午夜在线精品| 欧美xxxxx在线视频| 性感少妇一区| 九色porny91| 日本免费在线视频不卡一不卡二| 午夜肉伦伦影院| 久久先锋资源| 三级a在线观看| 麻豆成人久久精品二区三区小说| 国内自拍视频网| 久久精品国产精品亚洲综合| 中文字幕中文在线| 国产综合一区二区| 手机看片国产精品| 国产99久久久国产精品免费看 | 国产欧美一区二区三区网站| 亚洲色成人网站www永久四虎| 国产情人综合久久777777| www亚洲色图| 亚洲婷婷国产精品电影人久久| 成人自拍小视频| 亚洲一区在线免费观看| 中文字幕亚洲精品在线| 日本丰满少妇一区二区三区| 亚洲天堂中文网| 日韩一区二区三区电影| 日本精品一二区| 国产一区二区三区直播精品电影| 日本福利在线| 色综合久综合久久综合久鬼88| 国产99在线观看| 国产精品视频一| av综合网页| 日韩片电影在线免费观看| 亚洲v在线看| 欧美成人三级在线视频| 日韩国产欧美一区二区三区| 日韩在线一区视频| 成人一区在线看| 国产91丝袜美女在线播放| 日韩理论片一区二区| 亚洲国产精一区二区三区性色| 欧美视频在线免费看| 一二区在线观看| 亚洲国模精品一区| 中文字幕日本在线| 孩xxxx性bbbb欧美| 成人全视频免费观看在线看| 99在线国产| 成人一区二区| 老太脱裤让老头玩ⅹxxxx| 免费观看一级特黄欧美大片| 欧美丰满熟妇bbb久久久| 久久精品亚洲精品国产欧美| 国模无码国产精品视频| 91国偷自产一区二区三区观看 | 久久精品夜夜夜夜久久| 亚洲色图综合区| 91黄色免费观看| 黄色片一区二区| 日韩视频精品在线| 2020日本在线视频中文字幕| 91精品久久久久久综合乱菊| 欧美网色网址| 97超碰在线视| 久久国产欧美日韩精品| 一级做a爰片毛片| 亚洲摸摸操操av| 中文在线a天堂| 国产婷婷成人久久av免费高清| 精品美女在线观看视频在线观看 | 九九九在线观看视频| www.日韩av| 欧美精品一区二区蜜桃| 欧美日韩精品一区二区在线播放| 日韩亚洲视频在线观看| 久精品免费视频| 高清不卡一区| 亚洲欧洲一区二区福利| 久久久久综合| 国产中文字幕一区二区| 亚洲一线二线三线久久久| 99精品国产99久久久久久97| 色妞欧美日韩在线| 亚洲精品国产嫩草在线观看| 麻豆91av| 噜噜噜91成人网| 日韩av在线看免费观看| 亚洲成人第一页| 国产成人三级在线观看视频| 欧美成人久久久| 国产专区精品| 日本在线视频www色| 蓝色福利精品导航| 自拍偷拍第9页| 精品污污网站免费看| 北岛玲日韩精品一区二区三区| 日本精品中文字幕| 欧美激情在线精品一区二区三区| 少妇av一区二区三区无码| aa级大片欧美| 国产乱国产乱老熟| 精品香蕉一区二区三区| 亚洲精品一区| 日韩啊v在线| 免播放器亚洲一区| 少妇视频一区二区| 91精品国产综合久久久蜜臀粉嫩 | 疯狂欧美牲乱大交777| 天堂在线资源网| 日本久久精品视频| 精品99久久| 亚洲欧美日韩三级| 亚洲美女少妇撒尿| 亚洲欧美高清视频| 91精品国产高清| 女人av一区| 99国产精品久久久久久| 亚洲日本护士毛茸茸| 亚洲老妇色熟女老太| 7777kkkk成人观看| 奇米亚洲欧美| 黄色一级片免费播放| 亚洲一区二区三区中文字幕| 污视频在线免费观看| 国产精品99久久久久久白浆小说| 日韩欧美视频专区| 91性高潮久久久久久久| 亚洲第一福利一区| 国内在线精品| 99久久精品无码一区二区毛片| 亚洲一级网站| 日本理论中文字幕| 日韩一区二区在线观看视频| 97超碰免费在线| 日本一区二区不卡高清更新| 国产一区二区91| 国产欧美一区二区三区在线看蜜臂| 中文字幕欧美精品在线 | 久久久久久久久一区| 蜜臂av日日欢夜夜爽一区| 久久久久99精品成人片毛片| 亚洲毛片在线观看| 国色天香久久精品国产一区| 国产视频九色蝌蚪| 亚洲欧洲日产国码二区| 少妇一级淫片免费看| 国产有码在线一区二区视频| 尤物网精品视频| 又嫩又硬又黄又爽的视频| 亚洲国产成人精品久久| 国产精品99久久久久久董美香| 免费的av在线| 国产女同互慰高潮91漫画| 成人乱码一区二区三区| 国产精品女主播视频| 在线一区视频|