官宣|Apache Flink 1.20 發(fā)布公告

作者:郭偉杰(阿里云), 范瑞(Shopee)


Apache Flink PMC(項(xiàng)目管理委員)很高興地宣布發(fā)布 Apache Flink 1.20.0。與往常一樣,這是一個(gè)充實(shí)的版本,包含了廣泛的改進(jìn)和新功能??偣灿?142 人為此版本做出了貢獻(xiàn),完成了 13 個(gè) FLIPs、解決了 300 多個(gè)問題。感謝各位貢獻(xiàn)者的支持!

站在 Flink 2.0 的前夜

Apache Flink 1.0 發(fā)布至今已經(jīng) 8 年了。因此,最近幾個(gè)月以來,社區(qū)一直在積極朝著下一個(gè)大版本(Flink 2.0)邁進(jìn)。最新發(fā)布的 Flink 1.20 版本將會(huì)是 Flink 2.0 (預(yù)計(jì) 2024 年底發(fā)布) 之前的最后一個(gè)小版本。

從 Flink 1.19 開始,社區(qū)決定正式開始廢棄過時(shí)的公共 API。在 1.20 中,我們進(jìn)一步整理了所有可能需要被替換或棄用的API,為 2.0 版本鋪平道路:

  • 為了提升易用性和可維護(hù)性,我們重新審視了所有運(yùn)行時(shí)、Table、SQL 以及狀態(tài)和檢查點(diǎn)相關(guān)的配置項(xiàng),對(duì)它們進(jìn)行了歸類,增強(qiáng)和廢棄。

  • 廢棄過時(shí)的 SinkFunction 接口: Flink 1.12 引入了 Unified Sink V2,經(jīng)過了多個(gè)版本的開發(fā)和迭代后, 它已經(jīng)變得比較穩(wěn)定和完善。根據(jù)社區(qū)在 FLIP-197 中提出的關(guān)于 API 演進(jìn)的要求,我們把 Unified Sink V2 提升為了公共接口,并且廢棄了 SinkFunction 接口。

歷經(jīng) 8 年的發(fā)展,我們對(duì) Flink 2.0 寄予厚望,并且計(jì)劃在 2.x 中發(fā)布幾個(gè)重量級(jí)的新功能。其中一些已在 Flink 1.20 中完成了最小可行產(chǎn)品(MVP)的開發(fā):

  • 提升數(shù)據(jù)加工鏈路開發(fā)體驗(yàn):FLIP-435引入了物化表功能,允許用戶在動(dòng)態(tài)表中通過統(tǒng)一的 SQL 語句來定義數(shù)據(jù)的流式/批式轉(zhuǎn)換邏輯,從而加速 ETL 管道開發(fā),并自動(dòng)管理任務(wù)調(diào)度。完整內(nèi)容和更多細(xì)節(jié)請(qǐng)參考FLIP-435。

  • 統(tǒng)一的檢查點(diǎn)文件合并機(jī)制:Flink 1.20 中引入了統(tǒng)一的檢查點(diǎn)文件合并機(jī)制,允許將零散的小的檢查點(diǎn)文件合并到大文件中,減少文件創(chuàng)建和文件刪除的次數(shù),緩解大量小文件對(duì)文件系統(tǒng)元數(shù)據(jù)管理帶來的壓力。完整內(nèi)容和更多細(xì)節(jié)請(qǐng)參考FLIP-306。

Flink SQL 提升

引入物化表

Flink 1.20 版本 為 Flink SQL 引入了物化表(Materialized Table)抽象。這是一種新的表類型,旨在同時(shí)簡化流和批處理的數(shù)據(jù)加工鏈路,同時(shí)提供一致的開發(fā)體驗(yàn)。

通過定義查詢語句和數(shù)據(jù)新鮮度,引擎會(huì)自動(dòng)推導(dǎo)出表結(jié)構(gòu)并創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)加工鏈路,以保證查詢結(jié)果滿足所要求的數(shù)據(jù)新鮮度。用戶無需理解流處理和批處理之間的概念和差異,也不必直接維護(hù) Flink 流處理或批作業(yè),所有操作都在物化表上完成,這可以顯著加快 ETL 數(shù)據(jù)加工鏈路的開發(fā)速度。

下面是創(chuàng)建一個(gè)具備自動(dòng)刷新能力的物化表的示例,數(shù)據(jù)新鮮度為 3 分鐘。

-- 1. 創(chuàng)建物化表并定義新鮮度
CREATE MATERIALIZED TABLE dwd_orders
(
 PRIMARY KEY(ds, id) NOT ENFORCED
)
PARTITIONED BY (ds)
FRESHNESS = INTERVAL '3' MINUTE
AS SELECT 
 o.ds
 o.id,
 o.order_number,
 o.user_id,
...
FROM 
 orders as o
 LEFT JOIN products FOR SYSTEM_TIME AS OF proctime() AS prod
 ON o.product_id = prod.id
 LEFT JOIN order_pay AS pay
 ON o.id = pay.order_id and o.ds = pay.ds;

-- 2. 暫停數(shù)據(jù)刷新
ALTER MATERIALIZED TABLE dwd_orders SUSPEND;

-- 3. 恢復(fù)數(shù)據(jù)刷新
ALTER MATERIALIZED TABLE dwd_orders RESUME
-- Set table option via WITH clause
WITH(
 'sink.parallesim' = '10'
);

-- 手動(dòng)刷寫歷史數(shù)據(jù)
ALTER MATERIALIZED TABLE dwd_orders REFRESH PARTITION(ds='20231023');

更多信息

完善 Catalog 相關(guān)語法

隨著 Flink SQL 的廣泛采用,F(xiàn)link Catalog 發(fā)揮著越來越重要的作用。Flink 內(nèi)置了 JDBCHive Catalog 實(shí)現(xiàn),而其他開源項(xiàng)目(如 Apache Paimon)也實(shí)現(xiàn)了自己的 Catalog。

在 Flink 1.20 中,您可以使用 DQL 語法從現(xiàn)有 Catalog 中獲取詳細(xì)的元數(shù)據(jù)信息,并使用 DDL語法修改指定Catalog 的屬性或注釋等元數(shù)據(jù)。

Flink SQL> CREATE CATALOG `cat` WITH ('type'='generic_in_memory', 'default-database'='db');
[INFO] Execute statement succeeded.

Flink SQL> SHOW CREATE CATALOG `cat`;
+---------------------------------------------------------------------------------------------+
|                                                                                      result |
+---------------------------------------------------------------------------------------------+
| CREATE CATALOG `cat` WITH (
  'default-database' = 'db',
  'type' = 'generic_in_memory'
)
|
+---------------------------------------------------------------------------------------------+
1 row in set

Flink SQL> DESCRIBE CATALOG `cat`;
+-----------+-------------------+
| info name |        info value |
+-----------+-------------------+
|      name |               cat |
|      type | generic_in_memory |
|   comment |                   |
+-----------+-------------------+
3 rows in set

Flink SQL> ALTER CATALOG `cat` SET ('default-database'='new-db');
[INFO] Execute statement succeeded.

Flink SQL> SHOW CREATE CATALOG `cat`;
+-------------------------------------------------------------------------------------------------+
|                                                                                          result |
+-------------------------------------------------------------------------------------------------+
| CREATE CATALOG `cat` WITH (
  'default-database' = 'new-db',
  'type' = 'generic_in_memory'
)
|
+-------------------------------------------------------------------------------------------------+
1 row in set

更多信息

DDL 支持 DISTRIBUTED BY 語句

鑒于越來越多的 SQL 引擎對(duì)外暴露了 “分區(qū)”、“分桶”或“聚類”的概念,F(xiàn)link 1.20 將“分桶”的概念引入了 Flink SQL。分桶操作通過將數(shù)據(jù)拆分為不相交的子集來實(shí)現(xiàn)數(shù)據(jù)在外部存儲(chǔ)系統(tǒng)中的負(fù)載均衡。雖然它在很大程度上取決于底層連接器的語義,但是用戶可以通過指定分桶數(shù)量、算法以及用于目標(biāo)分桶計(jì)算的列(如果算法允許)來影響分桶的行為。所有分桶相關(guān)的關(guān)鍵字在 SQL 語法中都是可選的。

Apache Paimon 的分桶表和 Apache Kafka 的 topic 分區(qū)都將對(duì)接到該語法上,簡化用戶的建表操作,并讓 Flink SQL 感知了外部數(shù)據(jù)的物理分布,為未來支持 bucket join 等優(yōu)化打好了基礎(chǔ)。

以下面的 SQL 語句為例:

-- 指定桶的個(gè)數(shù)和數(shù)據(jù)分配邏輯(按照 uid 列的哈希值進(jìn)行分配)
CREATE TABLE MyTable (uid BIGINT, name STRING) DISTRIBUTED BY HASH(uid) INTO 4 BUCKETS;

-- 不顯示指定分桶算法,數(shù)據(jù)分配邏輯由 Connector 自己決定。
CREATE TABLE MyTable (uid BIGINT, name STRING) DISTRIBUTED BY (uid) INTO 4 BUCKETS;

-- 不顯式指定桶的數(shù)量,桶數(shù)量和數(shù)據(jù)分配邏輯均由 Connector 自己決定。
CREATE TABLE MyTable (uid BIGINT, name STRING) DISTRIBUTED BY (uid);

-- 僅指定桶的數(shù)量
CREATE TABLE MyTable (uid BIGINT, name STRING) DISTRIBUTED INTO 4 BUCKETS;

更多信息

狀態(tài) & 檢查點(diǎn)提升

統(tǒng)一的檢查點(diǎn)文件合并機(jī)制

Flink 1.20 引入了統(tǒng)一的檢查點(diǎn)文件合并機(jī)制,它將多個(gè)小的檢查點(diǎn)文件合并為數(shù)量較少的大文件,從而減少了文件創(chuàng)建和文件刪除操作的次數(shù),并減輕了檢查點(diǎn)期間文件系統(tǒng)元數(shù)據(jù)管理的壓力。

可以通過將 execution.checkpointing.file-merging.enabled 設(shè)置為 true來啟用該功能。有關(guān)更多高級(jí)選項(xiàng)以及此功能背后的原理,請(qǐng)參閱文檔

更多信息

壓縮小的 SST 文件

在某些情況下,RocksDB 狀態(tài)后端生成的文件數(shù)量會(huì)無限制地增長。除了許多小文件造成的開銷之外,此行為還可能導(dǎo)致任務(wù)狀態(tài)信息超出 RPC 消息大小限制,從而導(dǎo)致檢查點(diǎn)失敗。從 1.20 版開始,F(xiàn)link 可以使用 RocksDB API 在后臺(tái)合并此類文件。

更多信息

批處理能力提升

JobMaster 發(fā)生故障時(shí)更好的錯(cuò)誤恢復(fù)機(jī)制

在 Flink 1.20 中,我們支持了一種新的批處理作業(yè)恢復(fù)機(jī)制,使批處理作業(yè)能夠在 JobMaster故障轉(zhuǎn)移后盡可能多地恢復(fù)進(jìn)度,避免重新運(yùn)行已經(jīng)完成的任務(wù)。

更多信息

HiveSource 支持動(dòng)態(tài)并發(fā)推斷

在 Flink 1.20 中,我們?yōu)?Hive 數(shù)據(jù)源連接器增加了對(duì)動(dòng)態(tài)并發(fā)推斷的支持,這允許它基于動(dòng)態(tài)分區(qū)修剪(DPP)的結(jié)果動(dòng)態(tài)決定并行度。

此外,我們引入了一個(gè)新的配置選項(xiàng) table.exec.hive.infer-source-parallelism.mode,使用戶能夠在數(shù)據(jù)源并行度的靜態(tài)和動(dòng)態(tài)推斷模式之間進(jìn)行切換。需要注意的是,在 Flink 1.20 中,以前的配置選項(xiàng) table.exec.hive.infer-source-parallelism已被標(biāo)記為棄用。

更多信息

DataStream API 提升

DataSetAPI 已正式棄用,并將在 Flink 2.0 版本中被刪除。我們建議 Flink 用戶根據(jù)數(shù)據(jù)處理需求將作業(yè)從 DataSet API 逐步遷移到 DataStream API、TableAPI 和 SQL。

支持 DataStream API 上的全量分區(qū)數(shù)據(jù)處理

在 Flink 1.20 之前,DataStream API 不支持對(duì)非分區(qū)流上的數(shù)據(jù)做全量的數(shù)據(jù)聚合操作,這阻礙了用戶從 DataSetAPI 的遷移。作為一種替代方案,用戶可以將子任務(wù)的編號(hào)關(guān)聯(lián)到數(shù)據(jù)上,并以此為數(shù)據(jù)鍵來構(gòu)建分區(qū)流,但這會(huì)產(chǎn)生很大的額外開銷。為此,F(xiàn)link 1.20 引入了 FullPartitionWindow API,從而補(bǔ)齊了對(duì)全量分區(qū)數(shù)據(jù)處理的內(nèi)置支持。

假設(shè)我們想要計(jì)算每個(gè)分區(qū)中的總記錄數(shù)并輸出到下游,可以按如下方式完成:

inputStream.fullWindowPartition()
                .mapPartition(
         new MapPartitionFunction<Record, Long>() {
                    @Override
                    public void mapPartition(
                            Iterable<Record> values, Collector<Long> out)
                            throws Exception {
                        long counter = 0;
                        for (Record value : values) {
                            counter++;
                        }
                        out.collect(counter));
                    }
          })

更多信息

重要配置項(xiàng)變更

隨著 Apache Flink 即將來到 2.0 版本,一大批配置項(xiàng)在 Flink 1.20 版本被更改或棄用,以提高易用性和可維護(hù)性。

更新配置項(xiàng)為合適的類型

  • 一系列與時(shí)間相關(guān)的配置項(xiàng)(例如 client.heartbeat.interval)的類型被更新為了 Duration。完整列表可在FLINK-35359 中找到。

  • 配置項(xiàng) taskmanager.network.compression.codectable.optimizer.agg-phase-strategy的類型被更新為了Enum。

  • 配置項(xiàng)yarn.application-attempts的類型被更新為了 Int。

更多信息

棄用多個(gè)配置項(xiàng)

在 Flink 1.20 中社區(qū)決定正式棄用多個(gè)即將在 Flink 2.0 停用的配置項(xiàng):

  • 由于我們正在逐步淘汰基于哈希的 Blocking Shuffle,以下配置項(xiàng)已被棄用并將在 Flink 2.0 中被刪除:

    • taskmanager.network.sort-shuffle.min-parallelism

    • taskmanager.network.blocking-shuffle.type

  • 由于我們正在逐步淘汰舊的Hybrid Shuffle 模式,以下配置項(xiàng)已被棄用并將在 Flink 2.0 中被刪除:

    • taskmanager.network.hybrid-shuffle.spill-index-region-group-size

    • taskmanager.network.hybrid-shuffle.num-retained-in-memory-regions-max

    • taskmanager.network.hybrid-shuffle.enable-new-mode

  • 為了簡化網(wǎng)絡(luò)緩沖區(qū)相關(guān)配置,以下配置選項(xiàng)已被棄用并將在 Flink 2.0 中被刪除:

    • taskmanager.network.memory.buffers-per-channel

    • taskmanager.network.memory.floating-buffers-per-gate

    • taskmanager.network.memory.max-buffers-per-channel

    • taskmanager.network.memory.max-overdraft-buffers-per-gate

    • taskmanager.network.memory.exclusive-buffers-request-timeout-ms (請(qǐng)使用 taskmanager.network.memory.buffers-request-timeout 代替)

  • 由于絕大多數(shù)批作業(yè)都會(huì)開啟壓縮,配置項(xiàng) taskmanager.network.batch-shuffle.compression.enabled 已被棄用并將在 Flink 2.0 中被刪除。如確有需要,請(qǐng)將 taskmanager.network.compression.codec 設(shè)置為 NONE以禁用壓縮。

  • 以下與 Netty 相關(guān)的配置項(xiàng)過于底層,已在 Flink 1.20 被棄用,我們將在 Flink 2.0 中將其移除:

    • taskmanager.network.netty.num-arenas

    • taskmanager.network.netty.server.numThreads

    • taskmanager.network.netty.client.numThreads

    • taskmanager.network.netty.server.backlog

    • taskmanager.network.netty.sendReceiveBufferSize

    • taskmanager.network.netty.transport

  • 以下配置項(xiàng)是不必要的,已在 Flink 1.20 被棄用并且將在 Flink 2.0 中被刪除:

    • taskmanager.network.max-num-tcp-connections(將在 Flink 2.0 中被硬編碼為 1

    • fine-grained.shuffle-mode.all-blocking

  • 以下配置項(xiàng)用于微調(diào) TPC 測試但當(dāng)前 Flink 已不再需要,已被棄用并且將在 Flink 2.0 中被刪除:

    • table.exec.range-sort.enabled

    • table.optimizer.rows-per-local-agg

    • table.optimizer.join.null-filter-threshold

    • table.optimizer.semi-anti-join.build-distinct.ndv-ratio

    • table.optimizer.shuffle-by-partial-key-enabled

    • table.optimizer.smj.remove-sort-enabled

    • table.optimizer.cnf-nodes-limit

  • 以下配置項(xiàng)是為現(xiàn)已過時(shí)的 FilterableTableSource 接口引入的,已被棄用并且將在 Flink 2.0 中被刪除:

    • table.optimizer.source.aggregate-pushdown-enabled

    • table.optimizer.source.predicate-pushdown-enabled

  • 配置選項(xiàng)sql-client.display.max-column-width已被棄用并且將在 Flink 2.0 中被刪除。請(qǐng)改用 table.display.max-column-width替代。

更多信息

配置項(xiàng)的其他變更

重新組織配置項(xiàng)

在 Flink 1.20 中,所有關(guān)于狀態(tài)和檢查點(diǎn)的配置項(xiàng)都被重新組織并按前綴分類:

  • execution.checkpointing.*:所有與檢查點(diǎn)和保存點(diǎn)相關(guān)的配置選項(xiàng)。

  • execution.state-recovery.*:所有與狀態(tài)恢復(fù)相關(guān)的配置選項(xiàng)。

  • state.*:所有與狀態(tài)訪問相關(guān)的配置選項(xiàng)。

  • state.backend.*: 各個(gè)狀態(tài)后端的配置選項(xiàng),例如 RocksDB 狀態(tài)后端。

  • state.changelog.*:與狀態(tài)變更日志相關(guān)的配置選項(xiàng)。

  • state.latency-track.*:與狀態(tài)訪問的延遲追蹤相關(guān)的配置選項(xiàng)。

新的公開配置項(xiàng)

  • 以下與動(dòng)態(tài)哈希聚合相關(guān)配置項(xiàng)已從 org.apache.flink.table.planner.codegen.agg.batch.HashAggCodeGenerator移動(dòng)至 org.apache.flink.table.api.config 并提升為 @PublicEvolvingAPI:

  • table.exec.local-hash-agg.adaptive.enabled

  • table.exec.local-hash-agg.adaptive.sampling-threshold

  • table.exec.local-hash-agg.adaptive.distinct-value-rate-threshold

  • 以下與 LookupJoin 相關(guān)的配置項(xiàng)已從 org.apache.flink.table.planner.hint.LookupJoinHintOptions移動(dòng)至 org.apache.flink.table.api.config.LookupJoinHintOptions并提升為 @PublicEvolvingAPI:

  • table

  • async

  • output-mode

  • capacity

  • timeout

  • retry-predicate

  • retry-strategy

  • fixed-delay

  • max-attempts

  • 以下與優(yōu)化器有關(guān)的配置項(xiàng)已從 org.apache.flink.table.planner.plan.optimize.RelNodeBlock移動(dòng)至 org.apache.flink.table.api.config.OptimizerConfigOptions并升級(jí)為 @PublicEvolvingAPI:

  • table.optimizer.union-all-as-breakpoint-enabled

  • table.optimizer.reuse-optimize-block-with-digest-enabled

  • table.optimizer.incremental-agg-enabled 已從 org.apache.flink.table.planner.plan.rules.physical.stream.IncrementalAggregateRule移動(dòng)至 org.apache.flink.table.api.config.OptimizerConfigOptions 并升級(jí)為 @PublicEvolvingAPI.

更多信息

升級(jí)說明

Apache Flink 社區(qū)努力確保升級(jí)過程盡可能平穩(wěn), 但是升級(jí)到 1.20 版本可能需要用戶對(duì)現(xiàn)有應(yīng)用程序做出一些調(diào)整。請(qǐng)參考Release Notes獲取更多的升級(jí)時(shí)需要的改動(dòng)與可能的問題列表細(xì)節(jié)。

貢獻(xiàn)者列表

在 1.20 版本中,我們一如既往地看到了許多來自中國的開發(fā)者身影。他們積極參與并貢獻(xiàn)社區(qū),協(xié)助新版本的發(fā)布,四個(gè)版本發(fā)布管理者(Release Manager)中有兩位均來自國內(nèi),分別是來自阿里云智能的郭偉杰和來自 Shopee 的范瑞。中國開發(fā)者在 1.20 備受期待的新功能上也作出了巨大貢獻(xiàn),例如來自阿里云的開發(fā)者們主導(dǎo)并貢獻(xiàn)了物化表、檢查點(diǎn)文件合并、JobMaster 發(fā)生故障時(shí)更好的錯(cuò)誤恢復(fù)機(jī)制等特性。來自字節(jié)跳動(dòng),網(wǎng)易,小米等公司的開發(fā)者們也都為社區(qū)帶來了非常多的重要功能貢獻(xiàn)和 bug 修復(fù)。

Apache Flink 社區(qū)感謝對(duì)此版本做出貢獻(xiàn)的每一位貢獻(xiàn)者:

Ahmed Hamdy, Alan Sheinberg, Aleksandr Pilipenko, Alexander Fedulov, Andrey Gaskov, Antonio Vespoli, Anupam Aggarwal, Barak Ben-Nathan, Benchao Li, Brad, Cheng Pan, Chesnay Schepler, DamonXue, Danny Cranmer, David Christle, David Moravek, David Schlosnagle, Dawid Wysakowicz, Dian Fu, Dmitriy Linevich, Elphas Toringepi, Emre Kartoglu, Fang Yong, Feng Jin, Ferenc Csaky, Frank Yin, Gabor Somogyi, Gyula Fora, HCTommy, Hangxiang Yu, Hanyu Zheng, Hao Li, Hong Liang Teoh, Hong Teoh, HuangXingBo, Jacky Lau, James Hughes, Jane Chan, Jeyhun Karimov, Jiabao Sun, Jim Hughes, Jing Ge, Jinzhong Li, JunRuiLee, Juntao Hu, JustinLee, Kartikey Pant, Kumar Mallikarjuna, Leonard Xu, Lorenzo Affetti, Luke Chen, Martijn Visser, Mason Chen, Matthias Pohl, Mingliang Liu, Panagiotis Garefalakis, Peter Huang, Peter Vary, Piotr Nowojski, Puneet Duggal, Qinghui Xu, Qingsheng Ren, Ravi Dutt Singh, Robert Metzger, Robert Young, Roc Marshal, Roman, Roman Boyko, Roman Khachatryan, Ron, Rui Fan, Ryan Skraba, Samrat, Sergey Nuyanzin, Shilun Fan, Stefan Richter, SuDewei, Timo Walther, Ufuk Celebi, Vincent Woo, Wang FeiFan, Weijie Guo, Wencong Liu, Wouter Zorgdrager, Xiangyu Feng, Xintong Song, Xuyang, Yanfei Lei, Yangze Guo, Yu Chen, Yubin Li, Yuepeng Pan, Yun Tang, Yuxin Tan, Zakelly, Zhanghao Chen, Zhen Wang, Zhenqiu Huang, Zhu Zhu, Zmm, ammar-master, anupamaggarwal, bvarghese1, caicancai, caodizhou, chenzihao, drymatini, dsaisharath, eason.qin, elon-X, fengli, gongzhongqiang, hejufang, jectpro7, jiangxin, liming.1018, lincoln lee, liuyongvs, lxliyou001, oleksandr.nitavskyi, plugatarev, rmoff, slfan1989, spoon-lz, sunxia, sxnan, sychen, wforget, xiaogang, xingbo, yebukong, yunfengzhou-hub, yunhong, zhouyisha, 馬越

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容