Pulsar 與 Kafka 全方位對比(上篇):功能、性能、用例

本文為《Pulsar vs. Kafka — Part 1 — A More Accurate Perspective on Performance, Architecture, and Features》中文譯文版本。

原文首發于:
https://streamnative.io/blog/tech/2020-07-08-pulsar-vs-kafka-part-1

越來越多的消息平臺開始采用實時流技術,這大大促進了 Pulsar 的發展。2020 年,Pulsar 受到持續關注,多家媒體爭相報道;從《財富》百強企業到有前瞻性的初創團隊,凡是開發消息平臺和事件流應用程序的公司都在持續關注 Pulsar,這些關注激勵著 Pulsar 項目和社區的迅猛發展。

同時,Pulsar 的應用場景也越來越廣泛。近期的新聞和文章都在推送 Pulsar 的用戶案例和功能特性,幫助大家進一步了解 Pulsar。

但并非所有的媒體報道都真實準確。前段時間 Confluent 發表了《 Kafka、Pulsar 和 RabbitMQ 對比》的技術文章,Pulsar 社區的小伙伴紛紛來信,讓我們對此文做出回應。Pulsar 成為一項革新技術,社區發展迅猛,我們感謝社區小伙伴們的大力支持,并借此機會和大家深入聊聊 Pulsar。

本系列文章分為上下篇,上篇從性能、架構和功能方面比較 Pulsar 和 Kafka 的區別。下篇主要介紹 Pulsar 的用例、支持與社區等。
Kafka 的文檔比較全面,普及范圍廣泛;我們會加大力度,普及 Pulsar 知識,讓更多人了解 Pulsar。

概 況

組件

Pulsar 有 3 個重要組件:broker、Apache BookKeeper 和 Apache ZooKeeper。Broker 是無狀態服務,客戶端需要連接到 broker 進行核心消息傳遞。而 BookKeeper 和 ZooKeeper 是有狀態服務。

BookKeeper 節點(bookie)存儲消息和游標,ZooKeeper 則只用于為 broker 和 bookie 存儲元數據。另外,BookKeeper 使用 RocksDB 作為內嵌數據庫,用于存儲內部索引,但不能獨立于 BookKeeper 單獨管理 RocksDB。

image

Kafka 采用單片架構模型,將服務與存儲緊密結合,而 Pulsar 采用了多層架構,各層可以單獨管理。Pulsar 在 broker 計算層進行計算,在 bookie 存儲層管理有狀態存儲。

表面上來看,Pulsar 的架構似乎比 Kafka 的架構更為復雜,但實際情況并非如此。架構設計需要權衡利弊,Pulsar 采用了 BookKeeper,因此伸縮性更靈活,速度更快,性能更一致,運維開銷更小。后文,我們會詳細討論這幾個方面。

存儲架構

Pulsar 的多層架構影響了存儲數據的方式。Pulsar 將 topic 分區劃分為分片(segment),然后將這些分片存儲在 Apache BookKeeper 的存儲節點上,以提高性能、可伸縮性和可用性。

image

Pulsar 的無限分布式日志以分片為中心,借助擴展日志存儲(通過 Apache BookKeeper)實現,內置分層存儲支持,因此分片可以均勻地分布在存儲節點上。由于與任一給定 topic 相關的數據都不會與特定存儲節點進行捆綁,因此很容易替換存儲節點或縮擴容。另外,集群中最小或最慢的節點也不會成為存儲或帶寬的短板。

Pulsar 架構能實現分區管理,負載均衡,因此使用 Pulsar 能夠快速擴展并達到高可用。這兩點至關重要,所以 Pulsar 非常適合用來構建關鍵任務服務,如金融應用場景的計費平臺,電子商務和零售商的交易處理系統,金融機構的實時風險控制系統等。

通過性能強大的 Netty 架構,數據從 producers 到 broker,再到 bookie 的轉移都是零拷貝,不會生成副本。這一特性對所有流應用場景都非常友好,因為數據直接通過網絡或磁盤進行傳輸,沒有任何性能損失。

消息消費

Pulsar 的消費模型采用了流拉取的方式。流拉取是長輪詢的改進版,不僅實現了單個調用和請求之間的零等待,還可以提供雙向消息流。通過流拉取模型,Pulsar 實現了端到端的低延遲,這種低延遲比所有現有的長輪詢消息系統(如 Kafka)都低。

使用簡單

運維簡單

在評估特定技術的操作簡便性時,不僅要考慮初始設置,還要考慮長期維護和可伸縮性。需要考慮以下幾項:

  • 要跟上業務增長的速度,擴展集群是否快速、方便?
  • 集群是否對多租戶(對應于多團隊、多用戶)開箱可用?
  • 運維(如替換硬件)是否會影響業務的可用性與可靠性?
  • 是否可以輕松復制數據以實現數據的地理冗余或不同的訪問模式?

長期使用 Kafka 的用戶發現維護 Kafka 時,以上這些都很難做到。多數任務需要借助 Kafka 之外的工具,如用于管理集群再平衡的 cruise control,以及用于復制需求的 Kafka mirror-maker。

由于 Kafka 很難在不同的團隊間共享,很多機構開發了用于支持和管理多個不同集群的工具。這些工具對大規模應用 Kafka 至關重要,但同時也增加了 Kafka 的復雜性。最適合管理 Kafka 集群的工具都是商業軟件,不開源。那這就不意外了,囿于 Kafka 復雜的管理和運維,許多企業轉而購買 Confluent 的商業服務。

相比之下,Pulsar 的目標是簡化運維和可擴展。根據 Pulsar 的性能,對以上問題,我們回復如下:

Q:要跟上業務增長的速度,擴展集群的操作是否迅速便捷?
A:Pulsar 有自動負載均衡的能力,集群中新增了計算和存儲節點,可以自動、立即投入使用。這樣 broker 之間可以遷移 topic 來平衡負載,新 bookie 節點可以立即接受新數據分片的寫入流量,無需手動重新平衡或管理 broker。

Q:集群是否對多租戶(對應于多團隊、多用戶)開箱可用?
A:Pulsar 采用分層架構,租戶和命名空間能夠與機構或團隊形成良好的邏輯映射,Pulsar 通過這種相同的機構支持簡易 ACL、配額、自主服務控制,同時也支持資源隔離,因此集群使用者可以輕松管理、共享集群。

Q:運維任務(如替換硬件)是否會影響業務的可用性與可靠性?
A:Pulsar 的 broker 是無狀態的,替換操作簡單,無需擔心數據丟失。Bookie 節點會自動復制全部未復制的數據分片,而且用于解除和替換節點的工具為內置工具,很容易實現自動化。

Q:是否可以輕松復制數據以實現數據的地理冗余或不同的訪問模式?
A:Pulsar 具有內置的復制功能,可用于無縫跨地域同步數據或復制數據到其他集群,以實現其他功能(如災備、分析等)。

和 Kafka 相比,Pulsar 為流數據的現實問題提供了更完善的解決方案。從這個角度看,Pulsar 擁有更完善的核心功能集,使用簡單,因而允許使用者和開發者專注于業務的核心需求。

文檔與學習

Pulsar 比 Kafka 發展稍晚,Pulsar 的生態系統還不夠完善,文檔和培訓資源也在陸續地補充。在過去的一年半時間里,Pulsar 正在逐步完善這些資料。以下為一些主要成果:

?? Pulsar Summit Virtual Conference 2020
Pulsar 的首次全球峰會,匯集了 36 個主題演講,覆蓋了 25+ 機構,注冊參會者超過 600 人。

?? 2020 年原創 50+ 視頻及培訓版塊
https://streamnative.io/resource#pulsar-summit

?? Pulsar 每周直播及互動教程
https://www.bilibili.com/video/BV1T741147B6

?? 業內領先講師進行專業培訓
https://bit.ly/31NLaCD

?? 與戰略商業伙伴每月舉辦一次網絡研討會
https://www.youtube.com/playlist?list=PLqRma1oIkcWhfmUuJrMM5YIG8hjju62Ev

?? 發布來自騰訊、Yahoo!Japan、OVHCloud、涂鴉智能等多種應用場景的白皮書
https://streamnative.io/resource#white-paper

更多關于 Pulsar 文檔和培訓的內容,參閱 StreamNative 的 Resources 網站。
https://streamnative.io/resource

企業支持

Kafka 和 Pulsar 都提供企業級支持。多個大型供應商(包括 Confluent)為 Kafka 提供企業級支持。StreamNative 為 Pulsar 提供企業級支持,目前處于起步發展階段。StreamNative 為企業提供全面托管的 Pulsar 云服務和 Pulsar 企業級支持服務。

StreamNative 團隊在消息和事件流方面經驗豐富,成長迅速。StreamNative 由 Pulsar 和 BookKeeper 核心成員創建。在 StreamNative 團隊的幫助下,Pulsar 生態系統在短短幾年時間里突飛猛進,得到了戰略合作伙伴的支持,這種支持將會進一步促進 Pulsar 的發展,滿足大量應用場景的需求。在下一篇,我們會詳細介紹這部分內容。

Pulsar 的發展最近有了重大突破。

?? 2020 年 3 月,OVHCloud 和 StreamNative 聯合推出了 KoP(Kafka-on-Pulsar)
通過向現有 Pulsar 集群添加 KoP 協議處理程序,用戶不需要修改代碼,就可以把現有的 Kafka 應用程序和服務遷移到 Pulsar。

?? 2020 年 6 月,中國移動與 StreamNative 宣布推出另一重要產品 —— AoP(AMQP on Pulsar)
使用 AoP,RabbitMQ 應用程序可以充分利用 Pulsar 的重要功能,如使用 Apache BookKeeper 和分層存儲支持無限事件流存儲等。

?? 2020 年 9 月,StreamNative 開源了 MoP(MQTT on Pulsar)
MoP 將 MQTT 協議處理插件引入 Pulsar broker。把 MoP 協議處理插件添加到現有 Pulsar 集群后,用戶不用修改代碼就可以將現有的 MQTT 應用程序和服務遷移到 Pulsar。

這樣 MQTT 應用程序就可以利用 Pulsar 的特性,例如 Apache Pulsar 計算和存儲分離的架構以及 Apache BookKeeper 保存事件流和 Pulsar 分層存儲等特性。

生態集成

隨著 Pulsar 應用場景的迅速增加,Pulsar 社區發展壯大,全球用戶高度參與。Pulsar 社區活躍,積極推動 Pulsar 生態系統的集成應用。過去的六個月,Pulsar 生態系統中官方支持的 connector 數量急劇增長。

為了進一步支持 Pulsar 社區的發展,StreamNative 推出了 StreamNative Hub。StreamNative Hub 支持用戶搜索、下載集成應用,會進一步加速 Pulsar connector 和插件生態系統的發展。
https://hub.streamnative.io/

Pulsar 社區一直與其他社區密切合作,共同開發一系列集成項目,目前多個項目仍在進行中。已經完成的項目如:

Pulsar 社區與 Flink 社區共同開發的 Pulsar-Flink Connector(FLIP-72 的一部分)。
https://github.com/streamnative/pulsar-flink

通過 Pulsar-Spark Connector,用戶可以使用 Apache Spark 處理 Apache Pulsar 中的事件。
https://github.com/streamnative/pulsar-spark

SkyWalking Pulsar 插件集成了 Apache SkyWalking 和 Apache Pulsar,用戶可以通過 SkyWalking 追蹤 Pulsar 消息。
https://github.com/apache/skywalking/tree/master/apm-sniffer/apm-sdk-plugin/pulsar-plugin

多元客戶端庫

目前,Pulsar 官方客戶端支持 7 種語言,而 Kafka 只支持 1 種語言。Confluent 發布博客聲稱 Kafka 目前支持 22 種語言,然而其官方客戶端并不支持這么多種語言,而且有些語言已經不再維護。

根據最新統計,Apache Kafka 官方客戶端只支持 1 種語言。
https://github.com/apache/kafka/tree/trunk/clients/src/main/java/org/apache/kafka/clients

而 Apache Pulsar 官方客戶端支持 7 種語言。
http://pulsar.apache.org/docs/en/client-libraries/

  • Java
  • C
  • C++
  • Python
  • Go
  • .NET
  • Node

Pulsar 還支持由 Pulsar 社區開發的諸多客戶端,如:

  • Rust
  • Scala
  • Ruby
  • Erlang

性能與可用性

吞吐量、延遲與容量

Pulsar 和 Kafka 都被廣泛用于各個企業,也各有優勢,都能通過數量基本相同的硬件處理大流量。部分用戶誤以為 Pulsar 使用了很多組件,因此需要很多服務器來實現與 Kafka 相匹敵的性能。這種想法適用于一些特定硬件配置,但在多數資源配置相同的情況中,Pulsar 的優勢更加明顯,可以用相同的資源實現更好的性能。

舉例來說,Splunk 最近分享了他們選擇 Pulsar 放棄 Kafka 的原因,其中提到“由于分層架構,Pulsar 幫助他們將成本降低了 30% - 50%,延遲降低了 80% - 98%,運營成本降低了 33% - 50%”。
https://www.slideshare.net/streamnative/why-splunk-chose-pulsarkarthik-ramasamy(參考幻燈片第 34 頁)

Splunk 團隊發現 Pulsar 可以更好地利用磁盤 IO,降低 CPU 利用率,同時更好地控制內存。

騰訊等公司選擇 Pulsar 在很大程度上是因為 Pulsar 的性能。在騰訊計費平臺白皮書中提到,騰訊計費平臺擁有百萬級用戶,管理約 300 億第三方托管賬戶,目前正在使用 Pulsar 處理日均數億美元的交易。
https://streamnative.io/whitepaper/case-study-apache-pulsar-tencent-billing

考慮到 Pulsar 可預測的低延遲、更強的一致性和持久性保證,騰訊選擇了 Pulsar。

有序性保證

Apache Pulsar 支持四種不同訂閱模式。單個應用程序的訂閱模式由排序和消費可擴展性需求決定。以下為這四種訂閱模式及相關的排序保證。

  • 獨占(Exclusive)和災備(Failover)訂閱模式都在分區級別支持強序列保證,支持跨 consumer 并行消費同一 topic 上的消息。
  • 共享(Shared)訂閱模式支持將 consumer 的數量擴展至超過分區的數量,因此這種模式非常適合 worker 隊列應用場景。
  • 鍵共享(Key_Shared)訂閱模式結合了其他訂閱模式的優點,支持將 consumer 的數量擴展至超過分區的數量,也支持鍵級別的強序列保證。

更多關于 Pulsar 訂閱模式和相關排序保證的信息,可以參閱:
http://pulsar.apache.org/docs/en/concepts-messaging/#subscriptions

特 性

內置流處理

Pulsar 和 Kafka 對于內置流處理的目標不盡相同。針對較為復雜的流處理,Pulsar 集成了 Flink 和 Spark 這兩套成熟的流處理框架,并開發了 Pulsar Functions 來處理輕量級計算。Kafka 開發并使用 Kafka Streams 作為流處理引擎。

Kafka Streams 異常復雜,用戶要將其作為流處理引擎,需要先弄清楚使用 KStreams 應用程序的場景及方法。對大多數輕量級計算應用場景來說,KStreams 過于復雜。

而 Pulsar Functions 輕松實現了輕量級計算,并允許用戶創建復雜的處理邏輯,無需單獨部署其他系統。Pulsar Functions 還支持原生語言和易于使用的 API。用戶不必學習復雜的 API 就可以編寫事件流應用程序。

最近,Pulsar 改進方案(Pulsar Improvement Proposal,PIP)中介紹了 Function Mesh。Function Mesh 是無服務器架構的事件流框架,結合使用多個 Pulsar Functions 以便構建復雜的事件流應用程序。

Exactly-Once 處理

目前,Pulsar 通過 broker 端去重支持 exactly-once producer。這個重大項目正在開發中,敬請期待!
https://github.com/apache/pulsar/wiki/PIP-6:-Guaranteed-Message-Deduplication

PIP-31 提議 Pulsar 支持事務型消息流,目前正在開發中。這一特性提高了 Pulsar 的消息傳遞語義和處理保證。
https://github.com/apache/pulsar/wiki/PIP-31:-Transaction-Support

在交易型消息流中,每條消息只會寫入一次、處理一次,即便 broker 或 Function 實例出現故障,也不會出現數據重復或數據丟失。交易型消息不僅簡化了使用 Pulsar 或 Pulsar Functions 向應用程序寫入的操作,還擴展了 Pulsar 支持的應用場景。

如果開發順利,Pulsar 2.7.0 版本會支持事務型消息流,預計 2020 年 11 月發布。

Topic(日志)壓縮

Pulsar 支持用戶根據需要選擇數據格式來消費數據。應用程序可以根據需要選擇使用原始數據或壓縮數據。通過按需選擇的方式,Pulsar 允許未壓縮數據通過保留策略,控制數據無限增長,同時通過周期性壓縮生成最新的實物化視圖。內置的分層存儲特性支持 Pulsar 從 BookKeeper 卸載未壓縮數據到云存儲中,從而降低長期存儲的成本。

而 Kafka 不支持用戶使用原始數據。并且,在數據壓縮后,Kafka 會立即刪除原始數據。

用 例

事件流

雅虎最初開發 Pulsar 將其用作統一的發布/訂閱消息平臺(又稱云消息)。現在,Pulsar 不僅是消息平臺,還是消息和事件流的統一平臺。Pulsar 引入了一系列工具,作為平臺的一部分,為構建事件流應用程序提供必要的基礎。Pulsar 支持以下事件流功能:

  • 無限事件流存儲支持通過向外擴展日志存儲(通過 Apache BookKeeper)大規模存儲事件,并且 Pulsar 內置的分層存儲支持高質量、低成本的系統,如 S3、HDFS 等。

  • 統一的發布/訂閱消息模型方便用戶向應用程序中添加消息。這一模型可以根據流量和用戶需求進行伸縮。

  • 協議處理框架、Pulsar 與 Kafka 的協議兼容性(KoP),以及 AMQP (AMQP-on-Pulsar)支持應用程序使用任何現有協議在任一位置生產和消費事件。

  • Pulsar IO 提供了一組與大型生態系統集成的 connector,用戶不需要編寫代碼,即可從外部系統獲取數據。

  • Pulsar 與 Flink 的集成可以全面處理復雜的事件。

  • Pulsar Functions 是一個輕量級無服務器框架,能夠隨時處理事件。

  • Pulsar 與 Presto 的集成(Pulsar SQL),數據專家和開發者能夠使用 ANSI 兼容的 SQL 來分析數據和處理業務。

消息路由

通過 Pulsar IO、Pulsar Functions、Pulsar Protocol Handler,Pulsar 具有完善的路由功能。Pulsar 的路由功能包括基于內容的路由、消息轉換和消息擴充。

和 Kafka 相比,Pulsar 的路由能力更穩健。Pulsar 為 connector 和 Functions 提供了更靈活的部署模型。可以在 broker 中簡單部署,也可以在專用的節點池中部署(類似于 Kafka Streams),節點池支持大規模擴展。Pulsar 還與 Kubernetes 原生集成。另外,可以將 Pulsar 配置為以 pod 的形式來調度 Functions 和 connector 的工作負載,充分利用 Kubernetes 的彈性。

消息隊列

如前文所述,Pulsar 最初的開發目的是作為統一的消息發布/訂閱平臺。Pulsar 團隊深入研究了現有開源消息系統的優缺點,憑借豐富的經驗,設計了統一的消息模型。

Pulsar 消息 API 結合隊列和流的能力,不僅實現了 worker 隊列以輪詢的方式將消息發送給相互競爭的 consumer(通過共享訂閱),還支持事件流:一是基于分區(通過災備訂閱)中消息的順序;二是基于鍵范圍(通過鍵共享訂閱)中消息的順序。用戶可以在同一組數據上構建消息應用程序和事件流應用程序,而無需復制數據到不同的數據系統。

另外,Pulsar 社區還在嘗試使 Apache Pulsar 原生支持不同的消息協議(如 AoP、KoP、MoP),以擴展 Pulsar 處理消息的能力。

結語

Pulsar 社區發展迅猛,隨著 Pulsar 技術的發展和應用場景的增加,Pulsar 生態也在日益壯大。

Pulsar 具有許多優勢,在統一的消息和事件流平臺脫穎而出,成為大眾選擇。和 Kafka 相比,Pulsar 彈性更靈活,在運維和擴展上更為簡單。

新技術的推出和采用都需要一些時間,Pulsar 不僅提供了全套解決方案,安裝后可立即投入生產環境,維護成本低。Pulsar 涵蓋了構建事件流應用程序所需的基礎,集成了豐富的內置功能(包括各種工具)。Pulsar 工具不需要單獨安裝,即可立即使用。

StreamNative 一直致力于開發 Pulsar 新功能,加強現有功能,同時促進社區發展。2020 年我們定下了宏偉目標,目前一切進展順利,期待 11 月發布 Pulsar 2.7.0。

敬請關注本系列文章 Pulsar 與 Kafka 全方位對比(下篇):應用、應用場景、支持與社區。
StreamNative 發起了一個讀者討論
你在使用 Pulsar 過程中,有哪些想要給推薦給大家的使用場景/特性體現呢?

特別致謝

感謝幫助撰寫本文的 Pulsar 社區成員:Jerry Peng、Jesse Anderson、Joe Francis、Matteo Merli、Sanjeev Kulkarni、Addison Higham 等。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380