圖解 | 搞定分布式,程序員進階之路
編程是一門藝術(shù),它的魅力在于創(chuàng)造。
65 哥已經(jīng)工作兩年了,一直做著簡單重復的編程工作,活活熬成了一個只會 CRUD 的打工 boy。
65 哥:總是聽大佬講分布式分布式,什么才是分布式系統(tǒng)呢?
分布式系統(tǒng)是一個硬件或軟件系統(tǒng)分布在不同的網(wǎng)絡計算機上,彼此之間僅僅通過消息傳遞進行通信和協(xié)調(diào)的系統(tǒng)。在一個分布式系統(tǒng)中,一組獨立的計算機展現(xiàn)給用戶的是一個統(tǒng)一的整體,就好像是一個系統(tǒng)似的。系統(tǒng)擁有多種通用的物理和邏輯資源,可以動態(tài)的分配任務,分散的物理和邏輯資源通過計算機網(wǎng)絡實現(xiàn)信息交換。
65 哥:巴拉巴拉,能不能講點人話。俺聽不懂。
那好,下面我們從平常最熟悉的事物開始理解分布式系統(tǒng)如何出現(xiàn),發(fā)展的,并經(jīng)過實踐總結(jié)通用的理論,這些理論成為指導我們?nèi)绾卧O計更完善的分布式系統(tǒng)的基礎。
從此篇文章,你將學習到以下知識:
分享Java技術(shù),不論基礎核心還是分布式、高并發(fā)場景。還是 SpringBoot 、MySQL、Redis、 Spring Cloud 等框架原理和源碼分析。
Web 應用的擴展
為什么會出現(xiàn)分布式應用?
65 哥:這個我也不清楚啊,以前我寫的 web 應用都是直接扔進 Tomcat 中,啟動 Tomcat 就可以訪問了,這肯定不是分布式應用。
嗯,我們就從大家最熟悉 web 后臺應用講起,以前我們的系統(tǒng)訪問量小,業(yè)務也不復雜,一臺服務器一個應用就可以處理所有的業(yè)務請求了,后來我們公司發(fā)達了,訪問量上去了,業(yè)務也拓展了,雖然老板依舊沒有給我們加工資,卻總是埋怨我們系統(tǒng)不穩(wěn)定,扛不住大并發(fā),是可忍孰不可也,加錢,我們要升級。
如果我們的服務器可以無限添加配置,那么一切性能問題都不是問題。
為提高系統(tǒng)處理能力,我們首先想到的擴展方式就是升級系統(tǒng)配置,8 核 cpu 升級為 32 核,64 核,內(nèi)存 64G 升級為 128G,256G,帶寬上萬兆,十萬兆,這就叫做垂直擴展。但這樣的擴展終將無法持續(xù)下去,原因如下。
- 單機系統(tǒng)的處理能力最終會達到瓶頸
- 單機升級的邊際成本將越來越大
沒有什么可以攔住我們編程打工人的步伐。
俗話說,系統(tǒng)撐不住了,就加服務器,一臺不行就加兩臺。
當垂直擴展到達技術(shù)瓶頸或投入產(chǎn)出比超過預期,我們可以考慮通過增加服務器數(shù)量來提高并發(fā)能力,這種方式就是水平擴展。
系統(tǒng)拆分
65 哥:哦,這就是分布式系統(tǒng)了?這么簡單的么。
我勒個呵呵,哪有那么簡單,在水平擴展中,我們增加了服務器數(shù)量,但是如何讓這些服務器像一個整體一樣對外提供穩(wěn)定有效的服務才是關(guān)鍵。既然已經(jīng)有了多臺服務器,我們就要考慮如何將系統(tǒng)部署到到不同的節(jié)點上去。
65 哥:這還不簡單,我將我的 SpringBoot 項目部署到多臺服務器上,前面加個 nginx 就可以了,現(xiàn)在我們的系統(tǒng)都是這樣的,穩(wěn)定高效 perfect。給你畫個架構(gòu)圖(小聲,這個我在學校時就會了。)
哪有什么歲月靜好,只不過是有人在為你負重前行。上面你所認為的簡單,其實有兩個原因:
- 系統(tǒng)分離不徹底,很重要的一點,就是依然在共享一個數(shù)據(jù)庫
- 在這個成熟的體系中,有太多成熟的中間件在為我們服務,比如上面提到的 nginx
系統(tǒng)拆分也有兩種方式,垂直拆分和水平拆分,注意,這里和上面提到的垂直擴展和水平擴展不是處理同一個問題的。(65 哥:哈哈,我知道,世間萬物不外乎縱橫二字)。
系統(tǒng)的垂直拆分,就是將相同的系統(tǒng)部署多套,所有的節(jié)點并沒有任何不同,角色和功能都一樣,它們各自分擔一部分功能請求,這樣整個系統(tǒng)的處理能力的上升了。
從處理 web 請求上來看,垂直拆分的每個節(jié)點都處理一個完整的請求,每個節(jié)點都承擔一部分請求量;
從數(shù)據(jù)存儲的角度看,每個數(shù)據(jù)節(jié)點都存儲相同的業(yè)務數(shù)據(jù),每個節(jié)點存儲一部分數(shù)據(jù)。
系統(tǒng)的水平拆分,就是將系統(tǒng)按不同模塊或角色拆分,不同的模塊處理不同的事情。
從 web 請求上來看,需要多個相互依賴的系統(tǒng)配合完成一個請求,每個節(jié)點處理的需求不一致;
從數(shù)據(jù)存儲角度上來看,每個數(shù)據(jù)節(jié)點都存儲著各自業(yè)務模塊相關(guān)的數(shù)據(jù),它們的數(shù)據(jù)都不一樣。
上面垂直拆分之后各個節(jié)點組成的就是一個集群,而水平拆分各個節(jié)點就是分布式。這就是集群和分布式的區(qū)別。集群除了上面提到的可以提高并發(fā)處理能力外,還可以保證系統(tǒng)的高可用,當一部分節(jié)點失效后,整個系統(tǒng)依舊可以提供完整的服務。分布式也一樣,除了提高并發(fā)能力,解耦系統(tǒng),使系統(tǒng)邊界更清晰,系統(tǒng)功能更內(nèi)聚也是其一大好處,所以在實際的系統(tǒng)中我們往往這兩種方式同時都在使用,而且我們常常提及的分布式系統(tǒng)其實是包含著集群的概念在里面的。
分布式目標
歸納和演繹是人類理性的基石,學習和思考就是不斷的歸納過去的經(jīng)驗,從而得到普遍的規(guī)律,然后將得之的規(guī)律演繹于其他事物,用于指導更好的實踐過程。
上面我們講解了分布式系統(tǒng)的由來,現(xiàn)在我們回顧和總結(jié)一下這個過程。我們引入分布式系統(tǒng)必然是基于現(xiàn)實的需求和目標而來的。
65 哥:那分布式的目標什么呢?
分布式就是為了滿足以下目標而設計的:
- Transparency: 透明性,即用戶是不關(guān)心系統(tǒng)背后的分布式的,無論系統(tǒng)是分布式的還是單機的,對用戶來說都應該是透明的,用戶只需要關(guān)心系統(tǒng)可用的能力。這里的透明性就包括以下方面:
- 訪問透明性:固定統(tǒng)一的訪問接口和方式,不因為分布式系統(tǒng)內(nèi)部的變動而改變系統(tǒng)的訪問方式。
- 位置透明性:外部訪問者不需要知道分布式系統(tǒng)具體的地址,系統(tǒng)節(jié)點的變動也不會影響其功能。
- 并發(fā)透明性:幾個進程能并發(fā)的使用共享資源而不互相干擾。
- 復制透明性:使用資源的多個實例提升可靠性和性能,而用戶和程序員無需知道副本的相關(guān)信息。
- 故障透明性:分布式系統(tǒng)內(nèi)部部分節(jié)點的故障不影響系統(tǒng)的整體功能。
- 移動透明性:資源和客戶能夠在系統(tǒng)內(nèi)移動而不受影響。
- 性能透明性:負載變化時,系統(tǒng)能夠被重新配置以提高性能。
- 伸縮透明性:系統(tǒng)和應用能夠進行擴展而不改變系統(tǒng)結(jié)構(gòu)和應用算法。
- Openness: 開放性,通用的協(xié)議和使用方式。
- Scalability: 可伸縮性,隨著資源數(shù)量的增加和用戶訪問的增加,系統(tǒng)仍然能保持其有效性,該系統(tǒng)就被稱為可伸縮的。分布式系統(tǒng)應該在系統(tǒng)大小,系統(tǒng)管理方面都可擴展。
- Performance: 性能,相對于單體應用,分布式系統(tǒng)應該用更加突出的性能。
- Reliability: 可靠性,與單體系統(tǒng)相比,分布式系統(tǒng)應具有更好安全性,一致性和掩蓋錯誤的能力。
分布式挑戰(zhàn)
分布式的挑戰(zhàn)來源于不確定性。想一想,分布式系統(tǒng)相對于單體應用,多了哪些東西?
65 哥:有了更多的服務節(jié)點,還有就是服務之間的網(wǎng)絡通信。
是的,看來 65 哥同學已經(jīng)懂得思考和分析系統(tǒng)了。分布式系統(tǒng)的所有挑戰(zhàn)就來源于這兩者的不確定性。
1.節(jié)點故障:
節(jié)點數(shù)量越多,出故障的概率就變高了。分布式系統(tǒng)需要保證故障發(fā)生的時候,系統(tǒng)仍然是可用的,這就需要系統(tǒng)能夠感知所有節(jié)點的服務狀態(tài),在節(jié)點發(fā)生故障的情況下將該節(jié)點負責的計算、存儲任務轉(zhuǎn)移到其他節(jié)點。
2.不可靠的網(wǎng)絡:
節(jié)點間通過網(wǎng)絡通信,我們都知道網(wǎng)絡是不可靠的??赡艿木W(wǎng)絡問題包括:網(wǎng)絡分割、延時、丟包、亂序。相比單機過程調(diào)用,網(wǎng)絡通信最讓人頭疼的是超時已經(jīng)雙向通行的不確定性。出現(xiàn)超時狀態(tài)時,網(wǎng)絡通信發(fā)起方是無法確定當前請求是否被成功處理的。
在不可靠的網(wǎng)絡和節(jié)點中,分布式系統(tǒng)依然要保證其可用,穩(wěn)定,高效,這是一個系統(tǒng)最基本的要求。因此分布式系統(tǒng)的設計和架構(gòu)充滿了挑戰(zhàn)。
分而治之
分布式系統(tǒng)就是充分利用更多的資源進行并行運算和存儲來提升系統(tǒng)的性能,這就是分而治之的原理。
65 哥:哦,懂了懂了,那 MapReduce 的 map,Elasticsearch 的 sharding,Kafka 的 partition 是不是都是分布式的分而治之原理。
可以啊,65 哥同學不僅能夠歸納,還能夠舉一反三了。不錯,無論是 map,sharding 還是 partition,甚至 請求路由負載均衡 都是在將計算或數(shù)據(jù)拆分,再分布到不同的節(jié)點計算和存儲,從而提高系統(tǒng)的并發(fā)性。
不同集群類型的分
sharding
同樣是分,在不同領域的,甚至不同實現(xiàn)的系統(tǒng)中通常會有不同的說法。sharding 通常是在數(shù)據(jù)存儲系統(tǒng)中將不同數(shù)據(jù)分布到不同節(jié)點的方式,中文通常翻譯為數(shù)據(jù)分片。
比如在 MongoDB 中,當 MongoDB 存儲海量的數(shù)據(jù)時,一臺機器可能不足以存儲數(shù)據(jù),也可能不足以提供可接受的讀寫吞吐量。這時,我們就可以通過在多臺機器上分割數(shù)據(jù),使得數(shù)據(jù)庫系統(tǒng)能存儲和處理更多的數(shù)據(jù)。
比如在 Elasticsearch 中,每個索引有一個或多個分片,索引的數(shù)據(jù)被分配到各個分片上,相當于一桶水用了 N 個杯子裝。分片有助于橫向擴展,N 個分片會被盡可能平均地(rebalance)分配在不同的節(jié)點上。
partition
partition的概念經(jīng)常在 Kafka 中可以看到,在 kafka 中 topic 是一個邏輯概念,從分布式隊列的角度看,topic 對使用者來說就是一個隊列,topic 在 kafka 的具體實現(xiàn)中,由分布在不同節(jié)點上的 partition 組成,每個 partition 就是根據(jù)分區(qū)算法拆分的多個分區(qū),在 kafka 中,同一個分區(qū)不能被同一個 group 下的多個 consumer 消費,所以一個 topic 有多少 partition 在一定意義上就表示這個 topic 具有多少并發(fā)處理能力。
在 Amazing 的分布式數(shù)據(jù)庫DynamoDB中,一張表在底層實現(xiàn)中也被分區(qū)為不同的 partition。
load balance
負載均衡是高可用網(wǎng)絡基礎架構(gòu)的關(guān)鍵組件,通常用于將工作負載分布到多個服務器來提高網(wǎng)站、應用、數(shù)據(jù)庫或其他服務的性能和可靠性。
比如 nginx 的負載均衡,通過不同的負載均衡分配策略,將 http 請求分發(fā)到 web 應用的不同節(jié)點之上,從而提高應用的并發(fā)處理能力。
比如 dubbo 的客戶端負載能力,可以將 dubbo 請求路由到具體的 producer 提供節(jié)點上,負載均衡是一個完善的 RPC 所應該具有的能力。
在 Spring Cloud 的體系中 Robbin 組件可以通過 Spring Cloud 的各微服務之間通信的負載均衡分配問題,依舊是將請求分發(fā)到集群中的不同節(jié)點上去。
分的策略
無論是分區(qū)還是分片,還是分區(qū)路由,其實都有一些通用的分區(qū)算法,以下的概念可能很多同學都在不同的領域看到過,如上面看到的反向代理服務器 nginx 中,如分布式消息隊列 kafka 中,如 RPC 框架 Dubbo 中,這有時候會讓很多同學感到懵。
其實無論在什么領域中,你只要抓住它在完成的核心功能上就可以理解,它們就是在考慮如何分的問題,把處理請求(即計算)如何均勻地分到不同的機器上,把數(shù)據(jù)如何分配到不同的節(jié)點上。
從大的方向看分有兩種策略,一種可復刻,一種不可復刻。
可復刻,這種策略根據(jù)一定算法分配計算和數(shù)據(jù),在相同的條件下,無論什么時間點得出的結(jié)果相同,因此對于相同條件的請求和數(shù)據(jù)來說是可復刻的,在不同時間點相同的請求和數(shù)據(jù)始終都在統(tǒng)一節(jié)點上。這種策略一般用于有數(shù)據(jù)狀態(tài)在情況。
不可復刻,這種策略使用全隨機方式,即使在相同的條件下,不同時間點得出的結(jié)果也不一致,因此也是不可還原的,如果只是為了可還原,如果通過元數(shù)據(jù)記錄已經(jīng)分配好的數(shù)據(jù),之后需要還原時通過元數(shù)據(jù)就可以準確的得知數(shù)據(jù)所在位置了。
65 哥:這么神奇么?我想看看不同系統(tǒng)都有什么策略。
Dubbo 的負載均衡
Dubbo 是阿里開源的分布式服務框架。其實現(xiàn)了多種負載均衡策略。
Random LoadBalance
隨機,可以按權(quán)重設置隨機概率。在一個截面上碰撞的概率高,但調(diào)用量越大分布越均勻,而且按概率使用權(quán)重后也比較均勻,有利于動態(tài)調(diào)整提供者權(quán)重。
RoundRobin LoadBalance
輪詢,按公約后的權(quán)重設置輪詢比率。存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調(diào)到第二臺時就卡在那,久而久之,所有請求都卡在調(diào)到第二臺上。
LeastActive LoadBalance
最少活躍調(diào)用數(shù),相同活躍數(shù)的隨機,活躍數(shù)指調(diào)用前后計數(shù)差。使慢的提供者收到更少請求,因為越慢的提供者的調(diào)用前后計數(shù)差會越大。
ConsistentHash LoadBalance
一致性 Hash,相同參數(shù)的請求總是發(fā)到同一提供者。當某一臺提供者掛時,原本發(fā)往該提供者的請求,基于虛擬節(jié)點,平攤到其它提供者,不會引起劇烈變動。
Kafka 的分區(qū)分配策略
Kafka 中提供了多重分區(qū)分配算法(PartitionAssignor)的實現(xiàn):
RangeAssignor
RangeAssignor 策略的原理是按照消費者總數(shù)和分區(qū)總數(shù)進行整除運算來獲得一個跨度,然后將分區(qū)按照跨度進行平均分配,以保證分區(qū)盡可能均勻地分配給所有的消費者。對于每一個 Topic,RangeAssignor 策略會將消費組內(nèi)所有訂閱這個 Topic 的消費者按照名稱的字典序排序,然后為每個消費者劃分固定的分區(qū)范圍,如果不夠平均分配,那么字典序靠前的消費者會被多分配一個分區(qū)。
RoundRobinAssignor
RoundRobinAssignor 的分配策略是將消費組內(nèi)訂閱的所有 Topic 的分區(qū)及所有消費者進行排序后盡量均衡的分配(RangeAssignor 是針對單個 Topic 的分區(qū)進行排序分配的)。
StickyAssignor
從字面意義上看,Sticky 是“粘性的”,可以理解為分配結(jié)果是帶“粘性的”——每一次分配變更相對上一次分配做最少的變動(上一次的結(jié)果是有粘性的),其主要是為了實現(xiàn)以下兩個目標:
分區(qū)的分配盡量的均衡
- 每一次重分配的結(jié)果盡量與上一次分配結(jié)果保持一致
- 65 哥:哇,看來優(yōu)秀的系統(tǒng)都是相通的。
副本
副本是解決分布式集群高可用問題的。在集群系統(tǒng)中,每個服務器節(jié)點都是不可靠的,每個系統(tǒng)都有宕機的風險,如何在系統(tǒng)中少量節(jié)點失效的情況下保證整個系統(tǒng)的可用性是分布式系統(tǒng)的挑戰(zhàn)之一。副本就是解決這類問題的方案。副本同樣也可以提高并發(fā)處理能力,比如數(shù)據(jù)在不同的節(jié)點上可以讀寫分離,可以并行讀等。
在這里其實也有很多說法,如 Master-Salve、Leader-Follower、Primary-Shard、Leader-Replica 等等。

Mysql 的主從架構(gòu)
目前,大部分的主流關(guān)系型數(shù)據(jù)庫都提供了主從熱備功能,通過配置兩臺(或多臺)數(shù)據(jù)庫的主從關(guān)系,可以將一臺數(shù)據(jù)庫服務器的數(shù)據(jù)更新同步到另一臺服務器上。這既可以實現(xiàn)數(shù)據(jù)庫的讀寫分離,從而改善數(shù)據(jù)庫的負載壓力,也可以提高數(shù)據(jù)高可用,多份數(shù)據(jù)備份降低了數(shù)據(jù)丟失的風險。
Elasticsearch 的副本機制
在 ES 中有主分片和副本分片的概念。副本分片的主要目的就是為了故障轉(zhuǎn)移,如果持有主分片的節(jié)點掛掉了,一個副本分片就會晉升為主分片的角色從而對外提供查詢服務。
CAP 理論
在理論計算機科學中,CAP 定理(CAP theorem),又被稱作布魯爾定理(Brewer's theorem),它指出對于一個分布式計算系統(tǒng)來說,不可能同時滿足分布式系統(tǒng)一致性、可用性和分區(qū)容錯(即 CAP 中的"C","A"和"P"):
65 哥:什么是一致性、可用性和分區(qū)容錯性能?
一致性 (Consistency)
一致性意味著所有客戶端同時看到相同的數(shù)據(jù),無論它們連接到哪個節(jié)點。要發(fā)生這種情況,每當將數(shù)據(jù)寫入一個節(jié)點時,必須立即將數(shù)據(jù)轉(zhuǎn)發(fā)或復制到系統(tǒng)中的所有其他節(jié)點,然后才能將寫入視為"成功"。
可用性 (Availability)
任何客戶端的請求都能得到響應數(shù)據(jù),不會出現(xiàn)響應錯誤。換句話說,可用性是站在分布式系統(tǒng)的角度,對訪問本系統(tǒng)的客戶的另一種承諾:我一定會給您返回數(shù)據(jù),不會給你返回錯誤,但不保證數(shù)據(jù)最新,強調(diào)的是不出錯。
分區(qū)容錯
分區(qū)即分布式系統(tǒng)中的通信中斷,兩個節(jié)點之間的丟失或暫時延遲的連接。分區(qū)容錯意味著群集必須繼續(xù)工作,盡管系統(tǒng)中的節(jié)點之間存在的通信故障。
這三種性質(zhì)進行倆倆組合,可以得到下面三種情況:
- CA:完全嚴格的仲裁協(xié)議,例如 2PC(兩階段提交協(xié)議,第一階段投票,第二階段事物提交)
- CP:不完全(多數(shù))仲裁協(xié)議,例如 Paxos、Raft
- AP:使用沖突解決的協(xié)議,例如 Dynamo、Gossip
CA 和 CP 系統(tǒng)設計遵循的都是強一致性理論。不同的是 CA 系統(tǒng)不能容忍節(jié)點發(fā)生故障。CP 系統(tǒng)能夠容忍 2f+1 個節(jié)點中有 f 個節(jié)點發(fā)生失敗。
Base 理論
CAP 理論表明,對于一個分布式系統(tǒng)而言,它是無法同時滿足 Consistency(強一致性)、Availability(可用性) 和 Partition tolerance(分區(qū)容忍性) 這三個條件的,最多只能滿足其中兩個。
在分布式環(huán)境中,我們會發(fā)現(xiàn)必須選擇 P(分區(qū)容忍)要素,因為網(wǎng)絡本身無法做到 100% 可靠,有可能出故障,所以分區(qū)是一個必然的現(xiàn)象。也就是說分區(qū)容錯性是分布式系統(tǒng)的一個最基本要求。
CAP 定理限制了我們?nèi)邿o法同時滿足,但我們可以盡量讓 C、A、P 都滿足,這就是 BASE 定理。
BASE 理論是 Basically Available(基本可用),Soft State(軟狀態(tài))和 Eventually Consistent(最終一致性)三個短語的縮寫。即使無法做到強一致性(Strong consistency),但每個應用都可以根據(jù)自身的業(yè)務特點,采用適當?shù)姆绞絹硎瓜到y(tǒng)達到最終一致性(Eventual consistency)。
基本可用 (Basically Available)
基本可用是指分布式系統(tǒng)在出現(xiàn)故障的時候,允許損失部分可用性,即保證核心可用。
電商大促時,為了應對訪問量激增,部分用戶可能會被引導到降級頁面,服務層也可能只提供降級服務,這就是損失部分可用性的體現(xiàn)。
軟狀態(tài) ( Soft State)
什么是軟狀態(tài)呢?相對于原子性而言,要求多個節(jié)點的數(shù)據(jù)副本都是一致的,這是一種“硬狀態(tài)”。
軟狀態(tài)指的是:允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認為該狀態(tài)不影響系統(tǒng)的整體可用性,即允許系統(tǒng)在多個不同節(jié)點的數(shù)據(jù)副本存在數(shù)據(jù)延時。
最終一致性 ( Eventual Consistency)
最終一致性是指系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過一定時間后,最終能夠達到一致的狀態(tài)。
弱一致性和強一致性相反,最終一致性是弱一致性的一種特殊情況。
BASE 理論面向的是大型高可用、可擴展的分布式系統(tǒng)。與傳統(tǒng) ACID 特性相反,不同于 ACID 的強一致性模型,BASE 提出通過犧牲強一致性來獲得可用性,并允許數(shù)據(jù)段時間內(nèi)的不一致,但是最終達到一致狀態(tài)。
分布式是系統(tǒng)擴展的必然方向,分布式系統(tǒng)所遇到的問題是普遍,隨著大量優(yōu)秀的項目在分布式的道路上披荊斬棘,前人已經(jīng)總結(jié)了大量豐富的理論。并且不同領域的分布式系統(tǒng)也層出不窮,我們既應該學習好這些好的理論知識,也應該去多看看不同分布式系統(tǒng)的實現(xiàn),總結(jié)它們的共性,發(fā)現(xiàn)它們在不同領域獨特的亮點權(quán)衡,更重要的,我們應該將所學用于日常項目的實踐當中,也應該在實踐中總結(jié)出更多的規(guī)律理論。
本文轉(zhuǎn)載自微信公眾號「碼哥字節(jié)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系碼哥字節(jié)公眾號。


2024-06-06 08:40:07
2025-03-24 11:30:05
2010-03-08 10:10:57
2012-07-12 09:31:49
2011-03-25 10:53:53




