摘要:使用此值作為其哈希函數(shù)的輸入值,從而生成可從中找到該項目的分區(qū)。在這種情況下,會根據(jù)字符串的哈希值,使用其哈希函數(shù)決定新項目的存儲位置。使用分區(qū)鍵值作為對內(nèi)部哈希函數(shù)的輸入??墒褂米址當?shù)據(jù)類型表示日期或時間戳。
DynamoDB 基本概念本節(jié)主要介紹DynamoDB 基本概念、核心組件、數(shù)據(jù)結(jié)構(gòu)、Api
DynamoDB 是 AWS 獨有的完全托管的 NoSQL Database。它的思想來源于 Amazon 2007 年發(fā)表的一篇論文:Dynamo: Amazon’s Highly Available Key-value Store。在這篇論文里,Amazon 介紹了如何使用 Commodity Hardware 來打造高可用、高彈性的數(shù)據(jù)存儲。想要理解 DynamoDB,首先要理解 Consistent Hashing。Consistent Hashing 的原理如下圖所示:
它的概念是:
我有一個足夠大的Keyspace(2的160次方,比較一下:IPv6是2的128次方),我們記作X。
然后將X放在一個環(huán)形的空間里劃分成大小相等的Y個 Partition,依次循環(huán)排列(如圖),每個 Partition 由一個Vnode(Riak的概念)管理,
當你有M個Database Server(Node),Y個Vnode再平均映射到M個Node上。
當數(shù)據(jù)要插入時,將其主鍵(Hash Key)映射到K中的一個地址(Addr),對應(yīng)到某個Vnode,再進一步對應(yīng)到某個Node,如果這個數(shù)據(jù)需要N個Replica,則將數(shù)據(jù)寫入Addr(Vnode a),Addr + 1(Vnode b), …,Add + N(Vnode n)。
這里,M就是你的Shards,N是Replica。
以后添加新的Node時,映射發(fā)生變化,只需要把相應(yīng)的變化了的Vnode遷移到新的Node上即可。在這種結(jié)構(gòu)下,Sharding/Replica對程序員基本上是透明的。
DynamoDB 核心組件基本 DynamoDB 組件包括:表、項目、屬性
表 - 類似于其他數(shù)據(jù)庫系統(tǒng),DynamoDB將數(shù)據(jù)存儲在表中。表是數(shù)據(jù)的集合。(類似于關(guān)系型數(shù)據(jù)庫中的表)
項目 - 每個表包含多個項目。項目是一組屬性,具有不同于所有其他項目的唯一標識。(類似于其他數(shù)據(jù)庫系統(tǒng)中的行、記錄或元組。)
屬性 - 每個項目包含一個或多個屬性。屬性是基礎(chǔ)的數(shù)據(jù)元素,無需進一步分解。(類似于其他數(shù)據(jù)庫系統(tǒng)中的字段或列。)
下圖是一個名為 People 的表,其中顯示了一些示例項目和屬性:
請注意有關(guān) People 表的以下內(nèi)容:
表中的每個項目都有一個唯一的標識符或主鍵,用于將項目與表中的所有其他內(nèi)容區(qū)分開來。在 People 表中,主鍵包含一個屬性 (PersonID)。
與主鍵外不同,People表是無架構(gòu)的,這表示屬性及其數(shù)據(jù)類型都不需要預(yù)先定義。每個項目都能擁有其自己的獨特屬性。
大多數(shù)屬性是標量類型的,這表示它們只能具有一個值。字符串和數(shù)字是標量的常見示例。
某些項目具有嵌套屬性 (Address)。DynamoDB 支持最高 32級深度的嵌套屬性。
這里,我們將看到第一個概念:主鍵。
主鍵創(chuàng)建表時,除表名稱外,您還必須指定表的主鍵。主鍵唯一標識表中的每個項目,因此,任意兩個項目的主鍵都不相同。
DynamoDB 支持兩種不同類型的主鍵:
分區(qū)鍵 - 簡單的主鍵,由一個稱為分區(qū)鍵的屬性組成。
如果表具有簡單主鍵(只有分區(qū)鍵),DynamoDB 將根據(jù)其分區(qū)鍵值存儲和檢索各個項目。同時,DynamoDB 使用分區(qū)鍵的值作為內(nèi)部哈希函數(shù)的輸入值,從而將項目寫入表中。哈希函數(shù)的輸出值決定了項目將要存儲在哪個分區(qū)。
要從表中讀取某個項目,必須為該項目指定分區(qū)鍵值。DynamoDB 使用此值作為其哈希函數(shù)的輸入值,從而生成可從中找到該項目的分區(qū)。(此時,分區(qū)鍵必須是唯一的,不可重復(fù)。)
下圖顯示了名為 Pets 的表,該表跨多個分區(qū)。表的主鍵為 AnimalType(僅顯示此鍵屬性)。在這種情況下,DynamoDB 會根據(jù)字符串 Dog 的哈希值,使用其哈希函數(shù)決定新項目的存儲位置。請注意,項目并非按排序順序存儲的。每個項目的位置由其分區(qū)鍵的哈希值決定。
分區(qū)鍵和排序鍵 - 稱為復(fù)合主鍵,此類型的鍵由兩個屬性組成。第一個屬性是分區(qū)鍵,第二個屬性是排序鍵。
DynamoDB 使用分區(qū)鍵值作為對內(nèi)部哈希函數(shù)的輸入。來自哈希函數(shù)的輸出決定了項目將存儲到的分區(qū)(DynamoDB 內(nèi)部的物理存儲)。具有相同分區(qū)鍵的所有項目按排序鍵值的排序順序存儲在一起。兩個項目可具有相同的分區(qū)鍵值,但這兩個項目必須具有不同的排序鍵值。
為將某個項目寫入表中,DynamoDB 會計算分區(qū)鍵的哈希值以確定該項目的存儲分區(qū)。在該分區(qū)中,可能有幾個具有相同分區(qū)鍵值的項目,因此 DynamoDB 會按排序鍵的升序?qū)⒃擁椖看鎯υ谄渌椖恐小?/p>
要讀取表中的某個項目,您必須為該項目指定分區(qū)鍵值和排序鍵值。DynamoDB 會計算分區(qū)鍵的哈希值,從而生成可從中找到該項目的分區(qū)。
如果我們查詢的項目具有相同的分區(qū)鍵值,則可以通過單一操作 (Query) 讀取表中的多個項目。DynamoDB 將返回具有該分區(qū)鍵值的所有項目?;蛘撸部梢詫ε判蜴I應(yīng)用某個條件,以便它僅返回特定值范圍內(nèi)的項目。
假設(shè) Pets 表具有由 AnimalType(分區(qū)鍵)和 Name(排序鍵)構(gòu)成的復(fù)合主鍵。
下圖顯示了 DynamoDB 寫入項目的過程,分區(qū)鍵值為 Dog、排序鍵值為 Fido。
Note為讀取 Pets 表中的同一項目,DynamoDB 會計算 Dog 的哈希值,從而生成這些項目的存儲分區(qū)。然后,DynamoDB 會掃描這些排序鍵屬性值,直至找到 Fido。
要讀取 AnimalType 為 Dog 的所有項目,您可以執(zhí)行 Query 操作,無需指定排序鍵條件。默認情況下,這些項目會按存儲順序(即按排序鍵的升序)返回?;蛘撸部梢哉埱笠越敌蚍祷?。
要僅查詢某些 Dog 項目,您可以對排序鍵應(yīng)用條件(例如,僅限 Name 在 A 至 K 范圍內(nèi)的 Dog 項目)。
每個主鍵屬性必須為標量(表示它只能具有一個值)。主鍵屬性唯一允許的數(shù)據(jù)類型是字符串、數(shù)字和二進制。對于其他非鍵屬性沒有任何此類限制。
DynamoDB 會自動分配足夠的存儲,每個分區(qū)鍵值的非重復(fù)排序鍵值無數(shù)量上限。所以即使需要在 Dog 表中存儲數(shù)十億 Pets項目,DynamoDB 也能這一需求。
二級索引DynamoDB支持在一個表上創(chuàng)建一個或多個二級索引。利用 secondary index,除了可對主鍵進行查詢外,還可使用替代鍵查詢表中的數(shù)據(jù)。
DynamoDB 支持兩種索引:
Global secondary index - 一種帶有可能與表中不同的分區(qū)鍵和排序鍵的索引。
Local secondary index - 一種分區(qū)鍵與表中的相同但排序鍵與表中的不同的索引。
最多可以為每個表定義 5 個全局二級索引和 5 個本地二級索引。
下圖顯示了示例 Music 表,該表包含一個名為 GenreAlbumTitle 的新索引
對于Music表,我們不僅可以按 Artist(分區(qū)鍵)或按 Artist 和 SongTitle(分區(qū)鍵和排序鍵)查詢數(shù)據(jù)項。還可以按 Genre 和 AlbumTitle 查詢數(shù)據(jù)。
Note請注意有關(guān) GenreAlbumTitle 索引的以下內(nèi)容:
每個索引屬于一個表(稱為索引的基表)。在上述示例中,Music 是 GenreAlbumTitle 索引的基表。
DynamoDB 將自動維護索引。當添加、更新或刪除基表中的某個項目時,DynamoDB 會添加、更新或刪除屬于該表的任何索引中的對應(yīng)項目。
當創(chuàng)建索引時,可指定哪些屬性將從基表復(fù)制或投影到索引。DynamoDB 至少會將鍵屬性從基表投影到索引中。對于 GenreAlbumTitle 也是如此,只不過此時只有 Music 表中的鍵屬性會投影到索引中。
DynamoDB 數(shù)據(jù)類型DynamoDB 對表中的屬性支持很多不同的數(shù)據(jù)類型。可按以下方式為屬性分類:
標量類型 - 標量類型可準確地表示一個值。標量類型包括數(shù)字、字符串、二進制、布爾值和 null。
文檔類型 - 文檔類型可表示具有嵌套屬性的復(fù)雜結(jié)構(gòu)。文檔類型包括列表和映射。
集類型 - 集類型可表示多個標量值。集類型包括字符串集、數(shù)字集和二進制集。
當創(chuàng)建表或secondary index時,必須指定每個主鍵屬性(分區(qū)鍵和排序鍵)的名稱和數(shù)據(jù)類型。此外,每個主鍵屬性必須定義為字符串、數(shù)字或二進制類型。
標量類型標量類型包括數(shù)字、字符串、二進制、布爾值和 null。
數(shù)據(jù)類型 | 說明 | 示例 |
---|---|---|
字符串 | 字符串是使用 UTF-8 二進制編碼的 Unicode。字符串的長度必須大于零且受限于最大 DynamoDB 項目大小 400 KB。 | "Bicycle" |
數(shù)字 | 數(shù)字可為正數(shù)、負數(shù)或零。數(shù)字最多可精確到 38 位 - 超過此位數(shù)將導(dǎo)致意外 | 300 |
二進制 | 二進制類型屬性可以存儲任意二進制數(shù)據(jù),如壓縮文本、加密數(shù)據(jù)或圖像。DynamoDB 會在比較二進制值時將二進制數(shù)據(jù)的每個字節(jié)視為無符號。二進制屬性的長度必須大于零且受限于最大 DynamoDB 項目大小 400 KB。 | 這是一個采用 Base64 編碼文本的二進制屬性: dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk |
布爾值 | 布爾類型屬性可以存儲 true 或 false。 | true |
空 | 空代表屬性具有未知或未定義狀態(tài)。 | NULL |
如果將主鍵屬性定義為字符串類型屬性,以下附加限制將適用:
對于簡單的主鍵,第一個屬性值(分區(qū)鍵)的最大長度為 2048 字節(jié)。
對于復(fù)合主鍵,第二個屬性值(排序鍵)的最大長度為 1024 字節(jié)
DynamoDB 使用基礎(chǔ)的 UTF-8 字符串編碼字節(jié)整理和比較字符串。例如,“a”(0x61) 大于“A”(0x41),“?”(0xC2BF) 大于“z”(0x7A)。
可使用字符串數(shù)據(jù)類型表示日期或時間戳。執(zhí)行此操作的一種方法是使用 ISO 8601 字符串,如以下示例所示:
2016-02-15
2015-12-21T17:42:34Z
20150311T122706Z
也可以使用數(shù)字數(shù)據(jù)類型表示日期或時間戳
數(shù)字數(shù)字范圍
正數(shù)范圍:1E-130 到 9.9999999999999999999999999999999999999E+125
負數(shù)范圍:-9.9999999999999999999999999999999999999E+125 到 -1E-130
在 DynamoDB 中,數(shù)字以可變長度形式表示。系統(tǒng)會刪減開頭和結(jié)尾的 0。
所有數(shù)字將作為字符串通過網(wǎng)絡(luò)發(fā)送到 DynamoDB,以最大程度地提高不同語言和庫之間的兼容性。但是,DynamoDB 會將它們視為數(shù)字類型屬性以方便數(shù)學(xué)運算。
Note
如果數(shù)字精度十分重要,則應(yīng)使用從數(shù)字類型轉(zhuǎn)換的字符串將數(shù)字傳遞給 DynamoDB。
二進制如果將主鍵屬性定義為二進制類型屬性,以下附加限制將適用:
對于簡單的主鍵,第一個屬性值(分區(qū)鍵)的最大長度為 2048 字節(jié)。
對于復(fù)合主鍵,第二個屬性值(排序鍵)的最大長度為 1024 字節(jié)。
文檔類型在將二進制值發(fā)送到 DynamoDB 之前,我們必須采用 Base64 編碼格式對其進行編碼。收到這些值后,DynamoDB 會將數(shù)據(jù)解碼為無符號字節(jié)數(shù)組,將其用作二進制屬性的長度。
文檔類型包括列表和映射。這些數(shù)據(jù)類型可以互相嵌套,用來表示深度最多為 32 層的復(fù)雜數(shù)據(jù)結(jié)構(gòu)。
只要包含值的項目大小在 DynamoDB 項目大小限制 (400 KB) 內(nèi),列表或映射中值的數(shù)量就沒有限制。
數(shù)據(jù)類型 | 說明 | 示例 |
---|---|---|
列表 | 列表類型屬性可存儲值的有序集合。列表用方括號括起:[ ... ]。列表類似于 JSON 數(shù)組。列表元素中可以存儲的數(shù)據(jù)類型沒有限制,列表元素中的元素也不一定為相同類型。 | FavoriteThings: ["Cookies", "Coffee", 3.14159] |
映射 | 映射類型屬性可以存儲名稱/值對的無序集合。映射用大括號括起:{ ... }。映射類似于 JSON 對象。映射元素中可以存儲的數(shù)據(jù)類型沒有限制,映射中的元素也不一定為相同類型。 | 示例如下 |
{ Day: "Monday", UnreadEmails: 42, ItemsOnMyDesk: [ "Coffee Cup", "Telephone", { Pens: { Quantity : 3}, Pencils: { Quantity : 2}, Erasers: { Quantity : 1} } ] }Note
集DynamoDB 讓您可以使用映射/列表中的單個元素
DynamoDB 支持表示數(shù)字、字符串或二進制值集的類型。集中的所有元素必須為相同類型(
集中的每個值必須是唯一的。集中的值的順序不會保留。不支持空集。
Example (字符串集、數(shù)字集和二進制集)
# 必須是相同的數(shù)據(jù)類型 # 字符串集 ["Black", "Green" ,"Red"] # 數(shù)字集 [42.2, -19, 7.5, 3.14] # 二進制集 ["U3Vubnk=", "UmFpbnk=", "U25vd3k="]DynamoDB API
DynamoDB 的api操作主要用于控制層面、數(shù)據(jù)層面和DynamoDB Streams。
控制層面控制層面 操作可讓我們可以創(chuàng)建和管理DynamoDB表。它們還可讓我們可以使用依賴于表的索引、流和其他對象。
CreateTable - 創(chuàng)建新表?;蛘?,也可以創(chuàng)建一個或多個二級索引并為表啟用 DynamoDB Streams。
DescribeTable - 返回有關(guān)表的信息,例如,表的主鍵架構(gòu)、吞吐量設(shè)置、索引信息等。
ListTables - 返回列表中所有表的名稱。
UpdateTable - 修改表或其索引的設(shè)置、創(chuàng)建或刪除表上的新索引或修改表的 DynamoDB Streams 設(shè)置。
DeleteTable - 從 DynamoDB 中刪除表及其所有依賴對象。
數(shù)據(jù)層面數(shù)據(jù)層面操作可讓我們對表中的數(shù)據(jù)執(zhí)行創(chuàng)建、讀取、更新和刪除(也稱為 CRUD)操作。某些數(shù)據(jù)層面操作還可讓我們可以從secondary index中讀取數(shù)據(jù)。
創(chuàng)建數(shù)據(jù)PutItem - 將單個項目寫入到表中。您必須指定主鍵屬性,但不必指定其他屬性。
BatchWriteItem - 將最多 25 個項目寫入到表中。
讀取數(shù)據(jù)GetItem - 從表中檢索單個項目。我們必須為所需的項目指定主鍵。我們可以檢索整個項目,也可以僅檢索其屬性的子集。
BatchGetItem - 從一個或多個表中檢索最多 100 個項目。
Query - 檢索具有特定分區(qū)鍵的所有項目。我們必須指定分區(qū)鍵值。
可以檢索整個項目,也可以僅檢索其屬性的子集?;蛘?,也可以對排序鍵值應(yīng)用條件,以便只檢索具有相同分區(qū)鍵的數(shù)據(jù)子集。我們可以對表使用此操作,前提是該表同時具有分區(qū)鍵和排序鍵。還可以對索引使用此操作,前提是該索引同時具有分區(qū)鍵和排序鍵。
Scan - 檢索指定表或索引中的所有項目。我們可以檢索整個項目,也可以僅檢索其屬性的子集?;蛘撸覀円部梢詰?yīng)用篩選條件以僅返回感興趣的值并放棄剩余的值。
更新數(shù)據(jù)UpdateItem - 修改項目中的一個或多個屬性。必須為要修改的項目指定主鍵。
刪除數(shù)據(jù)可以添加新屬性以及修改或刪除現(xiàn)有屬性。還可以執(zhí)行有條件更新。也可以實施一個原子計數(shù)器,該計數(shù)器可在不干預(yù)其他寫入請求的情況下遞增或遞減數(shù)字屬性。
DeleteItem - 從表中刪除單個項目。您必須為要刪除的項目指定主鍵。
BatchWriteItem - 從一個或多個表中刪除最多 25 個項目
NoteDynamoDB StreamsBatch 操作比調(diào)用多次單個請求(DeleteItem, GetItem, PutItem)更有效,因為秩序一個網(wǎng)絡(luò)請求即可操作多個項目。
DynamoDB Streams 操作可對表啟用或禁用流,并能允許對包含在流中的數(shù)據(jù)修改記錄的訪問。
ListStreams - 返回所有流的列表,或僅返回特定表的流。
DescribeStream - 返回有關(guān)流的信息,例如,流的 Amazon 資源名稱 (ARN) 和您的應(yīng)用程序可開始讀取前幾條流記錄的位置。
GetShardIterator - 返回一個分區(qū)迭代器,這是我們的應(yīng)用程序用來從流中檢索記錄的數(shù)據(jù)結(jié)構(gòu)。
GetRecords - 使用給定分區(qū)迭代器檢索一條或多條流記錄。
命名規(guī)則DynamoDB 中的表、屬性和其他對象必須具有名稱。名稱應(yīng)該簡明扼要 - 例如,Products、Books 和 Authors 之類的名稱是都是不言而喻的。
下面是 DynamoDB 的命名規(guī)則:
所有名稱都必須使用 UTF-8 進行編碼,并且區(qū)分大小寫。
表名稱和索引名稱的長度必須介于 3 到 255 個字符之間,而且只能包含以下字符:
a-z
A-Z
0-9
_(下劃線)
-(短劃線)
.(圓點)
屬性名稱的長度必須介于 1 到 255 個字符之間。
保留關(guān)鍵字和特殊字符與很多其他數(shù)據(jù)庫管理系統(tǒng)相似,DynamoDB 也具有一系列保留關(guān)鍵字和特殊字符。
有關(guān) DynamoDB 中的保留關(guān)鍵字的完整列表,請參閱 DynamoDB 中的保留關(guān)鍵字。
(哈希)和 :(冒號)在 DynamoDB 中具有特殊含義
DynamoDB允許使用這些關(guān)鍵字和特殊符號用于命名,但我們不建議這么做
有關(guān)更多信息,請參閱 為屬性名稱和值使用占位符。
讀取一致性Amazon DynamoDB 在全世界多個 AWS 區(qū)域可用。每個區(qū)域均與其他 AWS 區(qū)域完全獨立和隔離。
例如,如果我們在 us-east-1 區(qū)域有一個名為 People 的表,并在 us-west-2 區(qū)域有另一個名為 People 的表,則這兩個表將被視為完全獨立的表。
每個 AWS 區(qū)域包含多個不同的稱為“可用區(qū)”的位置。每個可用區(qū)都被設(shè)計成不受其他可用區(qū)故障的影響,并提供低價、低延遲的網(wǎng)絡(luò)連接,以連接到同一區(qū)域其他可用區(qū)。此設(shè)計可保證我們可以在某個區(qū)域的多個可用區(qū)中快速復(fù)制數(shù)據(jù)。
當我們將某個數(shù)據(jù)寫入 DynamoDB 表并收到 HTTP 200 響應(yīng) (OK) 時,該數(shù)據(jù)的所有副本都會更新。但是,要將數(shù)據(jù)傳播到當前 AWS 區(qū)域內(nèi)的所有存儲位置需要耗費一定的時間。該數(shù)據(jù)最終將在上述所有存儲位置中保持一致,通常只需一秒或更短時間。
為了支持各種應(yīng)用程序要求,DynamoDB 同時支持最終一致性 讀取和強一致性 讀取。
最終一致性讀取當我們從 DynamoDB 表中讀取數(shù)據(jù)時,返回的可能不是剛剛完成的寫入操作的結(jié)果。響應(yīng)可能包含某些舊的數(shù)據(jù)。但是,如果我們在短時間后重復(fù)讀取請求,響應(yīng)將返回最新的數(shù)據(jù)。
強一致性讀取當我們請求強一致性讀取時,DynamoDB 會返回具有最新數(shù)據(jù)的響應(yīng),從而反映來自所有已成功的之前寫入操作的更新。但是,如果網(wǎng)絡(luò)延遲或中斷,可能會無法執(zhí)行強一致性讀取。
DynamoDB 默認使用最終一致性讀取。讀取操作(例如 GetItem、Query 和 Scan)提供了一個 ConsistentRead 參數(shù):此參數(shù)設(shè)置為 true,DynamoDB 將在操作過程中使用強一致性讀取。
示例:
{ TableName: "Music", Key: { "Artist": "No One You Know", "SongTitle": "Call Me Today" }, ConsistentRead: true }python 示例
table = db3.Table("Music") response = table.get_item( Key={ "Artist": "The Acme Band", "SongTitle": "Still In Love" }, ConsistentRead=True )
下一篇主要介紹DynamoDB表的基本操作
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/38358.html
摘要:使用此值作為其哈希函數(shù)的輸入值,從而生成可從中找到該項目的分區(qū)。在這種情況下,會根據(jù)字符串的哈希值,使用其哈希函數(shù)決定新項目的存儲位置。使用分區(qū)鍵值作為對內(nèi)部哈希函數(shù)的輸入。可使用字符串數(shù)據(jù)類型表示日期或時間戳。 本節(jié)主要介紹DynamoDB 基本概念、核心組件、數(shù)據(jù)結(jié)構(gòu)、Api DynamoDB 基本概念 DynamoDB 是 AWS 獨有的完全托管的 NoSQL Database。...
摘要:基本的操作包括表操作項目操作和索引管理。將立即執(zhí)行請求。返回一個包含操作結(jié)果的響應(yīng)。表是關(guān)系數(shù)據(jù)庫和中的基本數(shù)據(jù)結(jié)構(gòu)。每秒需對此表執(zhí)行的讀取和寫入次數(shù)。 Amazon DynamoDB 表的基本操作 之前兩篇文章介紹了DynamoDB如何在本地安裝以及基本的工作原理和API,這一節(jié)主要介紹如何使用DynamoDB。 基本的DynamoDB 操作包括表操作、項目操作和索引管理。 首先是鏈...
閱讀 2973·2021-10-20 13:46
閱讀 2520·2021-08-12 13:22
閱讀 2705·2019-08-30 15:54
閱讀 2343·2019-08-30 15:53
閱讀 551·2019-08-30 13:47
閱讀 3583·2019-08-23 16:56
閱讀 1733·2019-08-23 13:02
閱讀 1799·2019-08-23 12:25