国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Flink流批一體計(jì)算(19):PyFlink DataStream API之State

這篇具有很好參考價(jià)值的文章主要介紹了Flink流批一體計(jì)算(19):PyFlink DataStream API之State。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

目錄

keyed state

Keyed DataStream

使用 Keyed State

實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的計(jì)數(shù)窗口

狀態(tài)有效期 (TTL)

過(guò)期數(shù)據(jù)的清理

全量快照時(shí)進(jìn)行清理

增量數(shù)據(jù)清理

在 RocksDB 壓縮時(shí)清理

Operator State算子狀態(tài)

Broadcast State廣播狀態(tài)


keyed state

Keyed DataStream

使用 keyed state,首先需要為DataStream指定 key(主鍵)。這個(gè)主鍵用于狀態(tài)分區(qū)(也會(huì)給數(shù)據(jù)流中的記錄本身分區(qū))。

使用 DataStream 中 Java/Scala API 的 keyBy(KeySelector) 或者是 Python API 的 key_by(KeySelector) 來(lái)指定 key。它將生成 KeyedStream,接下來(lái)允許使用 keyed state 操作。

Keyselector函數(shù)接收單條記錄作為輸入,返回這條記錄的 key。該 key 可以為任何類型,但是它的計(jì)算產(chǎn)生方式必須是具備確定性的。

Flink的數(shù)據(jù)模型不基于key-value對(duì),因此實(shí)際上將數(shù)據(jù)集在物理上封裝成 key和 value是沒(méi)有必要的。Key是“虛擬”的。它們定義為基于實(shí)際數(shù)據(jù)的函數(shù),用以操縱分組算子。

使用 Keyed State

keyed state接口提供不同類型狀態(tài)的訪問(wèn)接口,這些狀態(tài)都作用于當(dāng)前輸入數(shù)據(jù)的key。

換句話說(shuō),這些狀態(tài)僅可在KeyedStream上使用,在Java/Scala API上可以通過(guò)stream.keyBy(...)得到 KeyedStream,在Python API上可以通過(guò) stream.key_by(...) 得到 KeyedStream。

所有支持的狀態(tài)類型如下所示:

ValueState<T>: 保存一個(gè)可以更新和檢索的值

Liststate<T>: 保存一個(gè)元素的列表??梢酝@個(gè)列表中追加數(shù)據(jù),并在當(dāng)前的列表上進(jìn)行檢索。

ReducingState<T>: 保存一個(gè)單值,表示添加到狀態(tài)的所有值的聚合。但使用 add(T) 增加元素,會(huì)使用提供的 ReduceFunction 進(jìn)行聚合。

AggregatingState<IN, OUT>: 保留一個(gè)單值,表示添加到狀態(tài)的所有值的聚合。使用 add(IN) 添加的元素會(huì)用指定的 AggregateFunction 進(jìn)行聚合。

MapState<UK, UV>: 維護(hù)了一個(gè)映射列表。 你可以添加鍵值對(duì)到狀態(tài)中,也可以獲得反映當(dāng)前所有映射的迭代器。

所有類型的狀態(tài)還有一個(gè)clear() 方法,清除當(dāng)前 key 下的狀態(tài)數(shù)據(jù),也就是當(dāng)前輸入元素的 key。

實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的計(jì)數(shù)窗口

我們把元組的第一個(gè)元素當(dāng)作 key。 該函數(shù)將出現(xiàn)的次數(shù)以及總和存儲(chǔ)在 “ValueState” 中。

一旦出現(xiàn)次數(shù)達(dá)到 2,則將平均值發(fā)送到下游,并清除狀態(tài)重新開始。 請(qǐng)注意,我們會(huì)為每個(gè)不同的 key(元組中第一個(gè)元素)保存一個(gè)單獨(dú)的值。

必須創(chuàng)建一個(gè) StateDescriptor,才能得到對(duì)應(yīng)的狀態(tài)句柄。 這保存了狀態(tài)名稱,狀態(tài)所持有值的類型,并且可能包含用戶指定的函數(shù),例如ReduceFunction。

根據(jù)不同的狀態(tài)類型,可以創(chuàng)建ValueStateDescriptor,ListstateDescriptor, AggregatingStateDescriptor, ReducingStateDescriptor 或MapStateDescriptor。

狀態(tài)通過(guò) RuntimeContext 進(jìn)行訪問(wèn),因此只能在 rich functions 中使用。

from pyflink.common.typeinfo import Types
from pyflink.datastream import StreamExecutionEnvironment, FlatMapFunction, RuntimeContext
from pyflink.datastream.state import ValueStateDescriptor

class CountWindowAverage(FlatMapFunction):
??? def __init__(self):
??????? self.sum = None

??? def open(self, runtime_context: RuntimeContext):
??????? descriptor = ValueStateDescriptor(
??????????? "average",? # the state name
??????????? Types.PICKLED_BYTE_ARRAY()? # type information
??????? )
??????? self.sum = runtime_context.get_state(descriptor)

??? def flat_map(self, value):
??????? # access the state value
??????? current_sum = self.sum.value()
??????? if current_sum is None:
??????????? current_sum = (0, 0)
??????? # update the count
??????? current_sum = (current_sum[0] + 1, current_sum[1] + value[1])
??????? # update the state
??????? self.sum.update(current_sum)
??????? # if the count reaches 2, emit the average and clear the state
??????? if current_sum[0] >= 2:
??????????? self.sum.clear()
??????????? yield value[0], int(current_sum[1] / current_sum[0])


env = StreamExecutionEnvironment.get_execution_environment()
env.from_collection([(1, 3), (1, 5), (1, 7), (1, 4), (1, 2)]) \
??? .key_by(lambda row: row[0]) \
??? .flat_map(CountWindowAverage()) \
??? .print()

env.execute()
# the printed output will be (1,4) and (1,5)

狀態(tài)有效期 (TTL)

任何類型的keyed state都可以有有效期(TTL)。如果配置了TTL且狀態(tài)值已過(guò)期,則會(huì)盡最大可能清除對(duì)應(yīng)的值。所有狀態(tài)類型都支持單元素的TTL。 這意味著列表元素和映射元素將獨(dú)立到期。

在使用狀態(tài) TTL 前,需要先構(gòu)建一個(gè)StateTtlConfig 配置對(duì)象。 然后把配置傳遞到state descriptor中啟用TTL功能。

from pyflink.common.time import Time
from pyflink.common.typeinfo import Types
from pyflink.datastream.state import ValueStateDescriptor, StateTtlConfig

ttl_config = StateTtlConfig \
? .new_builder(Time.seconds(1)) \
? .set_update_type(StateTtlConfig.UpdateType.OnCreateAndWrite) \
? .set_state_visibility(StateTtlConfig.StateVisibility.NeverReturnExpired) \
? .build()

state_descriptor = ValueStateDescriptor("text state", Types.STRING())
state_descriptor.enable_time_to_live(ttl_config)

TTL配置有以下幾個(gè)選項(xiàng):

newBuilder 的第一個(gè)參數(shù)表示數(shù)據(jù)的有效期,是必選項(xiàng)。

TTL 的更新策略(默認(rèn)是 OnCreateAndWrite):

StateTtlConfig.UpdateType.OnCreateAndWrite - 僅在創(chuàng)建和寫入時(shí)更新

StateTtlConfig.UpdateType.OnReadAndWrite - 讀取時(shí)也更新

數(shù)據(jù)在過(guò)期但還未被清理時(shí)的可見性配置如下(默認(rèn)為 NeverReturnExpired):

??? StateTtlConfig.StateVisibility.NeverReturnExpired - 不返回過(guò)期數(shù)據(jù)

??? (注意: 在PyFlink作業(yè)中,狀態(tài)的讀寫緩存都將失效,這將導(dǎo)致一部分的性能損失)

??? NeverReturnExpired 情況下,過(guò)期數(shù)據(jù)就像不存在一樣,不管是否被物理刪除。這對(duì)于不能訪問(wèn)過(guò)期數(shù)據(jù)的場(chǎng)景下非常有用,比如敏感數(shù)據(jù)。

StateTtlConfig.StateVisibility.ReturnExpiredIfNotCleanedUp - 會(huì)返回過(guò)期但未清理的數(shù)據(jù)

??? (注意: 在PyFlink作業(yè)中,狀態(tài)的讀緩存將會(huì)失效,這將導(dǎo)致一部分的性能損失)

??? ReturnExpiredIfNotCleanedUp 在數(shù)據(jù)被物理刪除前都會(huì)返回。

過(guò)期數(shù)據(jù)的清理

默認(rèn)情況下,過(guò)期數(shù)據(jù)會(huì)在讀取的時(shí)候被刪除,例如 ValueState#value,同時(shí)會(huì)有后臺(tái)線程定期清理(如果 StateBackend 支持的話)??梢酝ㄟ^(guò) StateTtlConfig 配置關(guān)閉后臺(tái)清理.

from pyflink.common.time import Time
from pyflink.datastream.state import StateTtlConfig

ttl_config = StateTtlConfig \
? .new_builder(Time.seconds(1)) \
? .disable_cleanup_in_background() \
? .build()

可以配置更細(xì)粒度的后臺(tái)清理策略。當(dāng)前的實(shí)現(xiàn)中 HeapStateBackend 依賴增量數(shù)據(jù)清理,RocksDBStateBackend 利用壓縮過(guò)濾器進(jìn)行后臺(tái)清理。

全量快照時(shí)進(jìn)行清理

可以啟用全量快照時(shí)進(jìn)行清理的策略,這可以減少整個(gè)快照的大小。當(dāng)前實(shí)現(xiàn)中不會(huì)清理本地的狀態(tài),但從上次快照恢復(fù)時(shí),不會(huì)恢復(fù)那些已經(jīng)刪除的過(guò)期數(shù)據(jù)。

該策略可以通過(guò) StateTtlConfig 配置進(jìn)行配置,這種策略在 RocksDBStateBackend 的增量 checkpoint 模式下無(wú)效。

from pyflink.common.time import Time
from pyflink.datastream.state import StateTtlConfig

ttl_config = StateTtlConfig \
? .new_builder(Time.seconds(1)) \
? .cleanup_full_snapshot() \
? .build()

這種清理方式可以在任何時(shí)候通過(guò) StateTtlConfig 啟用或者關(guān)閉,比如在從 savepoint 恢復(fù)時(shí)。

增量數(shù)據(jù)清理

現(xiàn)在僅 Heap state backend 支持增量清除機(jī)制。

增量式清理狀態(tài)數(shù)據(jù),在狀態(tài)訪問(wèn)或/和處理時(shí)進(jìn)行。如果沒(méi)有 state 訪問(wèn),也沒(méi)有處理數(shù)據(jù),則不會(huì)清理過(guò)期數(shù)據(jù)。增量清理會(huì)增加數(shù)據(jù)處理的耗時(shí)。

如果某個(gè)狀態(tài)開啟了該清理策略,則會(huì)在存儲(chǔ)后端保留一個(gè)所有狀態(tài)的惰性全局迭代器。

每次觸發(fā)增量清理時(shí),從迭代器中選擇已經(jīng)過(guò)期的數(shù)進(jìn)行清理。

from pyflink.common.time import Time
from pyflink.datastream.state import StateTtlConfig

ttl_config = StateTtlConfig \
? .new_builder(Time.seconds(1)) \
? .cleanup_incrementally(10, True) \
? .build()

該策略有兩個(gè)參數(shù)。 第一個(gè)是每次清理時(shí)檢查狀態(tài)的條目數(shù),在每個(gè)狀態(tài)訪問(wèn)時(shí)觸發(fā)。

第二個(gè)參數(shù)表示是否在處理每條記錄時(shí)觸發(fā)清理。 Heap backend 默認(rèn)會(huì)檢查 5 條狀態(tài),并且關(guān)閉在每條記錄時(shí)觸發(fā)清理。

在 RocksDB 壓縮時(shí)清理

如果使用 RocksDB state backend,則會(huì)啟用 Flink 為 RocksDB 定制的壓縮過(guò)濾器。RocksDB 會(huì)周期性的對(duì)數(shù)據(jù)進(jìn)行合并壓縮從而減少存儲(chǔ)空間。 Flink 提供的 RocksDB 壓縮過(guò)濾器會(huì)在壓縮時(shí)過(guò)濾掉已經(jīng)過(guò)期的狀態(tài)數(shù)據(jù)。

from pyflink.common.time import Time
from pyflink.datastream.state import StateTtlConfig

ttl_config = StateTtlConfig \
? .new_builder(Time.seconds(1)) \
? .cleanup_in_rocksdb_compact_filter(1000) \
? .build()

Flink 處理一定條數(shù)的狀態(tài)數(shù)據(jù)后,會(huì)使用當(dāng)前時(shí)間戳來(lái)檢測(cè) RocksDB 中的狀態(tài)是否已經(jīng)過(guò)期, 你可以通過(guò) StateTtlConfig.newBuilder(...).cleanupInRocksdbCompactFilter(long queryTimeAfterNumEntries) 方法指定處理狀態(tài)的條數(shù)。

時(shí)間戳更新的越頻繁,狀態(tài)的清理越及時(shí),但由于壓縮會(huì)有調(diào)用 JNI 的開銷,因此會(huì)影響整體的壓縮性能。

RocksDB backend 的默認(rèn)后臺(tái)清理策略會(huì)每處理 1000 條數(shù)據(jù)進(jìn)行一次。

注意:

??? 壓縮時(shí)調(diào)用 TTL 過(guò)濾器會(huì)降低速度。TTL 過(guò)濾器需要解析上次訪問(wèn)的時(shí)間戳,并對(duì)每個(gè)將參與壓縮的狀態(tài)進(jìn)行是否過(guò)期檢查。 對(duì)于集合型狀態(tài)類型(比如 list 和 map),會(huì)對(duì)集合中每個(gè)元素進(jìn)行檢查。

??? 對(duì)于元素序列化后長(zhǎng)度不固定的列表狀態(tài),TTL 過(guò)濾器需要在每次 JNI 調(diào)用過(guò)程中,額外調(diào)用 Flink 的 java 序列化器, 從而確定下一個(gè)未過(guò)期數(shù)據(jù)的位置。

??? 對(duì)已有的作業(yè),這個(gè)清理方式可以在任何時(shí)候通過(guò) StateTtlConfig 啟用或禁用該特性,比如從 savepoint 重啟后。

Operator State算子狀態(tài)

Python DataStream API 仍無(wú)法支持算子狀態(tài)

算子狀態(tài)(或者非 keyed 狀態(tài))是綁定到一個(gè)并行算子實(shí)例的狀態(tài)。Kafka Connector 是 Flink 中使用算子狀態(tài)一個(gè)很具有啟發(fā)性的例子。

Kafka consumer 每個(gè)并行實(shí)例維護(hù)了 topic partitions 和偏移量的 map 作為它的算子狀態(tài)。

當(dāng)并行度改變的時(shí)候,算子狀態(tài)支持將狀態(tài)重新分發(fā)給各并行算子實(shí)例。處理重分發(fā)過(guò)程有多種不同的方案。

在典型的有狀態(tài) Flink 應(yīng)用中你無(wú)需使用算子狀態(tài)。它大都作為一種特殊類型的狀態(tài)使用。用于實(shí)現(xiàn) source/sink,以及無(wú)法對(duì) state 進(jìn)行分區(qū)而沒(méi)有主鍵的這類場(chǎng)景中。

Broadcast State廣播狀態(tài)

Python DataStream API 仍無(wú)法支持廣播狀態(tài)

廣播狀態(tài)是一種特殊的算子狀態(tài)。引入它的目的在于支持一個(gè)流中的元素需要廣播到所有下游任務(wù)的使用情形。在這些任務(wù)中廣播狀態(tài)用于保持所有子任務(wù)狀態(tài)相同。

該狀態(tài)接下來(lái)可在第二個(gè)處理記錄的數(shù)據(jù)流中訪問(wèn)??梢栽O(shè)想包含了一系列用于處理其他流中元素規(guī)則的低吞吐量數(shù)據(jù)流,這個(gè)例子自然而然地運(yùn)用了廣播狀態(tài)。

考慮到上述這類使用情形,廣播狀態(tài)和其他算子狀態(tài)的不同之處在于:

它具有 map 格式,

它僅在一些特殊的算子中可用。這些算子的輸入為一個(gè)廣播數(shù)據(jù)流和非廣播數(shù)據(jù)流,

這類算子可以擁有不同命名的多個(gè)廣播狀態(tài) 。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-686697.html

到了這里,關(guān)于Flink流批一體計(jì)算(19):PyFlink DataStream API之State的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Flink流批一體計(jì)算(11):PyFlink Tabel API之TableEnvironment

    目錄 概述 設(shè)置重啟策略 什么是flink的重啟策略(Restartstrategy) flink的重啟策略(Restartstrategy)實(shí)戰(zhàn) flink的4種重啟策略 FixedDelayRestartstrategy(固定延時(shí)重啟策略) FailureRateRestartstrategy(故障率重啟策略) NoRestartstrategy(不重啟策略) 配置State Backends 以及 Checkpointing Checkpoint 啟用和配置

    2024年02月13日
    瀏覽(47)
  • Flink流批一體計(jì)算(12):PyFlink Tabel API之構(gòu)建作業(yè)

    目錄 1.創(chuàng)建源表和結(jié)果表。 創(chuàng)建及注冊(cè)表名分別為 source 和 sink 的表 使用 TableEnvironment.execute_sql() 方法,通過(guò) DDL 語(yǔ)句來(lái)注冊(cè)源表和結(jié)果表 2. 創(chuàng)建一個(gè)作業(yè) 3. 提交作業(yè)Submitting PyFlink Jobs 1.創(chuàng)建源表和結(jié)果表。 創(chuàng)建及注冊(cè)表名分別為 source 和 sink 的表 其中,源表 source 有一列

    2024年02月13日
    瀏覽(21)
  • Flink流批一體計(jì)算(20):DataStream API和Table API互轉(zhuǎn)

    目錄 舉個(gè)例子 連接器 下載連接器(connector)和格式(format)jar 包 依賴管理 ?如何使用連接器 舉個(gè)例子 StreamExecutionEnvironment 集成了DataStream API,通過(guò)額外的函數(shù)擴(kuò)展了TableEnvironment。 下面代碼演示兩種API如何互轉(zhuǎn) TableEnvironment 將采用StreamExecutionEnvironment所有的配置選項(xiàng)。 建

    2024年02月10日
    瀏覽(24)
  • Flink流批一體計(jì)算(14):PyFlink Tabel API之SQL查詢

    舉個(gè)例子 查詢 source 表,同時(shí)執(zhí)行計(jì)算 Table API 查詢 Table 對(duì)象有許多方法,可以用于進(jìn)行關(guān)系操作。 這些方法返回新的 Table 對(duì)象,表示對(duì)輸入 Table 應(yīng)用關(guān)系操作之后的結(jié)果。 這些關(guān)系操作可以由多個(gè)方法調(diào)用組成,例如 table.group_by(...).select(...)。 Table API 文檔描述了流和批

    2024年02月12日
    瀏覽(23)
  • Flink流批一體計(jì)算(13):PyFlink Tabel API之SQL DDL

    1. TableEnvironment 創(chuàng)建 TableEnvironment TableEnvironment 是 Table API 和 SQL 集成的核心概念。 TableEnvironment 可以用來(lái): ·創(chuàng)建 Table ·將 Table 注冊(cè)成臨時(shí)表 ·執(zhí)行 SQL 查詢 ·注冊(cè)用戶自定義的 (標(biāo)量,表值,或者聚合) 函數(shù) ·配置作業(yè) ·管理 Python 依賴 ·提交作業(yè)執(zhí)行 創(chuàng)建 source 表 創(chuàng)建 sink

    2024年02月12日
    瀏覽(23)
  • Flink流批一體計(jì)算(15):PyFlink Tabel API之SQL寫入Sink

    目錄 舉個(gè)例子 寫入Sink的各種情況 1. 將結(jié)果數(shù)據(jù)收集到客戶端 2. 將結(jié)果數(shù)據(jù)轉(zhuǎn)換為Pandas DataFrame,并收集到客戶端 3. 將結(jié)果寫入到一張 Sink 表中 4. 將結(jié)果寫入多張 Sink 表中 舉個(gè)例子 將計(jì)算結(jié)果寫入給 sink 表 寫入Sink的各種情況 1. 將結(jié)果數(shù)據(jù)收集到客戶端 你可以使用 TableR

    2024年02月11日
    瀏覽(19)
  • 流批一體計(jì)算引擎-7-[Flink]的DataStream連接器

    流批一體計(jì)算引擎-7-[Flink]的DataStream連接器

    參考官方手冊(cè)DataStream Connectors 一、預(yù)定義的Source和Sink 一些比較基本的Source和Sink已經(jīng)內(nèi)置在Flink里。 1、預(yù)定義data sources支持從文件、目錄、socket,以及collections和iterators中讀取數(shù)據(jù)。 2、預(yù)定義data sinks支持把數(shù)據(jù)寫入文件、標(biāo)準(zhǔn)輸出(stdout)、標(biāo)準(zhǔn)錯(cuò)誤輸出(stderr)和 sock

    2023年04月08日
    瀏覽(22)
  • Flink流批一體計(jì)算(1):流批一體和Flink概述

    Apache Flink應(yīng)運(yùn)而生 數(shù)字化經(jīng)濟(jì)革命的浪潮正在顛覆性地改變著人類的工作方式和生活方式,數(shù)字化經(jīng)濟(jì)在全球經(jīng)濟(jì)增長(zhǎng)中扮演著越來(lái)越重要的角色,以互聯(lián)網(wǎng)、云計(jì)算、大數(shù)據(jù)、物聯(lián)網(wǎng)、人工智能為代表的數(shù)字技術(shù)近幾年發(fā)展迅猛,數(shù)字技術(shù)與傳統(tǒng)產(chǎn)業(yè)的深度融合釋放出巨大

    2024年02月10日
    瀏覽(23)
  • flink重溫筆記(五):Flink 流批一體 API 開發(fā)——物理分區(qū)(下)

    flink重溫筆記(五):Flink 流批一體 API 開發(fā)——物理分區(qū)(下)

    前言 :今天是學(xué)習(xí) flink 的第五天啦! 主要學(xué)習(xí)了物理分區(qū)較難理解的部分,在這個(gè)部分的三個(gè)分區(qū)的學(xué)習(xí)中, rescale partition 和 forward partition 其原理可以歸類 pointwise 模式,其他的 partition 其原理可以歸類 all_to_all 模式,而比較有趣的是 custom partitioning,這個(gè)可以進(jìn)行根據(jù)值

    2024年02月19日
    瀏覽(21)
  • flink重溫筆記(四):Flink 流批一體 API 開發(fā)——物理分區(qū)(上)

    flink重溫筆記(四):Flink 流批一體 API 開發(fā)——物理分區(qū)(上)

    前言:今天是學(xué)習(xí)flink的第四天啦!學(xué)習(xí)了物理分區(qū)的知識(shí)點(diǎn),這一次學(xué)習(xí)了前4個(gè)簡(jiǎn)單的物理分區(qū),稱之為簡(jiǎn)單分區(qū)篇! Tips:我相信自己會(huì)越來(lái)會(huì)好的,明天攻克困難分區(qū)篇,加油! 3. 物理分區(qū) 3.1 Global Partitioner 該分區(qū)器會(huì)將所有的數(shù)據(jù)都發(fā)送到下游的某個(gè)算子實(shí)例(subta

    2024年02月19日
    瀏覽(24)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包