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

一口氣搞懂分庫分表 12 種分片算法,大廠都在用

開發 前端
本文中我們講解了ShardingSphere-jdbc所支持的12種分片算法,每種算法都具有獨特的特點。在實際應用中,需要結合具體的業務場景來靈活選擇和應用適合的分片算法。

前言

本文是《ShardingSphere5.x分庫分表原理與實戰》系列的第五篇文章,我們一起梳理下ShardingSphere框架中的核心部分分片策略和分片算法,其內部針為我們提供了多種分片策略和分片算法,來應對不同的業務場景,本著拿來即用的原則。

這次將詳細介紹如何在ShardingSphere-jdbc中實戰 5 種分片策略和 12 種分片算法,自定義分片算法,比較它們的應用場景以及優劣。

圖片圖片

全部demo案例 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-algorithms

分片策略

分片策略是分片鍵和分片算法的組合策略,真正用于實現數據分片操作的是分片鍵與相應的分片算法。在分片策略中,分片鍵確定了數據的拆分依據,分片算法則決定了如何對分片鍵值運算,將數據路由到哪個物理分片中。

由于分片算法的獨立性,使得分片策略具有更大的靈活性和可擴展性。這意味著可以根據具體需求選擇不同的分片算法,或者開發自定義的分片算法,以適應各種不同的分片場景。在分表和分庫時使用分片策略和分片算法的方式是一致的。

注意:如果在某種分片策略中使用了不受支持的SQL操作符,比如 MYSQL 某些函數等,那么系統將無視分片策略,進行全庫表路由操作。這個在使用時要慎重!

ShardingSphere對外提供了standard、complex、hint、inline、none5種分片策略。不同的分片策略可以搭配使用不同的分片算法,這樣可以靈活的應對復雜業務場景。

標準分片策略

標準分片策略(standard)適用于具有單一分片鍵的標準分片場景。該策略支持精確分片,即在SQL中包含=、in操作符,以及范圍分片,包括BETWEEN AND、>、<、>=、<=等范圍操作符。

該策略下有兩個屬性,分片字段shardingColumn和分片算法名shardingAlgorithmName。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 邏輯表名稱
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分庫策略
            databaseStrategy: # 分庫策略
              standard: # 用于單分片鍵的標準分片場景
                shardingColumn: order_id # 分片列名稱
                shardingAlgorithmName: # 分片算法名稱
           tableStrategy: # 分表策略,同分庫策略

行表達式分片策略

行表達式分片策略(inline)適用于具有單一分片鍵的簡單分片場景,支持SQL語句中=和in操作符。

它的配置相當簡潔,該分片策略支持在配置屬性algorithm-expression中書寫Groovy表達式,用來定義對分片健的運算邏輯,無需單獨定義分片算法了。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 邏輯表名稱
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分庫策略
            databaseStrategy: # 分庫策略
              inline:   # 行表達式類型分片策略
                algorithm-expression: db$->{order_id % 2} Groovy表達式
            tableStrategy: # 分表策略,同分庫策略

復合分片策略

復合分片策略(complex)適用于多個分片鍵的復雜分片場景,屬性shardingColumns中多個分片健以逗號分隔。支持 SQL 語句中有>、>=、<=、<、=、IN 和 BETWEEN AND 等操作符。

比如:我們希望通過user_id和order_id等多個字段共同運算得出數據路由到具體哪個分片中,就可以應用該策略。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 邏輯表名稱
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分庫策略
            databaseStrategy: # 分庫策略
              complex: # 用于多分片鍵的復合分片場景
                shardingColumns: order_id,user_id # 分片列名稱,多個列以逗號分隔
                shardingAlgorithmName: # 分片算法名稱
            tableStrategy: # 分表策略,同分庫策略

Hint分片策略

Hint強制分片策略相比于其他幾種分片策略稍有不同,該策略無需配置分片健,由外部指定分庫和分表的信息,可以讓SQL在指定的分庫、分表中執行。

使用場景:

  • 分片字段不存在SQL和數據庫表結構中,而存在于外部業務邏輯。
  • 強制在指定數據庫進行某些數據操作。

比如,我們希望用user_id做分片健進行路由訂單數據,但是t_order表中也沒user_id這個字段啊,這時可以通過Hint API手動指定分片庫、表等信息,強制讓數據插入指定的位置。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 邏輯表名稱
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分庫策略
            databaseStrategy: # 分庫策略
              hint: # Hint 分片策略
                shardingAlgorithmName: # 分片算法名稱
            tableStrategy: # 分表策略,同分庫策略

不分片策略

不分片策略比較好理解,設置了不分片策略,那么對邏輯表的所有操作將會執行全庫表路由。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 邏輯表名稱
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分庫策略
            databaseStrategy: # 分庫策略
              none: # 不分片
           tableStrategy: # 分表策略,同分庫策略

分片算法

ShardingSphere 內置了多種分片算法,按照類型可以劃分為自動分片算法、標準分片算法、復合分片算法和 Hint 分片算法,能夠滿足我們絕大多數業務場景的需求。

此外,考慮到業務場景的復雜性,內置算法也提供了自定義分片算法的方式,我們可以通過編寫 Java代碼來完成復雜的分片邏輯。下邊逐個算法實踐一下,看看每種算法的實際執行效果。

開始前,我要吐槽下官方文檔,對于算法這種至關重要的內容,解釋描述的過于潦草,對于新手入門不友好,學習成本偏高啊

準備工作

給邏輯表配置完算法后,先執行創建表的SQL,這樣就可以依據你的算法在db內快速生成分片表,所以不要總是問我要表結構了,哈哈哈。如果有不明白的小伙伴可以看我上一篇對于autoTable的介紹 分庫分表如何管理不同實例中幾萬張分片表?。

自動分片算法

1、MOD

取模分片算法是內置的一種比較簡單的算法,定義算法時類型MOD,表達式大致(分片健/數據庫實例) % sharding-count,它只有一個 props 屬性sharding-count代表分片表的數量。

圖片圖片

這個 sharding-count 數量使用時有點小坑,比如db0和db1都有分片表t_order_1,那么實際上數量只能算一個。YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自動分片表規則配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_mod
        # 分片算法定義
        sharding-algorithms:
          t_order_table_mod:
            type: MOD # 取模分片算法
            props:
              # 指定分片數量
              sharding-count: 6
        tables:
          t_order: # 邏輯表名稱
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_mod

2、HASH_MOD

哈希取模分片算法是內置取模分片算法的一個升級版本,定義算法時類型HASH_MOD,也只有一個props屬性sharding-count代表分片的數量。表達式hash(分片健/數據庫實例) % sharding-count。

圖片圖片

YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自動分片表規則配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_hash_mod
        # 分片算法定義
        sharding-algorithms:
          t_order_table_hash_mod:
            type: HASH_MOD # 哈希取模分片算法
            props:
              # 指定分片數量
              sharding-count: 6
        tables:
          t_order: # 邏輯表名稱
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_hash_mod

3、VOLUME_RANGE

基于分片容量的范圍分片算法,依據數據容量來均勻分布到分片表中。

它適用于數據增長趨勢相對均勻,按分片容量將數據均勻地分布到不同的分片表中,可以有效避免數據傾斜問題;由于數據已經被按照范圍進行分片,支持頻繁進行范圍查詢場景。

不僅如此,該算法支持動態的分片調整,可以根據實際業務數據的變化動態調整分片容量和范圍,使得系統具備更好的擴展性和靈活性。

VOLUME_RANGE算法主要有三個屬性:

圖片圖片

看完是不是一臉懵逼,上界下界都是什么含義,我們實際使用一下就清晰了。為t_order邏輯表設置VOLUME_RANGE分片算法,range-lower下界數為 2,range-upper上界數為 20,分量容量sharding-volume 10。

yml核心配置如下:

# 分片算法定義
spring:
  shardingsphere:
    rules:
      sharding:
        # 自動分片表規則配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_volume_range
        sharding-algorithms:
          t_order_table_volume_range:
            type: VOLUME_RANGE
            props:
              range-lower: 2 # 范圍下界,超過邊界的數據會報錯
              range-upper: 20 # 范圍上界,超過邊界的數據會報錯
              sharding-volume: 10 # 分片容量
        tables:
          t_order: # 邏輯表名稱
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_volume_range

這個配置的意思就是說,分片健t_order_id的值在界值 [range-lower,range-upper) 范圍內,每個分片表最大存儲 10 條數據;低于下界的值 [ 1,2 ) 數據分布到 t_order_0,在界值范圍內的數據 [ 2,20 ) 遵循每滿足 10 條依次放入 t_order_1、t_order_2;超出上界的數據[ 20,∞ ) 即便前邊的分片表里未滿 10條剩下的也全部放在 t_order_3。

那么它的數據分布應該如下:

  • [ 0,2 )數據分布到 t_order_0
  • [ 2,12 )數據分布到 t_order_1
  • [ 12,20 )數據分布到 t_order_2
  • [ 20,∞ )數據分布到 t_order_3

基于分片容量的范圍分片算法基于分片容量的范圍分片算法

接著準備插入40條數據,其中分片健字段t_order_id值從1~40,我們看到實際插入庫的數據和上邊配置的規則是一致的。超出range-lower、range-upper邊界的部分數據,比如:t_order_2表未滿 10條也不再插入,全部放入了t_order_3分片表中。

圖片圖片

4、BOUNDARY_RANGE

基于分片邊界的范圍分片算法,和分片容量算法不同,這個算法根據數據的取值范圍進行分片,特別適合按數值范圍頻繁查詢的場景。該算法只有一個屬性sharding-ranges為分片健值的范圍區間。

圖片圖片

比如,我們配置sharding-ranges=10,20,30,40,它的范圍默認是從 0開始,范圍區間前閉后開。配置算法以后執行建表語句,生成數據節點分布如:

db0-
   |_t_order_0
   |_t_order_2
   |_t_order_4
db1-
   |_t_order_1
   |_t_order_3

那么它的數據分布應該如下:

[ 0,10 )數據分布到t_order_0,

[ 10,20 )數據分布到t_order_1,

[ 20,30 )數據分布到t_order_2,

[ 30,40 )數據分布到t_order_3,

[ 40,∞ )數據分布到t_order_4。

基于分片邊界的范圍分片算法基于分片邊界的范圍分片算法

BOUNDARY_RANGE算法的YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自動分片表規則配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_boundary_range
        sharding-algorithms:
          # 基于分片邊界的范圍分片算法
          t_order_table_boundary_range:
            type: BOUNDARY_RANGE
            props:
              sharding-ranges: 10,20,30,40 # 分片的范圍邊界,多個范圍邊界以逗號分隔
        tables:
          t_order: # 邏輯表名稱
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_boundary_range

也插入40條數據,其中分片健字段t_order_id值從1~40,和上邊分析的數據分布結果大致相同??吹降谝粡埛制碇?t_order_0 只有 9 條數據,這是因為咱們插入數據的分片健值是從 1 開始,但算法是從 0 開始計算。

圖片圖片

5、AUTO_INTERVAL

自動時間段分片算法,適用于以時間字段作為分片健的分片場景,和VOLUME_RANGE基于容量的分片算法用法有點類似,不同的是AUTO_INTERVAL依據時間段進行分片。主要有三個屬性datetime-lower分片健值開始時間(下界)、datetime-upper分片健值結束時間(上界)、sharding-seconds單一分片表所能容納的時間段。

圖片圖片

這里分片健已經從t_order_id替換成了order_date?,F在屬性 datetime-lower 設為 2023-01-01 00:00:00,datetime-upper 設為 2025-01-01 00:00:00,sharding-seconds為 31536000 秒(一年)。策略配置上有些改動,將分庫和分表的算法全替換成AUTO_INTERVAL。

YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自動分片表規則配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_auto_interval
        # 分片算法定義
        sharding-algorithms:
          # 自動時間段分片算法
          t_order_table_auto_interval:
            type: AUTO_INTERVAL
            props:
              datetime-lower: '2023-01-01 00:00:00' # 分片的起始時間范圍,時間戳格式:yyyy-MM-dd HH:mm:ss
              datetime-upper: '2025-01-01 00:00:00' #  分片的結束時間范圍,時間戳格式:yyyy-MM-dd HH:mm:ss
              sharding-seconds: 31536000 # 單一分片所能承載的最大時間,單位:秒,允許分片鍵的時間戳格式的秒帶有時間精度,但秒后的時間精度會被自動抹去
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_auto_interval
            # 分表策略
#            table-strategy:
#              standard:
#                sharding-column: order_date
#                sharding-algorithm-name: t_order_table_auto_interval

只要你理解了上邊 VOLUME_RANGE 算法的數據分布規則,那么這個算法也很容易明白,分片健值在界值范圍內 [datetime-lower,datetime-upper) 遵循每滿足 sharding-seconds 時間段的數據放入對應分片表,超出界值的數據上下順延到其他分片中。

它的數據分布應該如下:

  • [ 2023-01-01 00:00:00,2024-01-01 00:00:00 )數據分布到 t_order_0,
  • [ 2024-01-01 00:00:00,2025-01-01 00:00:00 )數據分布到 t_order_1,
  • [ 2025-01-01 00:00:00,2026-01-01 00:00:00 )數據分布到 t_order_2。
  • [ 2026-01-01 00:00:00,∞ )數據分布到 t_order_3。

為了方便測試,手動執行插入不同日期的數據,按照上邊配置的規則應該t_order_0會有一條 23 年的數據,t_order_1 中有兩條 24 年的數據,t_order_2 中有兩條 25 年的數據,t_order_3 中有兩條 26、27 年的數據。

// 放入 t_order_0 分片表
INSERT INTO `t_order` VALUES (1, '2023-03-20 00:00:00', 1, '1', 1, 1.00);
// 放入 t_order_1 分片表
INSERT INTO `t_order` VALUES (2, '2024-03-20 00:00:00', 2, '2', 2,1.00);
INSERT INTO `t_order` VALUES (3, '2024-03-20 00:00:00', 3, '3', 3, 1.00);
// 放入 t_order_2 分片表
INSERT INTO `t_order` VALUES (4,'2025-03-20 00:00:00',4, '4', 4, 1.00);
INSERT INTO `t_order` VALUES (5,'2025-03-20 00:00:00',5, '5', 5,  1.00);
// 放入 t_order_3 分片表
INSERT INTO `t_order` VALUES (6,'2026-03-20 00:00:00',6, '6', 6,  1.00);
INSERT INTO `t_order` VALUES (7,'2027-03-20 11:19:58',7, '7', 7,  1.00);

查看實際的數據分布情況和預想的結果完全一致,至此內置算法全部使用大成。

標準分片算法

6、INLINE

行表達式分片算法,適用于比較簡單的分片場景,利用Groovy表達式在算法屬性內,直接書寫分片邏輯,省卻了配置和代碼開發,只支持SQL語句中的 = 和 IN 的分片操作,只支持單分片鍵。

圖片圖片

該算法有兩屬性:

  • algorithm-expression:編寫Groovy的表達式,比如: t_order_$->{t_order_id % 3} 表示根據分片健 t_order_id 取模獲得 3 張 t_order 分片表 t_order_0 到 t_order_2。
  • allow-range-query-with-inline-sharding:由于該算法只支持含有 = 和 IN 操作符的SQL,一旦SQL使用了范圍查詢 >、< 等操作會報錯。要想執行范圍查詢成功,該屬性開啟為true即可,一旦開啟范圍查詢會無視分片策略,進行全庫表路由查詢,這個要慎重開啟!

YML核心配置如下:

spring:
  shardingsphere:
    # 具體規則配置
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          # 標準分片算法
          # 行表達式分片算法
          t_order_table_inline:
            type: INLINE
            props:
              algorithm-expression: t_order_$->{order_id % 3} # 分片算法的行表達式
              allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_algorithms
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_inline

7、INTERVAL

時間范圍分片算法,針對于時間字段(字符串類型)作為分片健的范圍分片算法,適用于按照天、月、年這種固定區間的數據分片。 上邊使用其它時間分片算法時,用的都是t_order_n后綴編號格式的分片表。但業務上往往需要的可能是按月、年t_order_yyyyMM的這種分片表格式。

時間范圍分片算法(INTERVAL),可以輕松實現這種場景,它的屬性比較多,逐個解釋下:

圖片圖片

  • datetime-pattern:分片健值的時間格式,必須是Java DateTimeFormatter類支持的轉換類型
  • datetime-lower:分片健值的下界,超過會報錯,格式必須與datetime-pattern一致
  • datetime-upper:分片健值的上界,超過會報錯,格式必須與datetime-pattern一致
  • sharding-suffix-pattern:分片表后綴名格式,yyyyMM、yyyyMMdd等格式,分片表格式的定義要結合datetime-interval-unit的單位,比如:t_order_yyyyMM格式表示分片表存的月的數據,t_order_yyyy格式表示分片表存的年的數據;
  • datetime-interval-unit:分片間隔單位,超過該時間間隔將進入下一分片。它遵循 Java ChronoUnit 枚舉,比如:MONTHS、DAYS等;
  • datetime-interval-amount:分片間隔數,和datetime-interval-unit是緊密配合使用;

接下來實現個按月存儲數據的場景,用t_order_202401~t_order_202406 6張分片表存儲前半年的數據,每張分片表存儲一個月的數據。interval_value字段作為分片健,時間字符串類型,允許的分片值時間范圍 2024-01-01 00:00:00~2024-06-30 23:59:59 不在范圍內插入報錯。

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片數量
          t_order_table_interval:
            type: INTERVAL
            props:
              datetime-pattern: "yyyy-MM-dd HH:mm:ss"  # 分片字段格式
              datetime-lower: "2024-01-01 00:00:00"  # 范圍下限
              datetime-upper: "2024-06-30 23:59:59"  # 范圍上限
              sharding-suffix-pattern: "yyyyMM"  # 分片名后綴,可以是MM,yyyyMMdd等。
              datetime-interval-amount: 1  # 分片間隔,這里指一個月
              datetime-interval-unit: "MONTHS" # 分片間隔單位
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202406}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_interval
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

配置完成后插入測試數據 1月~7月,正常情況下前 6 個月的數據會正常插入,超過界值的 7月數據應該會報錯。

// 放入 t_order_202401 分片表
INSERT INTO `t_order` VALUES (1, 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);
// 放入 t_order_202402 分片表
INSERT INTO `t_order` VALUES (2, 2, '2', 2, 1.00, '2024-02-01 00:00:00', 1);
// 放入 t_order_202403 分片表
INSERT INTO `t_order` VALUES (3, 3, '3', 3, 1.00, '2024-03-01 00:00:00', 1);
// 放入 t_order_202404 分片表
INSERT INTO `t_order` VALUES (4, 4, '4', 4, 1.00, '2024-04-01 00:00:00', 1);
// 放入 t_order_202405 分片表
INSERT INTO `t_order` VALUES (5, 5, '5', 5, 1.00, '2024-05-01 00:00:00', 1);
// 放入 t_order_202406 分片表
INSERT INTO `t_order` VALUES (6, 6, '6', 6, 1.00, '2024-06-01 00:00:00', 1);

// 插入會報錯
INSERT INTO `t_order` VALUES (7, 7, '7', 7, 1.00, '2024-07-01 00:00:00', 1);

看到實際的入庫的效果和預期的一致,一月的數據存到t_order_202401,二月的數據存到t_order_202402~,在插入 7月數據的時候報錯了。

圖片圖片

COSID 類型算法

ShardingSphere 提供了三種基于散列散列算法的CosId(它是一款性能極高分布式ID生成器)分片算法,這個算法的核心思想是通過散列算法對CosId生成的分布式ID和分片鍵值進行處理,以確定數據應該存放在哪個具體的數據節點上。

使用散列算法的優勢,可以將數據按照一定規則映射到不同的數據節點上,能夠確保數據的均勻分布,避免某些節點負載過重或者數據傾斜的情況。

三個算法與其他分片算法主要區別在于底層的實現,在配置上使用上基本沒太多區別。

8、COSID_MOD

基于 CosId 的取模分片算法和普通的MOD算法使用上略有不同,mod為分片數量,logic-name-prefix分片數據源或真實表的前綴格式。

圖片圖片

yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片數量
          # 8、基于 CosId 的取模分片算法
          t_order_table_cosid_mod:
            type: COSID_MOD
            props:
              mod: 3  # 分片數量
              logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_cosid_mod
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

9、COSID_INTERVAL

基于 CosId 的固定時間范圍的分片算法,和INTERVAL算法的用法很相似,不同點在于增加了zone-id時區屬性,logic-name-prefix分片數據源或真實表的前綴格式,上下界datetime-lower、datetime-upper范圍的時間格式是固定的yyyy-MM-dd HH:mm:ss。

圖片圖片

yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片數量
          # 基于 CosId 的固定時間范圍的分片算法
          t_order_table_cosid_interval:
            type: COSID_INTERVAL
            props:
              zone-id: "Asia/Shanghai" # 時區,必須遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai
              logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式
              sharding-suffix-pattern: "yyyyMM" # 分片數據源或真實表的后綴格式,必須遵循 Java DateTimeFormatter 的格式,必須和 datetime-interval-unit 保持一致。例如:yyyyMM
              datetime-lower: "2024-01-01 00:00:00" # 時間分片下界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致
              datetime-upper: "2024-12-31 00:00:00" # 時間分片上界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致
              datetime-interval-unit: "MONTHS" # 分片鍵時間間隔單位,必須遵循 Java ChronoUnit 的枚舉值。例如:MONTHS
              datetime-interval-amount: 1 # 分片鍵時間間隔,超過該時間間隔將進入下一分片
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202412}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_cosid_interval
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

10、COSID_INTERVAL_SNOWFLAKE

基于 CosId 的雪花ID固定時間范圍的分片算法,和上邊的COSID_INTERVAL算法不同之處在于,底層用于散列的COSID的生成方式是基于雪花算法(Snowflake),內部結合了時間戳、節點標識符和序列號等,這樣有助于數據分布更均勻些。

圖片圖片

使用除了type類型不同COSID_INTERVAL_SNOWFLAKE外,其他屬性用法和COSID_INTERVAL完全一致。yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片數量
          # 基于 CosId 的固定時間范圍的分片算法
          t_order_table_cosid_interval_snowflake:
            type: COSID_INTERVAL_SNOWFLAKE
            props:
              zone-id: "Asia/Shanghai" # 時區,必須遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai
              logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式
              sharding-suffix-pattern: "yyyyMM" # 分片數據源或真實表的后綴格式,必須遵循 Java DateTimeFormatter 的格式,必須和 datetime-interval-unit 保持一致。例如:yyyyMM
              datetime-lower: "2024-01-01 00:00:00" # 時間分片下界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致
              datetime-upper: "2024-12-31 00:00:00" # 時間分片上界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致
              datetime-interval-unit: "MONTHS" # 分片鍵時間間隔單位,必須遵循 Java ChronoUnit 的枚舉值。例如:MONTHS
              datetime-interval-amount: 1 # 分片鍵時間間隔,超過該時間間隔將進入下一分片
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202412}
            # 分庫策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_cosid_interval_snowflake
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

復合分片算法

11、COMPLEX_INLINE

復合行表達式分片算法,適用于多分片健的簡單分片場景,和行表達式分片算法使用的方式基本一樣。多了一個屬性sharding-columns分片列名稱,多個列用逗號分隔。特別注意:使用多分片鍵復合算法,一定要基于復合分片策略進行設置。

圖片圖片

我們對現有的分庫分表算法進行了改進,將分片策略修改為complex,sharding-columns單個分片鍵升級為多個分片鍵逗號分隔。例如,將分庫表達式從db$->{order_id % 2}調整為db$->{(order_id + user_id) % 2},就實現了多個分片鍵的應用。

yml核心的配置如下:

spring:
  shardingsphere:
    # 具體規則配置
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          t_order_database_complex_inline_algorithms:
            type: COMPLEX_INLINE
            props:
              sharding-columns: order_id, user_id # 分片列名稱,多個列用逗號分隔。
              algorithm-expression: db$->{(order_id + user_id) % 2} # 分片算法的行表達式
              allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false
          # 11、復合行表達式分片算法
          t_order_table_complex_inline:
            type: COMPLEX_INLINE
            props:
              sharding-columns: order_id, user_id # 分片列名稱,多個列用逗號分隔。
              algorithm-expression: t_order_$->{ (order_id + user_id) % 3 } # 分片算法的行表達式
              allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
              complex:
                shardingColumns: order_id, user_id
                sharding-algorithm-name: t_order_database_complex_inline_algorithms
            # 分表策略
            table-strategy:
              complex:
                shardingColumns: order_id, user_id
                sharding-algorithm-name: t_order_table_complex_inline
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

Hint 分片算法

12、HINT_INLINE

Hint 行表達式分片算法(強制路由分片算法),允許我們指定數據分布的分片庫和分表的位置。這個算法只有一個屬性algorithm-expression,直接利用Groovy表達式在其中書寫分片邏輯。

如果想要向db0.t_order_1分片表中插入一條數據,但我的 Insert SQL 中并沒有分片健呀,執意執行插入操作可能就會導致全庫表路由,插入的數據就會重復,顯然是不能接受的。Hint 算法可以很好的解決此場景。

HINT_INLINE 算法一定要在 HINT 分片策略內使用,否則會報錯。

核心的配置如下:其中兩個表達式db$->{Integer.valueOf(value) % 2}和t_order_$->{Integer.valueOf(value) % 3}中的value值分別是我們通過 Hint API 傳入的分庫值和分表值。

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定義
        sharding-algorithms:
          # Hint 行表達式分片算法
          t_order_database_hint_inline:
            type: HINT_INLINE
            props:
              algorithm-expression: db$->{Integer.valueOf(value) % 2} # 分片算法的行表達式,默認值${value}
          t_order_table_hint_inline:
            type: HINT_INLINE
            props:
              algorithm-expression: t_order_$->{Integer.valueOf(value) % 3} # 分片算法的行表達式,默認值${value}
        tables:
          # 邏輯表名稱
          t_order:
            # 數據節點:數據庫.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分庫策略
            database-strategy:
              hint:
                sharding-algorithm-name: t_order_database_hint_inline
            # 分表策略
            table-strategy:
              hint:
                sharding-algorithm-name: t_order_table_hint_inline
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

配置完分片算法,如何將value值傳遞進來?通過HintManager設置邏輯表的分庫addDatabaseShardingValue、分表addTableShardingValue,強制數據分布到指定位置。

@DisplayName("測試 hint_inline 分片算法插入數據")
@Test
public void insertHintInlineTableTest() {
      HintManager hintManager = HintManager.getInstance();
      hintManager.clearShardingValues();
      // 設置邏輯表 t_order 的分庫值
      hintManager.addDatabaseShardingValue("t_order", 0);
      // 設置邏輯表 t_order 的分表值
      hintManager.addTableShardingValue("t_order", 1);
      // 1%3 = 1 所以放入 db0.t_order_1 分片表
      jdbcTemplate.execute("INSERT INTO `t_order`(`id`,`order_date`,`order_id`, `order_number`, `customer_id`, `total_amount`, `interval_value`, `user_id`) VALUES (1, '2024-03-20 00:00:00', 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);");
      hintManager.close();
}

ShardingSphere 通過使用ThreadLocal管理強制路由配置,可以通過編程的方式向HintManager中添加分片值,該分片值僅在當前線程內生效。

  • HintManager.getInstance() 獲取 HintManager 實例;
  • HintManager.addDatabaseShardingValue,HintManager.addTableShardingValue 方法設置分片鍵值;
  • 執行 SQL 語句完成路由和執行;
  • 最后調用 HintManager.close 清理 ThreadLocal 中的內容。

按我們設定的數據節點位置,插入一條測試數據,看到確實存在了db0.t_order_1中,完美!

圖片圖片

總結

本文中我們講解了ShardingSphere-jdbc所支持的12種分片算法,每種算法都具有獨特的特點。在實際應用中,需要結合具體的業務場景來靈活選擇和應用適合的分片算法。

由于篇幅已經夠長了,剩下的 3 種自定義分片算法會在下一篇中詳細介紹。

全部demo案例 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-algorithms

責任編輯:武曉燕 來源: 程序員小富
相關推薦

2021-03-29 12:22:25

微信iOS蘋果

2020-10-22 12:30:33

MySQL

2020-04-14 13:32:56

@Transacti失效場景

2021-06-08 22:43:07

IPC方式Qt

2020-03-31 08:12:25

Kafka架構數據庫

2021-05-18 09:03:16

Gomapslice

2021-12-06 08:30:49

SpringSpring Bean面試題

2025-05-14 01:55:00

FCMCPAI

2022-05-24 11:50:46

延時消息分布式

2023-12-18 23:09:25

開源優化引擎

2020-09-24 09:08:04

分布式系統架構

2020-07-08 07:45:44

OAuth2.0授權

2020-04-16 12:42:42

附近的人共享單車App

2020-08-12 09:55:07

附近的人數據庫MySQL

2025-11-11 08:47:00

2024-01-29 00:29:49

通信技術行業

2024-04-26 09:40:10

項目精度丟失javascrip

2021-03-01 18:52:39

工具在線瀏覽器

2021-01-04 11:23:21

手機無線電通訊

2020-05-08 10:08:21

延時隊列APIDelayQueue
點贊
收藏

51CTO技術棧公眾號

欧美日本韩国国产| 欧美在线视频一区二区| 粗大的内捧猛烈进出视频| 50度灰在线| www.日韩大片| 国产精品第一视频| 青花影视在线观看免费高清| 日韩在线亚洲| 91高清视频免费看| 亚洲精品偷拍视频| 天堂成人在线| 看片的网站亚洲| 久久久亚洲网站| 中文字幕免费在线看线人动作大片| 一区二区三区日本视频| 精品福利免费观看| 中国 免费 av| 黄色av网站在线看| 成人中文字幕电影| 国产精品一区二区三区在线播放| 国产一级做a爰片在线看免费| 精品美女在线视频| 欧美精品一区二区在线观看| 亚洲黄色小视频在线观看| 欧美家庭影院| 国产精品久久免费看| 国产丝袜不卡| www.av网站| 免费看精品久久片| 97视频在线观看亚洲| 一区二区国产精品精华液| 日韩在线麻豆| 精品欧美乱码久久久久久1区2区| 中文字幕22页| 日韩三区免费| 福利视频一区二区| 又大又硬又爽免费视频| 毛片在线不卡| 亚洲国产精华液网站w| 久久久久久久久久久久久久一区| av片免费播放| 韩国成人精品a∨在线观看| 日韩av不卡电影| 在线观看精品国产| 亚洲伦理精品| 欧美激情视频给我| 97成人资源站| 亚洲国产精品久久久久蝴蝶传媒| 在线播放日韩欧美| 国产一二三四五区| 伊人精品一区| 亚洲女人天堂网| 伊人网综合视频| 福利片一区二区| 亚洲国产精久久久久久久| 一区二区三区人妻| 亚洲一二av| 日韩精品一区二区三区视频 | 婷婷在线精品视频| 国产精品久久久久9999赢消| 日韩最新免费不卡| 亚洲综合久久av一区二区三区| 欧美日韩激情| 色视频www在线播放国产成人| 天天干天天舔天天操| 欧美日韩国产高清电影| 少妇久久久久久| 欧美成人久久久免费播放| 四虎成人av| 久久九九全国免费精品观看| 成人免费黄色小视频| 欧美日韩三级| 91国内精品久久| 91精品国产高清一区二区三密臀| 亚洲女同在线| 国产女人精品视频| 99国产在线播放| 懂色av一区二区三区免费观看| 国产精品久久九九| 欧美精品少妇| 国产精品久久久久久久午夜片| 在线看无码的免费网站| 欧美1—12sexvideos| 五月婷婷久久丁香| 久久精品网站视频| 国产精品777777在线播放| 日韩欧美国产综合一区| 波多野结衣先锋影音| 国内精品久久久久久久影视简单| 日韩在线观看你懂的| 中文字幕影音先锋| 亚洲一区日韩| 成人黄色激情网| 国产1区在线观看| 久久精品一级爱片| 看全色黄大色大片| 密臀av在线播放| 欧美日本韩国一区二区三区视频| 免费黄色a级片| 国产亚洲第一伦理第一区| 久久精视频免费在线久久完整在线看 | 国产精品无码在线播放| thepron国产精品| 亚洲国产精品123| 成人爽a毛片免费啪啪动漫| 日本精品视频一区二区三区| 在线视频日韩欧美| 精品一区在线| 色综合色综合网色综合| 中文字幕在线日本| 国产91对白在线观看九色| 日韩精品不卡| av成人 com a| 在线不卡欧美精品一区二区三区| 这里只有精品在线观看视频| 亚洲精彩视频| 国产精品大片wwwwww| 黑人操亚洲女人| 亚洲视频狠狠干| 午夜dv内射一区二区| 日韩av不卡一区| 久久91亚洲人成电影网站| 五月婷婷丁香在线| 91在线视频18| 久无码久无码av无码| 综合久久伊人| 曰本色欧美视频在线| 六月丁香激情综合| 成人性色生活片| 黄色网zhan| 亚洲精品69| 在线看日韩欧美| 日韩综合在线观看| 91丝袜国产在线播放| 国内自拍中文字幕| 96sao精品免费视频观看| 伊人青青综合网站| 国产小视频在线免费观看| 国产·精品毛片| 日韩国产精品毛片| 日本精品久久| 中文字幕亚洲图片| 黄色av网站免费| 久久蜜桃av一区精品变态类天堂| 欧美视频免费看欧美视频| 白嫩亚洲一区二区三区| 日韩在线观看免费av| 欧美日韩 一区二区三区| 92国产精品观看| 人人妻人人添人人爽欧美一区| 麻豆精品国产| 久久99精品久久久久久噜噜| 国产精品视频一区二区三区,| 国产女主播在线一区二区| 成人亚洲视频在线观看| 国产成人av| 国产精品久久久久久久久借妻 | 午夜精品福利电影| 亚洲精品国产手机| 亚洲一区二区三区免费视频| 无码人妻一区二区三区一| 欧美96在线丨欧| 不卡视频一区二区| 美女精品视频| 亚洲精品一区二区三区四区高清| 日本一级黄色大片| 99久久婷婷国产精品综合| 免费欧美一级视频| 国产精品欧美在线观看| 国产精品精品软件男同| 精品久久久久久久久久岛国gif| 色妞欧美日韩在线| 一级黄色免费看| 亚洲欧洲性图库| а 天堂 在线| 欧美日韩爆操| 九色91视频| 亚洲综合在线电影| www.xxxx欧美| 国产ts变态重口人妖hd| 一区二区三区欧美亚洲| 国产精品久久久久久久无码| 久久久精品五月天| 亚洲午夜精品一区二区| 国产精品**亚洲精品| 97久久精品在线| 高清av电影在线观看| 69堂精品视频| 成年人免费看毛片| 亚洲国产精品t66y| 久草视频福利在线| 丝袜亚洲另类欧美综合| 一区二区三视频| 成人在线视频你懂的| 国产99视频在线观看| 男女啪啪在线观看| 日韩麻豆第一页| 国产影视一区二区| 性欧美大战久久久久久久久| 成熟人妻av无码专区| 国产成人精品三级麻豆| 欧美亚洲另类色图| 中文字幕一区二区av| 久久66热这里只有精品| 久久99久久久精品欧美| 97色在线视频观看| 免费在线观看黄| 日韩精品亚洲精品| 精品久久久无码中文字幕| 91精品办公室少妇高潮对白| 欧美精品videos极品| 中文字幕乱码亚洲精品一区| 国产一卡二卡三卡四卡| 久久成人免费网| 黄www在线观看| 欧美日本三区| 亚洲精品一区二区三区四区五区 | 国产精品久久久久久久久婷婷| 欧美a级在线观看| 欧美精品少妇videofree| 国产高清在线看| 日韩av一区二区在线| www.好吊色| 9191久久久久久久久久久| 无码视频一区二区三区| 亚洲成av人片www| 亚洲国产精品久| 中文字幕亚洲欧美在线不卡| 日本精品在线观看视频| 不卡一区中文字幕| 日本55丰满熟妇厨房伦| 另类小说一区二区三区| 久久精品一区二| 国产模特精品视频久久久久| 久久久99精品视频| 羞羞答答成人影院www| 亚洲视频欧美在线| 成人激情电影在线| 欧美精品123| 中文字幕精品影院| 精品一区二区国产| 日本国产精品| 麻豆视频成人| 亚洲综合图色| 麻豆亚洲一区| 国产精品一区二区av交换| 精品一区二区国产| 性欧美lx╳lx╳| 国产一区二区三区黄| 成人线上播放| 国模精品一区二区三区| 国产欧美一区二区三区米奇| 国产精品视频免费一区| 亚洲综合影院| av免费观看久久| 中文字幕日韩在线| 国产精品一 二 三| 美女主播精品视频一二三四| 国产在线欧美日韩| 女同久久另类99精品国产| 国产精品日韩欧美一区二区三区| 国产人妖ts一区二区| 国产一区二区三区四区五区在线 | 日本成人在线不卡| 中文一区一区三区免费在线观看| 国产对白在线播放| 午夜欧美精品| 欧美 日韩 国产在线观看| 亚洲一区日本| 成人性生生活性生交12| 久久国产精品色婷婷| 欧美一级小视频| 国产99精品国产| 亚洲第一黄色网址| 久久久影视传媒| 久久丫精品忘忧草西安产品| 国产精品久久久久久久久免费桃花| 国产91在线播放九色| 亚洲男人的天堂在线aⅴ视频| 国产一级做a爱免费视频| 欧美日韩亚洲国产一区| 国产成人麻豆免费观看| 日韩一区二区在线看| 免费观看国产精品| 国产一区二区三区在线视频| 美女羞羞视频在线观看| 国模吧一区二区三区| 精品成人av| 91手机在线播放| 无码日韩精品一区二区免费| 一区二区三区四区国产| 亚洲国产第一| 亚洲三级视频网站| 国产成人免费在线观看| 亚洲久久久久久久| 亚洲综合成人在线| 波多野结衣在线观看一区| 欧美一区二区观看视频| 欧美成熟毛茸茸| 久久777国产线看观看精品| 中文字幕在线官网| 亚洲最大的免费| 黑人操亚洲人| 日韩美女爱爱视频| 麻豆一区二区99久久久久| 成人免费毛片日本片视频| 中文字幕中文字幕在线一区| 成人免费视频毛片| 欧美一区二区啪啪| 风间由美一区| 51视频国产精品一区二区| 成人在线日韩| 日韩一区不卡| 国产精品毛片在线| 丰满少妇中文字幕| 国产精品免费免费| 国产精品人人人人| 亚洲精品一区二区三区精华液| 伦xxxx在线| 国产精品高清免费在线观看| 精品国产18久久久久久洗澡| 亚洲美女自拍偷拍| 日韩精品成人一区二区在线| 日韩无码精品一区二区| 亚洲欧美日韩综合aⅴ视频| 天天干天天操天天操| 日韩电影网在线| 丁香影院在线| 91日韩久久| 欧美精品激情| 成人免费播放视频| 亚洲欧美综合网| 中文无码精品一区二区三区| 亚洲欧洲国产一区| 日韩脚交footjobhdboots| 国产伦精品一区二区三区四区免费 | 久久亚洲影视婷婷| 国产第一页第二页| 日韩视频中午一区| 国产网友自拍视频导航网站在线观看| 国产精品高潮视频| 成人在线电影在线观看视频| 欧美日韩一区二区在线免费观看| 99久久精品99国产精品| 日韩人妻无码一区二区三区99| 日韩精品一区二区三区老鸭窝| 国产美女福利在线| 成人精品一区二区三区| 国产精品久久观看| 污视频在线观看免费网站| 最新高清无码专区| 国产在成人精品线拍偷自揄拍| 日日噜噜噜夜夜爽亚洲精品| www.久久久久爱免| 国产四区在线观看| 国内精品久久久久影院薰衣草| 一区二区三区影视| 日韩欧美一区二区免费| 青草在线视频| 狠狠干一区二区| 久久久久国内| a级黄色免费视频| 8x8x8国产精品| 色呦呦呦在线观看| 国产一区二区在线网站| 免费精品视频| 一级特黄曰皮片视频| 欧美久久高跟鞋激| 色在线视频网| 欧美一区二区三区精美影视| 日韩高清在线不卡| 美女的奶胸大爽爽大片| 精品国产1区2区3区| 久草在线中文最新视频| 日韩啊v在线| 国产原创一区二区| 久久夜色精品亚洲| 一本一本久久a久久精品综合小说 一本一本久久a久久精品牛牛影视 | 日本一级淫片演员| 国产成人免费高清| 无码人妻黑人中文字幕| 中文字幕亚洲一区在线观看 | 国产伦子伦对白在线播放观看| 久久久久久久久久码影片| 麻豆精品一区二区综合av| 久久久久久久久久久网| 亚洲欧美色图片| 欧美视频二区欧美影视| 男人操女人逼免费视频| 国产日韩欧美精品一区| 国产a级免费视频| 欧美自拍大量在线观看| 91精品精品| av直播在线观看| 欧美电影一区二区| 色戒汤唯在线| 欧美性受黑人性爽| 2020国产成人综合网| 精品国产九九九| 国产成人高清激情视频在线观看|