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

萬字長文+實戰(zhàn)案例+企業(yè)級項目+高性能熔斷限流組件:徹底吃透Sentinel,看這一篇就夠了??!

開發(fā) 項目管理
Sentinel能夠在高并發(fā)、大流量的場景下有效的對流量進(jìn)行管控,包括限流、熔斷、降級、系統(tǒng)負(fù)載保護(hù)等,為了讓小伙伴們更加清楚的了解Sentinel的功能和使用案例,今天就系統(tǒng)性的帶著大家以實戰(zhàn)的方式學(xué)習(xí)Sentinel的核心技術(shù)和配置規(guī)則。

Sentinel能夠在高并發(fā)、大流量的場景下有效的對流量進(jìn)行管控,包括限流、熔斷、降級、系統(tǒng)負(fù)載保護(hù)等,為了讓小伙伴們更加清楚的了解Sentinel的功能和使用案例,今天就系統(tǒng)性的帶著大家以實戰(zhàn)的方式學(xué)習(xí)Sentinel的核心技術(shù)和配置規(guī)則。

一、Sentinel核心功能

隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來越重要。Sentinel 以流量為切入點,從流量控制、熔斷降級、系統(tǒng)負(fù)載保護(hù)等多個維度保護(hù)服務(wù)的穩(wěn)定性。所以,Sentinel的核心功能包括:流量控制、熔斷降級、系統(tǒng)負(fù)載保護(hù)

1.1 流量控制

在高并發(fā)、大流量場景下,進(jìn)入系統(tǒng)的流量如果不加控制的話,系統(tǒng)就很有可能會被流量壓垮。所以,在流量正式進(jìn)入系統(tǒng)之前,需要對流量進(jìn)行控制,以便使流量均勻、可控的方式進(jìn)入系統(tǒng)。

Sentinel作為一個非常出色的容錯組件,能夠?qū)⒉豢煽氐牧髁拷?jīng)過處理轉(zhuǎn)化成均勻、可控的流量。

1.2 熔斷降級

如果檢測到系統(tǒng)中的某個調(diào)用鏈路中某個節(jié)點出現(xiàn)故障,比如請求超時、服務(wù)宕機(jī)或者異常比超出一定閾值時,就會對出現(xiàn)故障的節(jié)點的調(diào)用頻率進(jìn)行限制,甚至不調(diào)用出現(xiàn)故障的節(jié)點,讓請求能夠快速失敗并返回,以最大程度避免影響到其他節(jié)點的服務(wù)而導(dǎo)致系統(tǒng)的級聯(lián)故障。

Sentinel主要通過 限制并發(fā)線程數(shù)和響應(yīng)時間 對資源的訪問進(jìn)行降級。

1)限制并發(fā)線程數(shù)進(jìn)行降級

Sentinel可以通過限制服務(wù)節(jié)點的并發(fā)線程數(shù)量,來減少對其他服務(wù)節(jié)點的影響。例如,當(dāng)某個服務(wù)節(jié)點出現(xiàn)故障,例如響應(yīng)時間變長,或者直接宕機(jī)。此時,對服務(wù)的直接影響就是會造成請求線程數(shù)的不斷堆積。如果這些堆積的線程數(shù)達(dá)到一定的數(shù)量后,對當(dāng)前服務(wù)節(jié)點的后續(xù)請求就會被拒絕,等到堆積的線程完成任務(wù)后再開始繼續(xù)接收新的請求。

2)通過響應(yīng)時間進(jìn)行降級

Sentinel除了可以通過限制并發(fā)線程數(shù)進(jìn)行降級外,也能夠通過響應(yīng)時間進(jìn)行降級。如果依賴的服務(wù)出現(xiàn)響應(yīng)時間過長的情況,則所有對該服務(wù)的請求都會被拒絕,直到過了指定的時間窗口之后才能再次訪問該服務(wù)。

1.3 系統(tǒng)負(fù)載保護(hù)

Sentinel提供了系統(tǒng)維度的自適應(yīng)保護(hù)能力。當(dāng)系統(tǒng)的壓力和負(fù)載比較高的時候,如果還持續(xù)讓大量的請求進(jìn)入系統(tǒng),此時就有可能將系統(tǒng)壓垮,進(jìn)而導(dǎo)致系統(tǒng)宕機(jī)。Sentinel會在集群環(huán)境下,將本應(yīng)服務(wù)器A承載的流量轉(zhuǎn)發(fā)到其他服務(wù)器上,比如轉(zhuǎn)發(fā)到服務(wù)器B上。如果此時服務(wù)器B也處于高負(fù)載的狀態(tài),則Sentinel會提供相應(yīng)的保護(hù)機(jī)制,讓系統(tǒng)的入口流量和系統(tǒng)的整體負(fù)載達(dá)到平衡,讓系統(tǒng)整體可用,并且能夠最大限度的處理請求。

二、Sentinel核心規(guī)則

Sentinel的核心規(guī)則包括流控規(guī)則、熔斷規(guī)則、熱點規(guī)則、授權(quán)規(guī)則和系統(tǒng)規(guī)則,每種規(guī)則的配置方式不同。接下來,就詳細(xì)介紹下Sentinel中的每種規(guī)則的作用與效果。

圖片圖片

三、流控規(guī)則

Sentinel能夠?qū)α髁窟M(jìn)行控制,主要是監(jiān)控應(yīng)用的QPS流量或者并發(fā)線程數(shù)等指標(biāo),如果達(dá)到指定的閾值時,就會被流量進(jìn)行控制,以避免服務(wù)被瞬時的高并發(fā)流量擊垮,保證服務(wù)的高可靠性。

3.1 簇點鏈路規(guī)則

(1)點擊簇點鏈路菜單,可以看到之前訪問過的接口,如下所示。

圖片圖片

(2)點擊右側(cè)的流控按鈕,會彈出新增流控規(guī)則的提示框,如下所示。

圖片圖片

這里,每個配置項的說明如下所示。

  • 資源名:資源的唯一名稱,默認(rèn)就是請求的接口路徑,可以自行修改,但是要保證唯一。
  • 針對來源:具體針對某個微服務(wù)進(jìn)行限流,默認(rèn)值為default,表示不區(qū)分來源,全部限流。
  • 閾值類型:QPS表示通過QPS進(jìn)行限流,并發(fā)線程數(shù)表示通過并發(fā)線程數(shù)限流。
  • 單機(jī)閾值:與閾值類型組合使用。如果閾值類型選擇的是QPS,表示當(dāng)調(diào)用接口的QPS達(dá)到閾值時,進(jìn)行限流操作。如果閾值類型選擇的是并發(fā)線程數(shù),則表示當(dāng)調(diào)用接口的并發(fā)線程數(shù)達(dá)到閾值時,進(jìn)行限流操作。
  • 是否集群:選中則表示集群環(huán)境,不選中則表示非集群環(huán)境。

3.2 配置簡單限流

這里,針對http://localhost:8080/order/test_sentinel接口進(jìn)行簡單的配置,在新增流控規(guī)則里閾值類型選擇QPS,單機(jī)閾值輸入3,表示每秒鐘的請求量如果超過3,則會觸發(fā)Sentinel的限流操作。

圖片圖片

點擊新增按鈕后,會為http://localhost:8080/order/test_sentinel接口新增一條限流規(guī)則,如下所示。

圖片圖片

接下來,在瀏覽器上快速刷新http://localhost:8080/order/test_sentinel接口,當(dāng)每秒鐘的刷新頻率超過3次時,會出現(xiàn)如下所示的提示信息。

圖片圖片

3.3 配置流控模式

點擊http://localhost:8080/order/test_sentinel接口流控規(guī)則后面的編輯按鈕,打開編輯流控規(guī)則彈出框(如果是首次配置的話,就是新增流控規(guī)則彈出框),點擊高級選項配置。

圖片圖片

會顯示出如下所示的界面。

圖片圖片

可以看到,Sentinel主要提供了三種流控模式,分別為直接、關(guān)聯(lián)和鏈路。

  • 直接:默認(rèn)的流控模式,當(dāng)接口達(dá)到限流條件時,直接開啟限流功能。
  • 關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到限流條件時,開啟限流功能。
  • 鏈路:當(dāng)從某個接口請求過來的資源達(dá)到限流條件時,開啟限流功能。

演示直接流控模式

Sentinel默認(rèn)就是使用的直接流控模式,我們之前在訂單微服務(wù)中集成的就是Sentinel的直接流控模式,在本文的流控規(guī)則-配置簡單限流中,也是使用的直接流控模式,這里不再贅述。

演示關(guān)聯(lián)流控模式

(1)在訂單微服務(wù)的io.binghe.shop.order.controller.OrderController 類中新增 /test_sentinel2接口,如下所示。

@GetMapping(value = "/test_sentinel2")
public String testSentinel2(){
    log.info("測試Sentinel2");
    return "sentinel2";
}

(2)在瀏覽器上訪問下http://localhost:8080/order/test_sentinel2接口,以便使Sentinel檢測到http://localhost:8080/order/test_sentinel2接口。

圖片圖片

注意:如果想使用Sentinel對某個接口進(jìn)行限流和降級等操作,一定要先訪問下接口,使Sentinel檢測出相應(yīng)的接口,這里一定要注意,在后續(xù)的文章中,不再單獨說明。

(3)回到為http://localhost:8080/order/test_sentinel接口配置流控規(guī)則的頁面,如下所示。

圖片圖片

(4)在流控模式中選擇關(guān)聯(lián),在關(guān)聯(lián)資源中輸入/test_sentinel2,如下所示。

圖片圖片

點擊保存按鈕保存配置。

(5)打開JMeter,對http://localhost:8080/order/test_sentinel2接口進(jìn)行測試,使其每秒鐘的訪問次數(shù)大于3,JMeter的具體配置如下所示。

圖片圖片

在線程組中配置每秒訪問4次。

配置完畢后,使用JMeter開始訪問http://localhost:8080/order/test_sentinel2接口。

(6)在瀏覽器上刷新http://localhost:8080/order/test_sentinel接口,發(fā)現(xiàn)已經(jīng)觸發(fā)了Sentinel的限流功能。

圖片圖片

至此,關(guān)聯(lián)流控模式演示完畢。

演示鏈路流控模式

(1)在訂單微服務(wù)的io.binghe.shop.order.service包中新增SentinelService接口,用于測試流控模式,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試Sentinel
 */
public interface SentinelService {

    /**
     * 測試方法
     */
    void sendMessage();
}

(2)在訂單微服務(wù)的io.binghe.shop.order.service.impl包中新增SentinelServiceImpl類,實現(xiàn)SentinelService接口,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試類
 */
@Service
public class SentinelServiceImpl implements SentinelService {
    @Override
    @SentinelResource("sendMessage")
    public void sendMessage() {
        System.out.println("測試Sentinel的鏈路流控模式");
    }
}

這里,我們在sendMessage()方法上使用了@SentinelResource注解, @SentinelResource注解會在后續(xù)文章中介紹,這里不再贅述。

(3)在訂單微服務(wù)的io.binghe.shop.order.controller包下新建SentinelController類,用于測試接口,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試Sentinel
 */
@Slf4j
@RestController
publicclass SentinelController {

    @Autowired
    private SentinelService sentinelService;

    @GetMapping(value = "/request_sentinel1")
    public String requestSentinel1(){
        log.info("測試Sentinel1");
        sentinelService.sendMessage();
        return"sentinel1";
    }
    @GetMapping(value = "/request_sentinel2")
    public String requestSentinel2(){
        log.info("測試Sentinel2");
        sentinelService.sendMessage();
        return"sentinel2";
    }
}

(4)升級SpringCloud Alibaba的依賴版本到2.2.7.RELEASE,升級SpringCloud版本到Hoxton.SR12,并且加入SpringBoot的管理依賴。主要的修改的是shop-springcloud-alibaba父工程的pom.xml配置,修改后的配置文件如下所示。

<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
    <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
    <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
    <logback.version>1.1.7</logback.version>
    <slf4j.version>1.7.21</slf4j.version>
    <common.logging>1.2</common.logging>
    <fastjson.version>1.2.51</fastjson.version>
    <mybatis.version>3.4.6</mybatis.version>
    <mybatis.plus.version>3.4.1</mybatis.plus.version>
    <mysql.jdbc.version>8.0.19</mysql.jdbc.version>
    <druid.version>1.1.10</druid.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

(5)升級Nacos,將Nacos注冊中心由1.4.3版本升級為2.1.0版本,并進(jìn)入Nacos的bin目錄,輸入如下命令啟動Nacos。

startup.cmd -m standalone

(6)在訂單微服務(wù)的application.yml文件中新增鏈路配置,如下所示。

spring:
  cloud:
    sentinel:
      web-context-unify: false

(7)在瀏覽器中分別訪問http://localhost:8080/order/request_sentinel1http://localhost:8080/order/request_sentinel2,查看Sentinel中的簇點鏈路,如下所示。

(8)點擊sendMessage后面的流控按鈕,如下所示。

(9)在彈出的新增流控規(guī)則編輯框中閾值類型選擇QPS,單機(jī)閾值輸入3,在打開的高級選項中的流控模式選擇鏈路,入口資源輸入/request_sentinel1,如下所示。

圖片圖片

點擊新增按鈕保存配置,此時,如果是通過http://localhost:8080/order/request_sentinel1接口調(diào)用io.binghe.shop.order.service.SentinelService#sendMessage()方法時,如果調(diào)用的頻率每秒鐘超過3次,就會觸發(fā)Sentinel的限流操作,而通過http://localhost:8080/order/request_sentinel2接口調(diào)用io.binghe.shop.order.service.SentinelService#sendMessage()方法時,則不受限制。

(10)在瀏覽器中不斷訪問http://localhost:8080/order/request_sentinel1,使得每秒的訪問次數(shù)超過3,則會觸發(fā)Sentinel的限流操作,如下所示。

圖片圖片

訪問http://localhost:8080/order/request_sentinel2接口則不會被限流。

至此,鏈路流控模式演示完畢。

附加說明

在流控規(guī)則的高級選項中還有三個流控效果,如下所示。

接下來,就對這三個選項進(jìn)行簡單的說明。

  • 快速失敗:會直接失敗,拋出異常,期間不會做任何其他的處理操作。
  • Warm Up:從開始閾值到最大QPS閾值會有一個緩沖,可以設(shè)置一個預(yù)熱時長,這個選項比較適合突發(fā)瞬時高并發(fā)流量的場景,能夠?qū)⑼话l(fā)的高并發(fā)流量轉(zhuǎn)換為均勻、緩慢增長的場景。
  • 排隊等待:能夠使請求均勻的通過,單機(jī)的閾值為每秒通過的請求數(shù)量,其余的請求會排隊等待。另外,還會設(shè)置一個超時時間,當(dāng)請求超過超時時間未處理時,會被丟棄。

圖片圖片

四、熔斷規(guī)則

降級規(guī)則一般情況下,指的是滿足某些條件時,對服務(wù)進(jìn)行降級操作。

4.1 熔斷規(guī)則概述

Sentinel主要提供了三個熔斷策略,分別為:慢調(diào)用比例、異常比例和異常數(shù)。

圖片圖片

4.2 演示基于慢調(diào)用比例熔斷

(1)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel2,在Sentinel的簇點鏈路里找到/request_sentinel2

(2)點擊熔斷按鈕,進(jìn)入熔斷規(guī)則配置框,按照如下方式進(jìn)行配置。

上述配置表示最大響應(yīng)時長為1ms,比例閾值達(dá)到0.1時,會觸發(fā)熔斷操作,并且熔斷的時長為2,最小請求數(shù)未5,統(tǒng)計的時長為1000毫秒。

(3)點擊新增按鈕后,不斷在瀏覽器中刷新http://localhost:8080/order/request_sentinel2,會發(fā)現(xiàn)觸發(fā)了Sentinel的熔斷操作,如下所示。

4.3 演示基于異常比例熔斷

(1)在訂單微服務(wù)的io.binghe.shop.order.controller.SentinelController類中定義一個成員變量count,用來記錄訪問計數(shù),同時,新增一個requestSentinel4()方法用來測試基于異常比例的熔斷,如下所示。

private int count = 0;
@GetMapping(value = "/request_sentinel4")
@SentinelResource("request_sentinel4")
public String requestSentinel4(){
    log.info("測試Sentinel4");
    count++;
    //模擬異常,比例為50%
    if (count % 2 == 0){
        throw new RuntimeException("演示基于異常比例熔斷");
    }
    return "sentinel4";
}

(2)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel4,在Sentinel的簇點鏈路里找到/request_sentinel4。

(3)點擊熔斷按鈕,進(jìn)入熔斷規(guī)則配置框,按照如下方式進(jìn)行配置。

io.binghe.shop.order.controller.SentinelController#requestSentinel4()方法中,設(shè)置的異常比例為50%,這里在Sentinel的比例閾值中設(shè)置的異常比例為0.3,也就是30%,所以,在訪問http://localhost:8080/order/request_sentinel4接口時,會觸發(fā)Sentinel的熔斷操作。

(4)點擊新增按鈕后,不斷在瀏覽器中刷新http://localhost:8080/order/request_sentinel4,會發(fā)現(xiàn)觸發(fā)了Sentinel的熔斷操作,如下所示。

圖片圖片

4.4 演示基于異常數(shù)熔斷

(1)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel4,在Sentinel的簇點鏈路里找到/request_sentinel4。

圖片圖片

(2)點擊熔斷按鈕,進(jìn)入熔斷規(guī)則配置框,按照如下方式進(jìn)行配置。

上述配置表示,在1秒鐘內(nèi)最少請求2次,當(dāng)異常數(shù)大于1時,會觸發(fā)熔斷操作,熔斷的時長為5秒。

(3)點擊保存按鈕后,不斷在瀏覽器中刷新http://localhost:8080/order/request_sentinel4,會發(fā)現(xiàn)觸發(fā)了Sentinel的熔斷操作,如下所示。

五、熱點規(guī)則

Sentinel的熱點規(guī)則可以將流量規(guī)則控制到具體的參數(shù)上。

5.1 熱點規(guī)則概述

Sentinel的熱點規(guī)則可以根據(jù)具體的參數(shù)來控制流量規(guī)則,適用于根據(jù)不同參數(shù)進(jìn)行流量控制的場景。

5.2 演示熱點規(guī)則

(1)在訂單微服務(wù)的io.binghe.shop.order.controller.SentinelController類中新增requestSentinel3()方法,其中會帶有一個String類型的參數(shù)header和一個String類型的參數(shù)body,如下所示。

@GetMapping(value = "/request_sentinel3")
@SentinelResource("request_sentinel3")
public String requestSentinel3(String header, String body){
    log.info("測試Sentinel3");
    return "sentinel3";
}

(2)在瀏覽器中訪問http://localhost:8080/order/request_sentinel3接口,在Sentinel的簇點鏈路中會顯示/request_sentinel3接口,如下所示。

(3)點擊熱點按鈕,如下所示。

(4)在彈出的熱點規(guī)則配置框中的參數(shù)索引中輸入0,單機(jī)閾值輸入1,統(tǒng)計窗口時長輸入1,如下所示。

表示對requestSentinel3()方法的第一個參數(shù)header進(jìn)行限流,如果每秒鐘訪問的次數(shù)超過1次,則觸發(fā)限流。

(5)保存配置后,在瀏覽器中不斷訪問http://localhost:8080/order/request_sentinel3?header=header,當(dāng)每秒訪問的頻率超過1次時,會觸發(fā)Sentinel的限流操作,如下所示。

圖片

不斷訪問http://localhost:8080/order/request_sentinel3?body=body,則不會觸發(fā)限流操作。

圖片

5.3 演示熱點高級選項規(guī)則

(1)在彈出的熱點規(guī)則配置框中打開高級選項,在參數(shù)類型中選擇java.lang.String,因為在參數(shù)索引中輸入0,表示的是對header參數(shù)限流,而header參數(shù)是String類型的。在參數(shù)值里輸入header,也就是為參數(shù)名為header的參數(shù)賦值為字符串header。限流閾值為1,如下所示。

圖片圖片

(2)點擊添加按鈕后如下所示。

(3)點擊保存按鈕,在瀏覽器不斷刷新http://localhost:8080/order/request_sentinel3?header=header,會觸發(fā)Sentinel的限流操作。

六、授權(quán)規(guī)則

授權(quán)規(guī)則能夠根據(jù)調(diào)用來源判斷還否允許執(zhí)行本次請求。

6.1 授權(quán)規(guī)則概述

在某些場景下,需要根據(jù)調(diào)用接口的來源判斷是否允許執(zhí)行本次請求。此時就可以使用Sentinel提供的授權(quán)規(guī)則來實現(xiàn),Sentinel的授權(quán)規(guī)則能夠根據(jù)請求的來源判斷是否允許本次請求通過。

在Sentinel的授權(quán)規(guī)則中,提供了 白名單與黑名單 兩種授權(quán)類型。

6.2 演示授權(quán)規(guī)則

(1)在訂單微服務(wù)shop-order中新建io.binghe.shop.order.parser包,并創(chuàng)建MyRequestOriginParser類,實現(xiàn)com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser接口,用來處理請求的來源。代碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description Sentinel授權(quán)規(guī)則,用來處理請求的來源
 */
@Component
public class MyRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getParameter("serverName");
    }
}

(2)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel4,在Sentinel的簇點鏈路里找到/request_sentinel4。

(3)點擊授權(quán)按鈕,進(jìn)入授權(quán)規(guī)則配置框,按照如下方式進(jìn)行配置。

其中,流控應(yīng)用填寫的是test,授權(quán)類型為黑名單。這里要結(jié)合新建的MyRequestOriginParser類進(jìn)行理解,MyRequestOriginParser類的parseOrigin()方法如下所示。

public String parseOrigin(HttpServletRequest httpServletRequest) {
    return httpServletRequest.getParameter("serverName");
}

parseOrigin()方法中直接返回了從HttpServletRequest中獲取的serverName參數(shù),而在上圖中的流控應(yīng)用中輸出的是test,授權(quán)類型為黑名單。

所以,如果我們訪問http://localhost:8080/order/request_sentinel4?serverName=test的話,是處于黑名單的狀態(tài),無法訪問。

(4)點擊新增按鈕后,不斷在瀏覽器中刷新http://localhost:8080/order/request_sentinel4?serverName=test,會發(fā)現(xiàn)無法訪問,被Sentinel限流了。

圖片

七、系統(tǒng)規(guī)則

系統(tǒng)保護(hù)規(guī)則是從應(yīng)用級別的入口流量進(jìn)行控制,從單臺機(jī)器的總體 Load、 RT、入口 QPS 、 CPU使用率和線程數(shù)五個維度監(jiān)控應(yīng)用數(shù)據(jù),讓系統(tǒng)盡可能跑在最大吞吐量的同時保證系統(tǒng)整體的穩(wěn)定性。

7.1 系統(tǒng)規(guī)則概述

系統(tǒng)保護(hù)規(guī)則是應(yīng)用整體維度的,而不是資源維度的,并且僅對入口流量 (進(jìn)入應(yīng)用的流量) 生效。

  • Load(僅對 Linux/Unix-like 機(jī)器生效):當(dāng)系統(tǒng) load1 超過閾值,且系統(tǒng)當(dāng)前的并發(fā)線程數(shù)超過系統(tǒng)容量時才會觸發(fā)系統(tǒng)保護(hù)。系統(tǒng)容量由系統(tǒng)的 maxQps * minRt 計算得出。設(shè)定參考值一般是 CPU cores * 2.5。
  • RT:當(dāng)單臺機(jī)器上所有入口流量的平均 RT 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù),單位是毫秒。
  • 線程數(shù):當(dāng)單臺機(jī)器上所有入口流量的并發(fā)線程數(shù)達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)。
  • 入口 QPS:當(dāng)單臺機(jī)器上所有入口流量的 QPS 達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)。
  • CPU使用率:當(dāng)單臺機(jī)器上所有入口流量的 CPU使用率達(dá)到閾值即觸發(fā)系統(tǒng)保護(hù)

7.2 演示系統(tǒng)規(guī)則

(1)在訂單微服務(wù)中新建io.binghe.shop.order.handler包,并創(chuàng)建MyUrlBlockHandler類,實現(xiàn)com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler接口,用來捕獲系統(tǒng)級Sentinel異常,代碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 處理Sentinel系統(tǒng)規(guī)則,返回自定義異常
 */
@Component
publicclass MyUrlBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = null;
        if (e instanceof FlowException) {
            msg = "限流了";
        } elseif (e instanceof DegradeException) {
            msg = "降級了";
        } elseif (e instanceof ParamFlowException) {
            msg = "熱點參數(shù)限流";
        } elseif (e instanceof SystemBlockException) {
            msg = "系統(tǒng)規(guī)則(負(fù)載/...不滿足要求)";
        } elseif (e instanceof AuthorityException) {
            msg = "授權(quán)規(guī)則不通過";
        }
        // http狀態(tài)碼
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 500);
        jsonObject.put("codeMsg", msg);
        response.getWriter().write(jsonObject.toJSONString());
    }
}

(2)在訂單微服務(wù)的io.binghe.shop.order.controller.SentinelController類中新增requestSentinel5()方法,如下所示。

@GetMapping(value = "/request_sentinel5")
@SentinelResource("request_sentinel5")
public String requestSentinel5(){
    log.info("測試Sentinel5");
    return "sentinel5";
}

(3)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel5,在Sentinel的簇點鏈路里找到/request_sentinel5。

(4)點擊流控按鈕,進(jìn)入流控規(guī)則配置框,按照如下方式進(jìn)行配置。

(5)在瀏覽器中不斷刷新http://localhost:8080/order/request_sentinel5,會顯示如下信息。

返回的原始數(shù)據(jù)如下所示。

{"code":500,"codeMsg":"限流了"}

說明觸發(fā)了系統(tǒng)規(guī)則,捕獲到了Sentinel全局異常。

八、@SentinelResource注解

使用Sentinel時,可以使用@SentinelResource注解來指定異常處理策略。

8.1 @SentinelResource注解概述

在Sentinel中,指定發(fā)生異常時的處理策略非常簡單,只需要使用@SentinelResource注解即可,@SentinelResource注解的源碼如下所示。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public@interface SentinelResource {

//資源名稱
    String value() default "";
//entry類型,標(biāo)記流量的方向,取值IN/OUT,默認(rèn)是OUT
    EntryType entryType() default EntryType.OUT;
    int resourceType() default 0;
//處理BlockException的函數(shù)名稱,函數(shù)要求:
    //1. 必須是 public
    //2.返回類型 參數(shù)與原方法一致
    //3. 默認(rèn)需和原方法在同一個類中。若希望使用其他類的函數(shù),可配置
    //blockHandlerClass ,并指定blockHandlerClass里面的方法。
    String blockHandler() default "";

    //存放blockHandler的類,對應(yīng)的處理函數(shù)必須static修飾。
    Class<?>[] blockHandlerClass() default {};

    //用于在拋出異常的時候提供fallback處理邏輯。 fallback函數(shù)可以針對所
    //有類型的異常(除了 exceptionsToIgnore 里面排除掉的異常類型)進(jìn)行處理。函數(shù)要求:
    //1. 返回類型與原方法一致
    //2. 參數(shù)類型需要和原方法相匹配
    //3. 默認(rèn)需和原方法在同一個類中。若希望使用其他類的函數(shù),可配置fallbackClass ,并指定fallbackClass里面的方法。
    String fallback() default "";

    //存放fallback的類。對應(yīng)的處理函數(shù)必須static修飾。
    String defaultFallback() default "";

//用于通用的 fallback 邏輯。默認(rèn)fallback函數(shù)可以針對所有類型的異常進(jìn)
    //行處理。若同時配置了 fallback 和 defaultFallback,以fallback為準(zhǔn)。函數(shù)要求:
    //1. 返回類型與原方法一致
    //2. 方法參數(shù)列表為空,或者有一個 Throwable 類型的參數(shù)。
    //3. 默認(rèn)需要和原方法在同一個類中。若希望使用其他類的函數(shù),可配置fallbackClass ,并指定 fallbackClass 里面的方法。
    Class<?>[] fallbackClass() default {};

   //指定排除掉哪些異常。排除的異常不會計入異常統(tǒng)計,也不會進(jìn)入fallback邏輯,而是原樣拋出。
    Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
    
//需要trace的異常
    Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

8.2 演示@SentinelResource注解

1.定義限流和降級后的處理方法

(1)在訂單微服務(wù)的io.binghe.shop.order.service.SentinelService接口中新增sendMessage2()方法,如下所示。

String sendMessage2();

(2)在訂單微服務(wù)的io.binghe.shop.order.service.impl.SentinelServiceImpl方法中,實現(xiàn)sendMessage2()方法,并且定義一個成員變量count,用來記錄請求sendMessage2()方法的次數(shù),同時定義25%的異常率。在sendMessage2()方法上使用@SentinelResource指定了資源的名稱、發(fā)生BlockException時進(jìn)入的方法和發(fā)生異常時進(jìn)入的方法,代碼如下所示。

private int count = 0;

@Override
@SentinelResource(
    value = "sendMessage2",
    blockHandler = "blockHandler",
    fallback = "fallback")
public String sendMessage2() {
    count ++;
    //25%的異常率
    if (count % 4 == 0){
        thrownew RuntimeException("25%的異常率");
    }
    return"sendMessage2";
}

public String blockHandler(BlockException e){
    log.error("限流了:{}", e);
    return"限流了";
}

public String fallback(Throwable e){
    log.error("異常了:{}", e);
    return"異常了";
}

(3)在訂單微服務(wù)的io.binghe.shop.order.controller.SentinelController類中新增requestSentinel6()方法,在方法中調(diào)用io.binghe.shop.order.service.SentinelService接口中的sendMessage2()方法,如下所示。

@GetMapping(value = "/request_sentinel6")
public String requestSentinel6(){
    log.info("測試Sentinel6");
    return sentinelService.sendMessage2();
}

(4)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel6,在Sentinel的簇點鏈路里找到/request_sentinel6。

(5)點擊流控按鈕進(jìn)入流控規(guī)則頁面,按照下圖方式進(jìn)行配置。

(6)點擊新增按鈕后在瀏覽器中刷新http://localhost:8080/order/request_sentinel6,當(dāng)刷新的頻率超過每秒2次時,瀏覽器會顯示如下信息。

圖片

當(dāng)刷新的次數(shù)是4的倍數(shù)時,瀏覽器會顯示如下信息。

圖片

2.在外部類中指定限流和異常調(diào)用的方法

(1)在訂單微服務(wù)的io.binghe.shop.order.handler包下新建MyBlockHandlerClass類,用于定義被Sentinel限流時的方法,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 定義被Sentinel限流時調(diào)用的方法
 */
@Slf4j
public class MyBlockHandlerClass {

    public static String blockHandler(BlockException e){
        log.error("限流了:{}", e);
        return "限流了";
    }
}

(2)在訂單微服務(wù)的io.binghe.shop.order.handler包下新建MyFallbackClass類,用于定義拋出異常時調(diào)用的方法,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 定義異常時調(diào)用的方法
 */
@Slf4j
public class MyFallbackClass {

    public static String fallback(Throwable e){
        log.error("異常了:{}", e);
        return "異常了";
    }
}

(3)修改io.binghe.shop.order.service.impl.SentinelServiceImpl#sendMessage2()方法上的注解,修改后的代碼如下所示。

@Override
@SentinelResource(
    value = "sendMessage2",
    blockHandlerClass = MyBlockHandlerClass.class,
    blockHandler = "blockHandler",
    fallbackClass = MyFallbackClass.class,
    fallback = "fallback")
public String sendMessage2() {
    count ++;
    System.out.println(count);
    //25%的異常率
    if (count % 4 == 0){
        thrownew RuntimeException("25%的異常率");
    }
    return"sendMessage2";
}

(4)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel6,在Sentinel的簇點鏈路里找到/request_sentinel6。

圖片圖片

(5)點擊流控按鈕進(jìn)入流控規(guī)則頁面,按照下圖方式進(jìn)行配置。

圖片圖片

(6)點擊新增按鈕后在瀏覽器中刷新http://localhost:8080/order/request_sentinel6,當(dāng)刷新的頻率超過每秒2次時,瀏覽器會顯示如下信息。

圖片圖片

當(dāng)刷新的次數(shù)是4的倍數(shù)時,瀏覽器會顯示如下信息。

圖片圖片

九、Sentinel持久化

Sentinel中可以自定義配置的持久化來將Sentinel的配置規(guī)則持久化到服務(wù)器磁盤,使得重啟應(yīng)用或者Sentinel后,Sentinel的配置規(guī)則不丟失。

9.1 Sentinel持久化概述

細(xì)心的小伙伴會發(fā)現(xiàn),我們之前配置的Sentinel規(guī)則在程序重啟或者Sentinel重啟后就會消失不見,此時就需要我們重新配置。如果這發(fā)生在高并發(fā)、大流量的場景下是不可接受的。那有沒有什么辦法讓程序或Sentinel重啟后配置不丟失呢?其實,Sentinel中可以自定義配置的持久化來解決這個問題。

9.2 實現(xiàn)Sentinel的持久化

(1)在訂單微服務(wù)shop-order中新建io.binghe.shop.order.persistence包,并創(chuàng)建SentinelPersistenceRule類,實現(xiàn)com.alibaba.csp.sentinel.init.InitFunc接口,并在SentinelPersistenceRule類中獲取應(yīng)用的名稱,覆寫init()方法,源碼如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description Sentinel規(guī)則持久化
 */
publicclass SentinelPersistenceRule implements InitFunc {
    //實際可以從外部配置讀取
    private String appcationName = "server-order";
    @Override
    public void init() throws Exception {
        String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + appcationName;
        String flowRulePath = ruleDir + "/flow-rule.json";
        String degradeRulePath = ruleDir + "/degrade-rule.json";
        String systemRulePath = ruleDir + "/system-rule.json";
        String authorityRulePath = ruleDir + "/authority-rule.json";
        String paramFlowRulePath = ruleDir + "/param-flow-rule.json";

        this.mkdirIfNotExits(ruleDir);
        this.createFileIfNotExits(flowRulePath);
        this.createFileIfNotExits(degradeRulePath);
        this.createFileIfNotExits(systemRulePath);
        this.createFileIfNotExits(authorityRulePath);
        this.createFileIfNotExits(paramFlowRulePath);

        // 流控規(guī)則
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
                flowRulePath,
                flowRuleListParser
        );
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
                flowRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);

        // 降級規(guī)則
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
                degradeRulePath,
                degradeRuleListParser
        );
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
                degradeRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);

        // 系統(tǒng)規(guī)則
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
                systemRulePath,
                systemRuleListParser
        );
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
                systemRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);

        // 授權(quán)規(guī)則
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
                authorityRulePath,
                authorityRuleListParser
        );
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                authorityRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);

        // 熱點參數(shù)規(guī)則
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
                paramFlowRulePath,
                paramFlowRuleListParser
        );
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
                paramFlowRulePath,
                this::encodeJson
        );
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }

    private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<FlowRule>>() {
            }
    );
    private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<DegradeRule>>() {
            }
    );
    private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<SystemRule>>() {
            }
    );

    private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<AuthorityRule>>() {
            }
    );

    private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<ParamFlowRule>>() {
            }
    );

    private void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    private void createFileIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    private <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }
}

(2)在訂單微服務(wù)的resources目錄下新建META-INF目錄,并在META-INF目錄下新建services目錄,在services目錄下新建名稱為com.alibaba.csp.sentinel.init.InitFunc的文件,如下所示。

圖片圖片

(3)在com.alibaba.csp.sentinel.init.InitFunc文件中添加io.binghe.shop.order.persistence.SentinelPersistenceRule類的全類名,如下所示。

io.binghe.shop.order.persistence.SentinelPersistenceRule

圖片圖片

(4)首先在瀏覽器中訪問http://localhost:8080/order/request_sentinel6,在Sentinel的簇點鏈路里找到/request_sentinel6。

圖片圖片

(5)點擊流控按鈕進(jìn)入流控規(guī)則頁面,按照下圖方式進(jìn)行配置。

圖片圖片

(6)點擊新增按鈕,此時打開電腦的user.home目錄,我電腦的目錄為C:\Users\binghe,可以發(fā)現(xiàn)C:\Users\binghe目錄中多了一個sentinel-rules目錄。

圖片圖片

(7)打開sentinel-rules目錄,發(fā)現(xiàn)里面存在一個server-order目錄,如下所示。

圖片圖片

(8)打開server-order目錄后,會發(fā)現(xiàn)生成了Sentinel的配置文件,并持久化到了磁盤上,如下所示。

圖片圖片

(9)打開flow-rule.json文件,內(nèi)容如下所示。

[
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0,
            "clientOfflineTime": 2000,
            "fallbackToLocalWhenFail": true,
            "resourceTimeout": 2000,
            "resourceTimeoutStrategy": 0,
            "sampleCount": 10,
            "strategy": 0,
            "thresholdType": 0,
            "windowIntervalMs": 1000
        },
        "clusterMode": false,
        "controlBehavior": 0,
        "count": 2,
        "grade": 1,
        "limitApp": "default",
        "maxQueueingTimeMs": 500,
        "resource": "/request_sentinel6",
        "strategy": 0,
        "warmUpPeriodSec": 10
    }
]

可以看到,flow-rule.json文件中持久化了對于/request_sentinel6接口的配置。

至此,我們完成了Sentinel規(guī)則的持久化。

責(zé)任編輯:武曉燕 來源: 冰河技術(shù)
相關(guān)推薦

2021-10-18 11:58:56

負(fù)載均衡虛擬機(jī)

2021-06-04 07:27:24

sourcemap前端技術(shù)

2023-02-10 09:04:27

2022-06-20 09:01:23

Git插件項目

2020-02-18 16:20:03

Redis ANSI C語言日志型

2023-09-11 08:13:03

分布式跟蹤工具

2022-08-01 11:33:09

用戶分析標(biāo)簽策略

2021-04-08 07:37:39

隊列數(shù)據(jù)結(jié)構(gòu)算法

2019-08-13 15:36:57

限流算法令牌桶

2023-12-04 08:10:34

Spring循環(huán)依賴

2020-12-10 15:25:51

Docker容器工具

2017-12-07 15:34:57

數(shù)據(jù)庫MySQL優(yōu)化原理

2019-05-14 09:31:16

架構(gòu)整潔軟件編程范式

2023-10-17 08:15:28

API前后端分離

2020-07-03 08:21:57

Java集合框架

2025-08-07 04:10:00

光模塊AI網(wǎng)絡(luò)

2018-05-22 08:24:50

PythonPyMongoMongoDB

2024-09-23 08:00:00

消息隊列MQ分布式系統(tǒng)

2022-04-07 10:39:21

反射Java安全

2017-03-11 22:19:09

深度學(xué)習(xí)
點贊
收藏

51CTO技術(shù)棧公眾號

劲爆欧美第一页| 男人添女人下面免费视频| 日韩中文字幕综合| 日韩香蕉视频| 亚洲欧洲中文天堂| 久久撸在线视频| 久久免费电影| 91视频一区二区三区| 国产精品成人一区二区三区吃奶| 亚洲欧美精品久久| 高清一区二区三区| 91国产视频在线观看| 亚洲高潮无码久久| 亚洲欧美日韩成人在线| 国产综合久久久久久鬼色 | 欧美午夜在线一二页| 一区二区日本伦理| 偷拍25位美女撒尿视频在线观看| 久久国产精品99国产| 欧美成人在线免费视频| 欧美黄色一级生活片| 中文字幕区一区二区三| 欧美三区在线观看| 日韩av三级在线| 黄色视屏免费在线观看| 国产亚洲欧美日韩在线一区| 96成人在线视频| 中文字幕在线网站| 一区二区亚洲| 久久久精品国产网站| 90岁老太婆乱淫| 欧美大奶一区二区| 欧美精品日韩一本| 成人在线激情网| 精精国产xxxx视频在线野外| 亚洲欧美色图小说| 亚洲视频在线二区| 成人资源www网在线最新版| 高清成人在线观看| 91性高湖久久久久久久久_久久99| 天天干在线播放| 日韩午夜黄色| 午夜精品视频网站| 久久精品久久国产| 午夜久久黄色| 麻豆乱码国产一区二区三区| 网爆门在线观看| 日韩欧美中字| 色综合亚洲精品激情狠狠| 成人av影院在线| 97免费中文视频在线观看| 欧美精品videos极品| 亚洲电影影音先锋| 久久久精品亚洲| 最新av电影网站| 香蕉综合视频| 久久在线免费视频| 五月综合色婷婷| 88国产精品视频一区二区三区| 中文精品99久久国产香蕉| 中文字幕网站在线观看| 久久99国产成人小视频| 国产婷婷成人久久av免费高清 | av在线不卡电影| 国产精品一区二区在线观看| 欧美一级一区二区三区| 成人毛片在线观看| 国内不卡一区二区三区| 深夜影院在线观看| 久久久久国产免费免费| 特级西西444www大精品视频| 亚洲精品传媒| 亚洲卡通动漫在线| 欧美精品卡一卡二| 中文字幕乱码中文乱码51精品| 欧美特黄级在线| 熟女少妇在线视频播放| 日韩免费福利视频| 欧美丝袜丝nylons| 91香蕉国产线在线观看| 国产suv精品一区| 亚洲人成网站色ww在线| www.日本高清视频| 欧美精品色网| 欧洲精品在线视频| 一级黄色大片免费观看| 狠狠色伊人亚洲综合成人| av激情久久| 美女做暖暖视频免费在线观看全部网址91| 国产日韩欧美在线一区| 美女在线免费视频| 国产伦理精品| 欧美日韩综合一区| 久久久久国产免费| 久久99青青| 欧美成人自拍视频| 色av性av丰满av| 国产一区二区三区四| 精品不卡在线| 黄色网页在线免费看| 精品久久久久久久久久久久久久| 午夜久久久精品| 国产精品45p| 最新的欧美黄色| 日本一级黄色录像| 久久精品国产网站| 欧美精品一区二区三区在线四季| 免费观看在线午夜影视| 午夜精品久久久| 制服丝袜中文字幕第一页| 女仆av观看一区| 俺也去精品视频在线观看| 国产一级免费av| 久久精品国产免费看久久精品| 激情欧美一区二区三区中文字幕| 免费黄色在线看| 色狠狠一区二区| 老司机午夜免费福利| 97久久视频| 热久久这里只有| 国精品人妻无码一区二区三区喝尿| 国产欧美一区二区精品忘忧草 | 亚洲国产精品小视频| 99热6这里只有精品| 亚洲伊人网站| 国产麻豆日韩| jizz性欧美10| 在线播放91灌醉迷j高跟美女| 久久精品老司机| 亚洲三级观看| 国产精品初高中精品久久| 久久日韩视频| 欧美中文字幕一区| 亚洲黄色在线网站| 亚洲国产影院| 国产精品久久精品国产| 中文字幕有码在线视频| 欧美日韩免费观看一区三区| 在线观看国产精品一区| 国产视频久久| 久久大片网站| 男人天堂视频在线观看| 亚洲成av人乱码色午夜| 久久免费黄色网址| 国产成人免费视频一区| 国产精品8888| 视频免费一区二区| 欧美人与物videos| 性做久久久久久久| 亚洲激情自拍偷拍| 韩国黄色一级片| 欧美视频导航| 国产高清精品一区二区| 白白色在线观看| 亚洲第一视频在线观看| 国产成人无码一区二区三区在线| 成人综合在线网站| 久操网在线观看| 色婷婷久久久| 久久精选视频| 91黄色8090| 黄色在线播放| 欧美亚洲一区二区三区四区| 日韩影视一区二区三区| 久久成人18免费观看| 99热一区二区三区| 99久久香蕉| 97色在线视频| 国产福利小视频在线| 欧美视频中文字幕| 亚洲二区在线播放| 国产精品 欧美精品| www.av毛片| 美女精品一区最新中文字幕一区二区三区 | 国产精品综合| 日本视频一区在线观看| 欧美hd在线| 97av在线视频| 久久手机免费观看| 欧美性生活大片视频| 色www亚洲国产阿娇yao| 久热成人在线视频| 伊人久久在线观看| 国产suv精品一区| 日本a级片电影一区二区| 九色网友自拍视频手机在线| 欧美日韩一级片在线观看| 国产91在线播放九色| 国产高清成人在线| 日本www在线播放| 久久社区一区| 激情小说综合网| 国产精品成人国产| 欧美激情一级欧美精品| 可以直接在线观看的av| 9191久久久久久久久久久| 国产午夜免费视频| 国产女同互慰高潮91漫画| 亚洲男人天堂2021| 午夜亚洲一区| 亚洲自拍偷拍一区二区三区| 日韩大胆成人| 91在线精品播放| 日韩免费电影| 午夜精品久久久久久久白皮肤| 99青草视频在线播放视| 精品av久久707| 啪啪小视频网站| 亚洲国产色一区| 国产三级精品三级观看| www.99精品| 精产国品一区二区三区| 日韩激情视频在线观看| av日韩一区二区三区| 我不卡影院28| 涩涩涩999| 天堂综合网久久| 日本麻豆一区二区三区视频| 91日本在线视频| 天堂久久午夜av| 26uuu久久噜噜噜噜| 中文av资源在线| 色青青草原桃花久久综合 | 国产麻豆精品95视频| 日韩在线视频在线观看| 欧美日韩岛国| 一区二区三区日韩视频| 欧美自拍偷拍| 欧美连裤袜在线视频| 红杏一区二区三区| 99国产在线观看| 91精品国产一区二区在线观看 | 亚洲资源网你懂的| 狠狠色噜噜狠狠色综合久| 日本在线一区二区三区| 国产一区欧美二区三区| 国产成人精品亚洲日本在线观看| 97超级碰碰碰久久久| 免费网站在线观看人| 欧美成年人视频| 成视频免费观看在线看| 久久久av免费| 免费人成在线观看播放视频| 最近2019中文字幕一页二页| 波多野结衣在线网站| 亚洲男女性事视频| 女人天堂在线| 国产亚洲精品高潮| 成人在线观看网站| 伊人久久久久久久久久久久久| 玖玖综合伊人| 伊人成人开心激情综合网| 91精彩在线视频| 日韩在线视频观看正片免费网站| av电影在线网| 日韩视频免费在线观看| 91精品大全| 欧美久久精品午夜青青大伊人| av免费网站在线观看| 欧美成人激情在线| 麻豆福利在线观看| 欧美一级电影免费在线观看| www.日韩| 国产精品久久久久影院日本| 国产精品成人国产| 99精品国产高清一区二区| 精品日产乱码久久久久久仙踪林| 久久精品日韩| 精品国产1区| 欧美 日韩 国产 在线观看 | 欧美激情欧美狂野欧美精品| 2018av在线| 日韩免费不卡av| 青青青国产精品| 动漫一区二区在线| 台湾色综合娱乐中文网| 亚洲一区二区三区精品视频| 欧美激情91| 色综合久久久久无码专区| 免费欧美日韩国产三级电影| 国产黑丝在线视频| av电影在线观看完整版一区二区| 亚洲最大成人网站| 亚洲欧洲色图综合| 国产无遮挡裸体免费视频| 色综合久久久久久久久久久| 一级片免费网站| 亚洲国产精品99| 在线免费观看的av网站| 久久久久久国产精品三级玉女聊斋| 波多野结衣亚洲| 91在线免费观看网站| 日韩精品免费一区二区三区竹菊| 亚洲一区二区三区精品动漫| 99在线|亚洲一区二区| 奇米影视四色在线| hitomi一区二区三区精品| 一级二级黄色片| 亚洲成人激情av| 国产一区二区三区四区视频| 亚洲精品久久久久中文字幕二区| av在线免费播放网站| 欧美精品激情在线观看| 日韩欧美一区二区三区免费观看| 99久久精品久久久久久ai换脸| 国产日产精品一区二区三区四区的观看方式| 一区国产精品| 久久国产精品久久w女人spa| 欧美日韩一区二区区别是什么| 国产喷白浆一区二区三区| 精品少妇久久久| 欧美精品777| 黄色毛片在线看| 久久久久一本一区二区青青蜜月| 国内精品伊人| 日本精品国语自产拍在线观看| 国产一区日韩一区| 999在线观看| 久久久综合激的五月天| 久久视频免费看| 这里只有精品99re| 成人午夜电影在线观看| 97视频人免费观看| 99ri日韩精品视频| 青青在线免费视频| 久久99在线观看| 天堂在线中文视频| 91久久精品一区二区| 日韩av资源站| 91av在线看| 欧美日韩直播| 国自产拍偷拍精品啪啪一区二区| 国产黄色成人av| 国产女人被狂躁到高潮小说| 欧美日韩在线播放一区| 精品久久av| 国产a∨精品一区二区三区不卡| 欧美美女啪啪| 欧美啪啪免费视频| 成人中文字幕合集| 精品午夜福利在线观看| 日韩精品影音先锋| 午夜在线激情影院| 999国产视频| 欧美日韩第一区| 国产原创剧情av| 午夜精品久久久久久久99水蜜桃| 婷婷av一区二区三区| 91禁外国网站| 日韩影视在线观看| 日本xxxxxxx免费视频| 国产欧美日韩精品一区| 日本三级一区二区三区| 一区二区av在线| 国产人妖一区| 日韩最新中文字幕| 国产高清精品在线| 91午夜视频在线观看| 亚洲精选一区二区| 欧美黑人巨大xxxxx| 少妇特黄a一区二区三区| 麻豆精品新av中文字幕| 婷婷社区五月天| 91精品国产乱| 97在线超碰| 日本一区二区高清视频| 六月丁香婷婷久久| 小泽玛利亚一区二区免费| 日韩欧美久久一区| 看黄在线观看| 日韩精品伦理第一区| 裸体在线国模精品偷拍| 国产探花在线免费观看| 精品久久久久久综合日本欧美| 麻豆国产在线| 视频一区在线免费观看| 韩国精品久久久| 日韩欧美亚洲视频| 亚洲一区www| 精品视频在线观看网站| 欧美日韩在线一| 国产精品美女一区二区| www.黄色片| 欧美在线精品免播放器视频| 久久福利影院| 色综合久久五月| 欧美日韩视频在线观看一区二区三区 | www日韩视频| 亚洲黄色免费电影| 日韩私人影院| 成人写真福利网| 国产欧美二区| 国产美女福利视频| 日韩www在线| 国产精品毛片aⅴ一区二区三区| 免费一级特黄毛片| 国产精品国产三级国产aⅴ原创| 欧日韩在线视频| 国产欧美日韩免费看aⅴ视频| 黄色工厂这里只有精品|