认识Cassandra

Cassandra

Apache Cassandra 是一个开源的、分布式、去中心化、弹性可扩展、高可用性、容错、一致性可调、面向行的数据库,它基于 Amazon Dynamo 的分布式设计和 Google Bigtable 的数据模型。它最初由 Facebook 创建,用于储存收件箱等简单格式数据,于2008年开源。此后,由于 Cassandra 良好的可扩展性,被 Digg、Twitter 等知名 Web 2.0 网站所采纳,成为了一种流行的分布式结构化数据存储方案。

截止目前,Apache Cassandra 最新版本为 3.7。

Apache Cassandra 官方网站为 http://cassandra.apache.org/

简介

Cassandra 是 Facebook 于2008年7月在 Google Code 上开源的项目,最早是由 Amazon 前雇员和一位 Microsoft 的工程师写成的。这个系统受到 Amazon Dynamo 的巨大影响(有关 Amazon Dynamo 的介绍,可以查阅论文《Dynamo: Amazon’s Highly Available Key-value Store》,网址为http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)。Cassandra 实现了 Dynamo 风格的副本复制模型和没有单点失效的架构,增加了更加强大的 column family 数据模型。

之后,在2009年1月,Cassandra 被接纳为 Apache 基金会的孵化器项目,并于2010年3月毕业后成为了顶级项目。此时,很多知名公司包括 Facebook、Rackspace、Digg、Twitter 等都成为了 Cassandra 的用户。

有关 Cassandra 论文,最早可见由 Facebook 的 Lakshman 和 Malik 发表的《A Decentralized Structured Storage System》(在线阅读地址为 http://www.cs.cornell.edu/projects/ladis2009/papers/lakshman-ladis2009.pdf)。在 Cassandra 2.0 发布以后,Jonathan Ellis 对该论文相应的做了修改,发表于 http://docs.datastax.com/en/articles/cassandra/cassandrathenandnow.html

伴随着业界对于 Cassandra 商业化、产品化的需求,在2010年4月 Apache Cassandra 项目主席 Jonathan Ellis 以及其同事 Matt Pfeil 成立了一家服务公司,称为 DataStax(原先的名字为 Riptano)。DataStax 雇佣了多名 Cassandra 贡献者,成为了领导和支持 Cassandra 项目的主力。

2015年11月,Cassandra 发布了 3.0 版本,其底层的存储引擎已被重写,支持全局索引,支持 Java 8,并将基于 Thrift 命令行界面给移除了。

Apache Cassandra 具有如下特性:

1. 分布式与去中心化

Cassandra 是分布式的,这意味着它可以运行在多台机器上,并呈现给用户一个一致的整体。

对于很多存储系统(如 MySQL、Bigtable、HBase 等),一旦你开始扩展它,就需要把某些节点设为主节点,其他则作为从节点。但 Cassandra 是去中心的,也就是说每个节点都是一样的,没有节点会承担特殊的管理任务。与主从模式(master-slave)相反,Cassandra 的协议是 P2P 的,并使用 gossip 来维护存活或死亡节点的列表。

去中心化这一事实意味着 Cassandra 不会存在单点失效。Cassandra 集群中的所有节点的功能都完全一样, 所以不存在一个特殊的主机作为主节点来承担协调任务。有时这被叫做“server symmetry(服务器对称)”。

综上所述,因为 Cassandra 是分布式、去中心化的,它不会有单点失效的问题,所以支持高可用性。

2. 弹性可扩展

可扩展性是指系统架构可以让系统提供更多的服务而不降低使用性能的特性。最简单的达到可扩展性的手段,就是给现有的机器增加硬件的容量、内存进行垂直扩展。而水平扩展则需要增加更多机器,每台机器提供全部或部分数据,这样所有主机都不必负担全部业务请求。但软件自己需要有内部机制来保证集群中节点间的数据同步。

弹性可扩展是指水平扩展的特性,意即你的集群可以不间断的情况下,方便扩展或缩减服务的规模。这样,你就不需要重新启动进程,不必修改应用的查询,也无需自己手工重新均衡数据分布。在 Cassandra 里,你只要加入新的计算机,Cassandra 就会自动地发现它并让它开始工作。

3. 高可用与容错

系统的可用性是由满足请求的能力来量度的。但计算机可能会有各种各样的故障,从硬件器件故障到网络中断都有可能。所以它们一般都有硬件冗余,并在发生故障事件的情况下会自动响应并进行热切换。从软件的层次来说,设置多个数据中心,就是“软件冗余”,它能保障在灾难发生时,故障中断的功能在剩余系统上能够进行恢复。

Cassandra 就是高可用的。你可以在不中断系统的情况下替换故障节点,还可以把数据分布到多个数据中心里,从而提供更好的本地访问性能,并且在某一数据中心发生火灾、洪水等不可抗灾难的时候防止系统彻底瘫痪。

4. Tuneable Consistency(可调一致性)

一致性的基本含义是读操作一定会返回最新写入的结果。扩展数据存储系统就意味着我们不得不在数据一致性、节点可用性和分区容错性之间做某些折衷(即 CAP 理论)。Cassandra 常被称作是“最终一致性”的,简单地说,Cassandra 牺牲了一点一致性来换取了完全的可用性。但是 Cassandra 实际更应该表述为“可调一致性”,它允许你来方便地选定需要的一致性水平与可用性水平,在二者间找到平衡点。

因为客户端可以控制在更新到达多少个副本之前,必须阻塞系统。这是通过设置 replication factor(副本因子)来调节与之相对的一致性级别。
通过 replication factor,你可以决定准备牺牲多少性能来换取一致性。 replication factor 是你要求更新在集群中传播到的节点数(注意,更新包括所有增加、删除和更新操作)。

客户端每次操作还必须设置一个 consistency level(一致性级别)参数,这个参数决定了多少个副本写入成功才可以认定写操作是成功的,或者读取过程中读到多少个副本正确就可以认定是读成功的。这里,Cassandra 把决定一致性程度的权利留给了客户自己。

所以,如果需要的话,你可以设定 consistency level 和 replication factor 相等,从而达到一个较高的一致性水平,不过这样就必须付出同步阻塞操作的代价,只有所有节点都被更新完成才能成功返回一次更新。而实际上,Cassandra 一般都不会这么来用,原因显而易见(这样就丧失了可用性目标,影响性能,而且这不是你选择 Cassandra 的初衷)。而如果一个客户端设置 consistency level 低于 replication factor 的话,即使有节点宕机了,仍然可以写成功。

5. Row-Oriented(面向行)

Cassandra 不是真正意义上的“Column-Oriented(面向列)”的数据库而是“Row-Oriented(面向行)”, 它的数据结构不是关系型的,而是一个多维稀疏哈希表。“稀疏”意味着任何一行都可能会有一列或者几列,但每行都不一定(像关系模型那样)和其他行有一样的列。每行都有一个唯一的键值,用于进行数据访问。所以,更确切地说,应该把 Cassandra 看做是一个有索引的、Row-Oriented 的存储系统。

Cassandra 的数据存储结构基本可以看做是一个多维哈希表。这意味着你不必事先精确地决定你的具体数据结构或是你的记录应该包含哪些具体字段。这特别适合处于草创阶段,还在不断增加或修改服务特性的应用。而且也特别适合应用在敏捷开发项目中,不必进行长达数月的预先分析。对于使用 Cassandra 的应用,如果业务发生变化了,只需要在运行中增加或删除某些字段就行了,不会造成服务中断。

当然, 这不是说你不需要考虑数据。相反,Cassandra 需要你换个角度看数据。在 RDBMS 里, 你得首先设计一个完整的数据模型, 然后考虑查询方式, 而在 Cassandra 里,你可以首先思考如何查询数据,然后提供这些数据就可以了。

6. Flexible Schema(灵活的模式)

早期版本的 Cassandra 是忠实于 Bigtable 的设计,而采用的是“schema-free(无模式)”的数据模型,新的 column 可以被动态定义。schema-free 模式的数据库在处理大数据时有非常强的扩展和高性能的优势。但这种模式的主要缺点是在确定数据的含义和数据的格式时存在难点,而这限制了执行复杂查询的能力。

Cassandra Query Language(CQL)正是为了解决上面提到的问题。CQL 它提供了一种通过类似于 Structured Query Language(SQL)的语法来定义的模式。起初,CQL 是基于 Apache Thrift 项目的 schema-free 接口来提供额外的 Cassandra 接口的。在这个过渡阶段,模式是可选的,可以通过 CQL 来定义,也可以通过 Thrift API 来实现在添加新的 column 时动态扩展。

自 Cassandra 3.0 以来,将不推荐采用通过基于 Thrift API 来实现动态创建 column 的方式。Cassandra 的底层存储已重新实现,并与 CQL 更紧密地结合起来。Cassandra 并不限制动态扩展模式,但它的工作方式已经显著的不同了。CQL 的集合,如 list、set,特别是 map 提供在无结构化的格式里面添加内容的能力,从而能扩展现有的模式。CQL 还提供了改变列的类型的能力,以支持 JSON 格式的文本的存储。

因此, Cassandra 是支持“灵活的模式”。

7. 高性能

Cassandra 在设计之初就特别考虑了要充分利用多处理器和多核计算机的性能,并考虑在分布于多个数据中心的大量这类服务器上运行。它可以一致而且无缝地扩展到数百台机器。Cassandra 已经显示出了高负载下的良好表现,在一个非常普通的工作站上,Cassandra 也可以提供非常高的写吞吐量。而如果你增加更多的服务器,你还可以继续保持 Cassandra 所有的特性而无需牺牲性能。

Cassandra 应用场景

尽管 Cassandra 设计精巧、功能出色,但也并非能胜任所有工作。所以,这里我们来介绍一下 Cassandra 最擅长的领域。

1. 大规模部署

Cassandra 的很多精巧设计都专注于高可用、可调一致性、P2P 协议、无缝扩展等,这些都是 Cassandra 的卖点。这些特性在单节点工作时都是没有意义的,更无法展现它的全部能力。所以,你需要做一些评估,考虑你期望的流量、吞吐需求以及 SLA 等。如果你认为有几种关系型数据库可以很好地应付你的流量,提供不错的性能,那可能选关系型数据库更好。简单地说,这是因为 RDBMS 更易于在单机上运行,对你来说也更熟悉。

但是,如果你认为需要至少几个节点才能支撑你的业务,那 Cassandra 就是个不错的选择。如果你的应用可能需要数十个节点,那 Cassandra 可能就是个很棒的选择了。

2. 写密集、统计和分析型工作

Cassandra 是为优异的写吞吐量而特别优化的。许多早期使用 Cassandra 的产品都用于存储用户状态更新、社交网络、建议/评价以及应用统计等。这些应用大都是写多于读的,并且更新可能随时发生并伴有突发的峰值。事实上,支撑应用负载需要很高的多客户线程并发写性能,这正是 Cassandra 的主要特性。

Cassandra 已经被用于开发了多种不同的应用,包括窗口化的时间序列数据库,用于文档搜索的反向索引,以及分布式任务优先级队列。

3. 地区分布

Cassandra 直接支持多地分布,可以很容易配置成将数据分布到多个数据中心的存储方式。如果你有一个全球部署的应用,那么让数据贴近用户会获得不错的性能收益,Cassandra 正适合这种应用场合。

4. 变化的应用

如果你正在“初创阶段”,业务会不断改进,Cassandra 这种灵活的模式的数据模型可能更适合你。这让你的数据库能更快地跟上业务改进的步伐。

Cassandra 架构、数据模型

Cassandra 是设计来处理跨多个节点的大数据工作负载,且不会产生单点故障问题。它的架构是基于对系统和硬件故障也时有发生的理解,即计算机的故障不可避免。Cassandra 通过在集群中的所有节点之间分布均匀的节点,采用 P2P 的方式来定位分布式系统涉及的故障问题。每个节点经常交流有关其自身的状态信息,其他节点利用 P2 gossip 通信协议与集群进行交互。Commit 日志在每个节点上会依次写入活动信息,以确保数据的持久性,然后数据被索引并写入内存结构 memtable 中。memtable 类似于一个回写高速缓存。每次这个内存结构满时,数据就被写入磁盘中的 SSTable 数据文件中。所有的写操作都会自动分区,并在整个集群中进行复制。Cassandra 定期合并使用一种称为 compaction 过程来合并 SSTable,合并过程中会丢弃标记为 tombstone 的数据。为了确保所有的数据在整个集群保持一致,不同的修复机制将被使用。

Cassandra 是一个分区 row 存储数据库,其中 row 被组织成一个必需有主键的 table。 Cassandra 的架构允许任何已授权的用户可以使用 CQL 语言来连接到任何数据中心的任何节点。为了方便使用,CQL 使用了类似的 SQL 的语法来操作表数据。开发人员可以通过 cqlshDevCenter 或者应用语言的驱动程序来访问 CQL。通常情况下,集群都每个应用程序都会有一个 keyspace (密钥空间),由许多不同的 table 组成。

客户端读取或写入请求可以被发送到集群中的任何节点。当客户端通过一个请求连接到一个节点时,则该节点充当协调器用于该客户端特定的操作。协调器充当客户端应用程序和拥有被请求数据的节点之间的代理。协调器来决定在哪些节点能收到请求,这往往是基于集群的配置要求。

Cassandra 包含如下核心构件:

  • Node(节点):存储数据的地方。它是 Cassandra 的基础设施组件。
  • Data center(数据中心):相关节点的集合。数据中心可以是物理数据中心或虚拟数据中心。不同的工作负载应使用单独的数据中心,无论是物理的还是虚拟。复制是由数据中心的设置。使用单独的数据中心可以防止由其他工作负荷受到影响卡桑德拉交易,并保持彼此接近为较低的延迟请求。根据不同的复制因子,可将数据写入到多个数据中心。数据中心必须永远跨越物理位置。
  • Cluster(集群):一个集群包含一个或多个数据中心。它可以跨越物理位置。
  • Commit log(Commit 日志)
    所有数据首先被写入 Commit 日志以确保数据的持久性。当其所有的数据已冲刷到 SSTable 时,它可以存档、删除或回收。
  • SSTable
    SSTable(sorted string table,经排序的字符串表)是 Cassandra 定期写 memtable 的不变的数据文件。SSTable 仅追加并在磁盘上依次存储并保持 Cassandra table。
  • CQL Table
    通过 table row 获取到的有序的 column 集合。table 由 column 和一个主键组成。

用于配置 Apache Cassandra 的核心组件

1. Gossip

P2P 通信协议用于发现和分享在 Cassandra 集群中的其他节点的位置和状态信息。Gossip 信息也保存在每个节点本地,当一个节点重新启动时可以被立即使用。

2. Partitioner(分区工具)

partitioner 用于确定哪些节点先接收第一个数据片段的副本,以及如何分配其他副本到集群的其他节点上。数据的每一 row 由唯一的主键来识别,该主键可以与 partition key(分区键)相同,但也可能包括了其他 clustering column。一个 partitioner 是一个是哈希函数,用于从 row 的主键中派生一个 token。partitioner 使用 token 值,以确定集群中哪些节点来接收该 row 的副本。Murmur3Partitioner 是新的 Cassandra 集群默认分区策略,在大部分情况下,也是在新的集群的正确选择。

必须设置 partitioner,并为每个节点分配 num_tokens 值。token 的分配数量取决于系统的硬件功能。如果不能使用 virtual nodes(vnodes,虚拟节点),请使用 initial_token 设置来代替。

3. Replication factor(副本因子)

replication factor 是指集群副本的总数。replication factor 为 1 意味着一个节点上每个 row 仅有一个副本;为 2 意味着 每个 row 有2个副本,且每个副本位于不同节点上。所有副本都同样重要,不区分是否是主副本。您需要为每个数据中心定义 replication factor。通常应设置策略大于1,但不超过集群中节点总数。

4. Replica placement strategy(副本放置策略)

Cassandra 存储数据的副本到多个节点,以确保可靠性和容错性。复制策略决定哪些节点需要放置到副本上。第一个数据的副本是简单的第一拷贝,它并不是唯一的。强烈建议大多数部署情况下使用 NetworkTopologyStrategy ,因为它在需要时更容易扩展到多个数据中心。

当创建一个 keyspace(密钥空间),你必须定义副本放置策略和副本数。

5. Snitch

snitch 定义了数据中心的计算机组以及复制策略用于放置副本的机架(拓扑)。

当你创建一个集群时,必须配置一个 snitch。所有 snitch 使用动态 snitch 层,来监控性能,并选择最佳副本来用于读取。它是默认是启用的,并推荐在大多数部署情况下使用。在 cassandra.yaml 配置文件里面来配置每个节点的动态 snitch 阈值。

默认 SimpleSnitch 不能识别的数据中心或机架的信息,可以在公共云的单数据中心部署或单区中使用它。建议在生产环境中使用 GossipingPropertyFileSnitch ,它定义了一个节点的数据中心和机架,并且使用 gossip 来传播该信息到其他节点。

6. cassandra.yaml 配置文件

主配置文件用于设置集群的初始化属性,比如 table 参数的缓存、调节属性和资源利用率、超时设置、客户端连接、备份、安全等。

默认情况下,节点被配置用于存储受其管理的设置在 cassandra.yaml 文件的目录下的数据。

在集群的生产部署环境,可以修改 commitlog-directory 目录到与 data_file_directories 不同的磁盘驱动下。

7. 系统 keyspace table 属性

你可以通过基本的编程方式来设置每个 keyspace 或 table 的存储配置属性,或者使用客户端应用,比如 CQL。

Cassandra 安装、配置、使用

本节将演示 Apache Cassandra 安装、配置,以及通过命令行来使用 Cassandra。

1. 前置条件

2. 从编译包来安装

tar -xvf apache-cassandra-3.6-bin.tar.gz cassandra

解压后的目录名为 apache-cassandra-3.6

  • 可以选择添加 apache-cassandra-3.6\bin 到您的路径。
  • 通过执行命令行bin/cassandra -f来在前台启动 Cassandra 按“Ctrl-C”来停止 Cassandra。通过执行命令行bin/cassandra来在后台启动 Cassandra。调用 kill pidpkill -f CassandraDaemon来停止 Cassandra,其中 pid 是 Cassandra 的进程 ID,您可以通过pgrep -f CassandraDaemon来查询。
  • 调用bin/nodetool status来验证 Cassandra 是否在运行。
  • 配置文件位于在conf子目录。
  • 自 Cassandra 2.1 以来,日志和数据目录分别位于logsdata子目录下。旧版本默认在 /var/log/cassandra/var/lib/cassandra。由于这一点,就必须要么使用 root 权限或改变conf/ cassandra.yaml中当前用户所使用的用户目录。

3. 从 Debian 包来安装

  • 添加 Cassandra 的 repository(仓库)到 /etc/apt/sources.list.d/cassandra.sources.list,例如 3.6 版本的配置如下:
echo "deb http://www.apache.org/dist/cassandra/debian 36x main" | sudo tee -a /etc/apt/sources.list.d/cassandra.sources.list
  • 更新 repository
sudo apt-get update
  • 如果遇到如下错误:
GPG error: http://www.apache.org 36x InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 749D6EEC0353B12C

就按如下方式来添加公钥749D6EEC0353B12C(该密钥要根据你实际的出错信息来获取):

gpg --keyserver pgp.mit.edu --recv-keys 749D6EEC0353B12C
gpg --export --armor 749D6EEC0353B12C | sudo apt-key add -

并再次执行 sudo apt-get update

  • 安装 Cassandra:
sudo apt-get install cassandra
  • 执行 sudo service cassandra start来启动 Cassandra,执行 sudo service cassandra stop来停止。
  • 执行nodetool status来验证 Cassandra 是否在运行。
  • 默认配置文件路径在/etc/cassandra
  • 默认的日志和数据目录在/var/log/cassandra//var/lib/cassandra

4. 配置集群

上述运行一个单节点 Cassandra,但若要部署集群,还要进行一些列参数的配置。

Cassandra 的配置文件在安装文件的conf目录下, 对于包,配置文件将位于/etc/cassandra

(1)主运行属性

大多数配置都在 cassandra.yaml文件中配置,你至少需要配置下面的属性:

  • cluster_name:集群的名称;
  • seeds:用逗号分隔的集群种子的 IP 地址列表;
  • storage_port:这项不一定要改,但请确保没有防火墙阻止此端口;
  • listen_address:您的节点的 IP 地址,通过它来让其他节点与该节点进行通信。或者,您也可以设置listen_interface告诉 Cassandra 哪些接口可以使用,使用哪个连续的地址。设置一个即可,不能同时使用。
    native_transport_port:作为storage_port,确保此端口不会被阻止通过防火墙的客户端将与卡桑德拉此端口上进行通讯。

(2)更改目录位置

下面是属性是控制目录的位置。

  • data_file_directories:一个或多个数据文件位置的目录;
  • commitlog_directory:commit log 文件所在的目录;
  • saved_caches_directory:其中保存的缓存的位置目录;
  • hints_directory: hints 所在的目录。

由于性能原因,如果你有多个磁盘,考虑将 commit log 和数据文件放在不同的磁盘。

(3)环境变量

可以在cassandra-env.sh进行 JVM 参数的设置,如堆大小等。您可以添加任何额外的 JVM 命令行参数到 JVM_OPTS环境变量,当 Cassandra 启动时,这些参数将被传递给 JVM。

(4)日志

日志框架是使用的 logback。可以修改logback.xml来修改日志属性。默认日志 INFO 级别是记录在 system.log 文件,而 debug 级别记录在debug.log。当 Cassandra 是在前台运行时,INFO 级别的信息会打印到控制台。

5. 插入和查询

使用 CQL 来进行插入和查询操作。为了使用 CQL,首先要连接到集群,可以使用 cqlsh 或者客户端应用的驱动。

(1)使用 CQLSH

cqlsh 是通过 CQL 与 Cassandra 交互的命令行 shell。该可执行命令,可以在bin/目录找到。例如,使用它连接到指定的单个节点:

$ bin/cqlsh localhost
Connected to Test Cluster at localhost:9042.
[cqlsh 5.0.1 | Cassandra 3.8 | CQL spec 3.4.2 | Native protocol v4]
Use HELP for help.
cqlsh> SELECT cluster_name, listen_address FROM system.local;

 cluster_name | listen_address
--------------+----------------
 Test Cluster |      127.0.0.1

(1 rows)
cqlsh>

可以参见 http://cassandra.apache.org/doc/latest/tools/cqlsh.html 来了解更多 cqlsh 的用法。

(2)使用客户端应用的驱动

很多语言都提供了客户端的驱动。在选择驱动时,需要验证 Cassandra 版本是否支持该驱动。

完整的驱动列表,可以参见 http://cassandra.apache.org/doc/latest/getting_started/drivers.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容