集中式日志分析平台 - ELK Stack - 部署篇

前言

调研了ELK技术栈,发现新一代的logstash-forward即Filebeat,使用了golang,性能超logstash,部署简单,占用资源少,可以很方便的和logstash和ES对接,作为日志文件采集组件。所以决定使用ELK+Filebeat的架构进行平台搭建。Filebeat是Beats家族的一员,后续可以使用Packetbeat进行网络数据采集、Winlogbeat进行Windosw事件采集、Heartbeat进行心跳采集、Metricbeat进行系统指标采集。这种架构解决了 Logstash 在各服务器节点上占用系统资源高的问题。相比 Logstash,Beats 所占系统的 CPU 和内存几乎可以忽略不计。另外,Beats 和 Logstash 之间支持 SSL/TLS 加密传输,客户端和服务器双向认证,保证了通信安全。

各组件承担的角色和功能:

  • Elasticsearch:分布式搜索和分析引擎,具有高可伸缩、高可靠和易管理等特点。基于 Apache Lucene 构建,能对大容量的数据进行接近实时的存储、搜索和分析操作。通常被用作某些应用的基础搜索引擎,使其具有复杂的搜索功能;
  • Logstash:数据处理引擎,它支持动态的从各种数据源搜集数据,并对数据进行过滤、分析、丰富、统一格式等操作,然后存储到 ES;
  • Kibana:数据分析和可视化平台。与 Elasticsearch 配合使用,对数据进行搜索、分析和以统计图表的方式展示;
  • Filebeat:ELK 协议栈的新成员,一个轻量级开源日志文件数据搜集器,使用 golang 基于 Logstash-Forwarder 源代码开发,是对它的替代。在需要采集日志数据的 server 上安装 Filebeat,并指定日志目录或日志文件后,Filebeat 就能读取数据,迅速发送到 Logstash 进行解析。

ELK 常用架构及使用场景介绍

在这个章节中,我们将介绍几种常用架构及使用场景。

All-In-One

在这种架构中,只有一个 Logstash、Elasticsearch 和 Kibana 实例,集中部署于一台服务器。Logstash 通过输入插件从多种数据源(比如日志文件、标准输入 Stdin 等)获取数据,再经过滤插件加工数据,然后经 Elasticsearch 输出插件输出到 Elasticsearch,通过 Kibana 展示。详见图 1。

All-in-One

这种架构非常简单,使用场景也有限。初学者可以搭建这个架构,了解 ELK 如何工作。

Logstash 分布式采集

这种架构是对上面架构的扩展,把一个 Logstash 数据搜集节点扩展到多个,分布于多台机器,将解析好的数据发送到 Elasticsearch server 进行存储,最后在 Kibana 查询、生成日志报表等。详见图 2。

Logstash 分布式采集

这种结构因为需要在各个服务器上部署 Logstash,而它比较消耗 CPU 和内存资源,所以比较适合计算资源丰富的服务器,否则容易造成服务器性能下降,甚至可能导致无法正常工作。

Beats 分布式采集

这种架构引入 Beats 作为日志搜集器。目前 Beats 包括四种:

  • Packetbeat(搜集网络流量数据);
  • Topbeat(搜集系统、进程和文件系统级别的 CPU 和内存使用情况等数据);
  • Filebeat(搜集文件数据);
  • Winlogbeat(搜集 Windows 事件日志数据)。

Beats 将搜集到的数据发送到 Logstash,经 Logstash 解析、过滤后,将其发送到 Elasticsearch 存储,并由 Kibana 呈现给用户。详见图 3。

Beats 分布式采集

这种架构解决了 Logstash 在各服务器节点上占用系统资源高的问题。相比 Logstash,Beats 所占系统的 CPU 和内存几乎可以忽略不计。另外,Beats 和 Logstash 之间支持 SSL/TLS 加密传输,客户端和服务器双向认证,保证了通信安全。

因此这种架构适合对数据安全性要求较高,同时各服务器性能比较敏感的场景。

引入消息队列机制的 Logstash 分布式架构

这种架构使用 Logstash 从各个数据源搜集数据,然后经消息队列输出插件输出到消息队列中。目前 Logstash 支持 Kafka、Redis、RabbitMQ 等常见消息队列。然后 Logstash 通过消息队列输入插件从队列中获取数据,分析过滤后经输出插件发送到 Elasticsearch,最后通过 Kibana 展示。详见图 4。

引入消息队列机制的 Logstash 分布式架构

这种架构适合于日志规模比较庞大的情况。但由于 Logstash 日志解析节点和 Elasticsearch 的负荷比较重,可将他们配置为集群模式,以分担负荷。引入消息队列,均衡了网络传输,从而降低了网络闭塞,尤其是丢失数据的可能性,但依然存在 Logstash 占用系统资源过多的问题。

引入消息队列机制的 Filebeat + Logstash 分布式架构

截至到我们调研为止,Filebeat 已经支持 kafka 作为 ouput,5.2.1 版本的 Logstash 已经支持 Kafka 作为 Input,和上面的架构不同的地方仅在于,把 Logstash 日志搜集发送替换为了 Filebeat。这种架构是当前最为完美的,有极低的客户端采集开销,引入消息队列,均衡了网络传输,从而降低了网络闭塞,尤其是丢失数据的可能性。

引入消息队列机制的 Filebeat + Logstash 分布式架构

对于绿湾的架构选型来说,高质量的数据传输、日志采集的低资源开销都需要考虑,同时,也需要logstash强大的插件支持灵活的日志数据过滤处理。确定采用引入消息队列机制的 Filebeat + Logstash 分布式架构

接下来我们进行初步的探视,利用测试环境体验下ELK Stack + Filebeat,测试环境我们就不进行 Kafka 的配置了,因为他的存在意义在于提高可靠性。

测试环境

机器分布

IP Role
172.16.134.2 Logstash, ES, Kibana
172.16.134.3 Filebeat
172.16.134.8 Filebeat

浏览器支持

Kibana 4.x 不支持 IE9 及以下;Kibana 3.1 虽然支持 IE9,但是不支持 Safari(iOS)和 Chrome(Android)。具体对浏览器的支持,请看这里

部署步骤

ELK 官网对于每种软件提供了多种格式的安装包(zip/tar/rpm/DEB),以 Linux 系列系统为例,如果直接下载 RPM,可以通过 rpm -ivh path_of_your_rpm_file直接安装成系统 service。以后就可以使用 service 命令启停。比如service elasticsearch start/stop/status。很简单,但缺点也很明显,就是不能自定义安装目录,相关文件放置比较分散。

实际使用中更常用是使用 tar 包安装,每种软件产品的安装过程非常相似。

Step1. SSH免密钥

假设所有步骤都在admin账户下执行,所有服务器的admin账户密码统一,需要打通172.16.134.2至所有agent的SSH免密登录,假设list_all已经包含了所有agent机器的列表:

172.16.134.2
172.16.134.3
172.16.134.8

进行密钥打通:

ssh-keygen
for agent in `cat list_all`;do ssh-copy-id -i /home/admin/.ssh/id_rsa.pub admin@${agent};done;

Step2. JDK安装

JDK 是 IBM Java 8。ELK 需要 Oracle 1.7(或者是 OpenJDK 1.7) 及以上,如果是 IBM Java,则需要 8 及以上的版本。具体信息

pssh -h list_all "sudo yum install -y java-1.8.0-openjdk.x86_64"

修改环境变量:

# .bash_profile 
# Get the aliases and functions 
if [ -f ~/.bashrc ]; then 
    . ~/.bashrc 
fi 
# User specific environment and startup programs 
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.65-3.b17.el7.x86_64
PATH=$JAVA_HOME/bin:$PATH 
export PATH JAVA_HOME

分发环境变量配置:

pscp -h list_all ~/.bash_profile /tmp 
pssh -h list_all "sudo cp /tmp/.bash_profile ~/"

Step3. 服务安装

安装ElasticSearch

下载安装包,如果待安装机器能访问外网,可以直接用以下命令下载安装包。

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.1.tar.gz

否则下载好后用 ftp 客户端等工具把包传过去。

解压到172.16.134.2指定目录/home/admin/soft

tar zxvf elasticsearch-5.2.1.tar.gz -C /home/admin/soft/

这时就能在 /home/admin/soft 下看到刚才解压出来的 elasticsearch-5.2.1 文件夹。

修改配置config/elasticsearch.yml

cluster.name: lw-test
node.name: v134002.yn1.lwsite.net
path.data: /home/admin/soft/elasticsearch-5.2.1/data
path.logs: /home/admin/soft/elasticsearch-5.2.1/logs
network.host: 172.16.134.2
http.port: 9200

Elasticsearch默认使用混合mmapfs / niofs目录来存储其索引。 对mmap计数的默认操作系统限制可能过低,这可能导致内存不足异常。修改内核参数vm.max_map_count

sudo sysctl -w vm.max_map_count=262144
sudo vim /etc/sysctl.conf
vm.max_map_count = 262144

确认内核参数是否生效:

sysctl vm.max_map_count

修改 /etc/security/limits.conf,添加:

admin soft nofile 65536
admin hard nofile 65536

修改 /etc/security/limits.d/90-nproc.conf,添加:

admin      soft    nproc     2048

重新以admin登录后运行:

/home/admin/soft/elasticsearch-5.2.1/bin/elasticsearch &

验证是否启动:

curl 'http://172.16.134.2:9200'

看到如下输出表示启动成功:

{
  "name" : "luOq_eh",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "mIcflXKsR3-ER66MCTSJzA",
  "version" : {
    "number" : "5.2.1",
    "build_hash" : "db0d481",
    "build_date" : "2017-02-09T22:05:32.386Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.1"
  },
  "tagline" : "You Know, for Search"
}

可以看到,它跟其他的节点的传输端口为9300,接受HTTP请求的端口为9200。

安装ElasticSearch Head (可选)

Head是一个用浏览器跟ES集群交互的插件,可以查看集群状态、集群的doc内容、执行搜索和普通的Rest请求等,本文不复述,这个不是重点。

安装Logstash

下载安装包,如果待安装机器能访问外网,可以直接用以下命令下载安装包。

wget https://artifacts.elastic.co/downloads/logstash/logstash-5.2.1.tar.gz

否则下载好后用 ftp 客户端等工具把包传过去。

解压到172.16.134.2指定目录/home/admin/soft

tar -zxvf logstash-5.2.1.tar.gz -C /home/admin/soft

一个Logstash的pipeline由3部分组成:input, filter, output。

Basic Logstash Pipeline

为了进行安装完成后的测试,我们运行下最基本的pipeline:

cd logstash-5.2.1
bin/logstash -e 'input { stdin { } } output { stdout {} }'

-e 可以允许进行命令行的直接配置,而无需进行文件配置。这个pipeline例子从标准输入获取数据 stdin,并把结构化数据输出到标准输出stdout。在启动后,看到日志Pipeline main started后,在终端中输入hello world,可以在终端中看到对应输出:

hello world
2017-02-18T09:48:22.414Z v134002.yn1 hello world

在我们的架构中,Logstash的input是beat,output是ES,需要对应的插件。

安装beat input插件:

./bin/logstash-plugin prepare-offline-pack logstash-input-beats
./bin/logstash-plugin install file:///home/admin/soft/logstash-5.2.1/logstash-offline-plugins-5.2.1.zip

配置 5044 端口作为 Filebeat 的连接和创建 ES 索引。修改 logstash.conf 配置文件,保存在 config 目录:

input {
  beats {
    port => 5044
  }
}

output {
  elasticsearch {
    hosts => "172.16.134.2:9200"
    manage_template => false
    index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}"
    document_type => "%{[@metadata][type]}"
  }
}

Logstash 使用该配置使用 ES 的索引,和 Filebeat 做的事情是一样的,不过拥有了额外的缓存以及强大丰富的插件库。

启动 logstash :

./bin/logstash -f config/logstash.conf &
安装Kibana

Kibana 从 ES 获取数据做前端的可视化展示。 它提供了用户体验极佳的高定制化 UI,可以灵活配置出你需要的 Dashboard。 Dashboard 可以轻易的保存、链接和分享。

测试环境,笔者把 Kibana 和 ES 进行了混部,但是在实际生产环境中是没有必要的。我们可以通过配置文件 config/kibana.yml 中的URL(IP:PORT) 去指定需要访问的 ES 服务端。

curl -L -O https://artifacts.elastic.co/downloads/kibana/kibana-5.2.1-linux-x86_64.tar.gz
tar xzvf kibana-5.2.1-linux-x86_64.tar.gz
cd kibana-5.2.1-linux-x86_64/
./bin/kibana

修改配置 config/kibana.yml

elasticsearch.url: "http://172.16.134.2:9200"
server.host: "172.16.134.2"

启动服务:

./bin/kibana &

在浏览器中访问,确认是否正常启动:

http://172.16.134.2:5601/
安装Filebeat

在 172.16.134.3, 172.16.134.8 上进行Filebeat的安装,采集 Filebeat 自身的运行日志:/home/admin/soft/filebeat-5.2.1-linux-x86_64/logs/filebeat

在安装之前,需要确认以上服务已经正常运行:

  • 存储和索引数据的 Elasticsearch 已经启动。
  • UI 展示的 Kibana 已经启动。
  • 写入和过滤数据的 Logstash 已经启动。

下载安装包,安装服务:

wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.2.1-linux-x86_64.tar.gz
tar zxvf filebeat-5.2.1-linux-x86_64.tar.gz -C /home/admin/soft/

修改配置:

cp filebeat.full.yml filebeat.yml

# 修改配置
filebeat.prospectors:
- input_type: log
  paths:
    - /home/admin/soft/filebeat-5.2.1-linux-x86_64/logs/filebeat
output.logstash:
  hosts: ["172.16.134.2:5044"]

logging.level: debug 这个配置一般情况下不要开,因为会把所有 message 都会明文打印出来,一来不安全,二来磁盘压力大。
测试配置是否正确:

./filebeat -configtest -e

有如下输出表示正常:

Config OK

在 Elasticsearch 中, Index Pattern 用于定义字段应如何分析的设置和映射。Filebeat 的默认 Index Pattern 由软件包安装。 如果在 filebeat.yml 配置文件中接受模板加载的默认配置,则 Filebeat 在成功连接到Elasticsearch后会自动加载模板。 如果模板已存在,默认不会覆盖,但是可以通过配置进行覆盖。如果要禁用自动模板加载,或者要加载自己的模板,可以在Filebeat配置文件中更改模板加载的设置。 如果选择禁用自动模板加载,则需要手动加载模板。

配置模板加载 - 仅Elasticsearch输出支持。

手动加载模板 - Logstash输出所需。

由于我们需要的是输出到 Logstash,所以我们使用手动模板加载:

curl -XPUT 'http://172.16.134.2:9200/_template/filebeat' -d@/home/admin/soft/filebeat-5.2.1-linux-x86_64/filebeat.template.json

如果已经使用 Filebeat 将数据索引到 Elasticsearch 中,则索引可能包含旧文档。 加载 Index Pattern 后,您可以从filebeat- * 中删除旧文档,以强制 Kibana 查看最新的文档。 使用此命令:

curl -XDELETE 'http://172.16.134.2:9200/filebeat-*'

启动服务:

./filebeat start &

如果对于生产环境,我们应该用 systemd 来管理进程,修改 /usr/lib/systemd/system/filebeat.service

[Unit]
Description=Filebeat
Documentation=https://www.elastic.co/guide
After=network.target

[Service]
Type=Simple
ExecStart=/home/admin/soft/filebeat-5.2.1-linux-x86_64/filebeat -c /home/admin/soft/filebeat-5.2.1-linux-x86_64/filebeat.yml -httpprof 0.0.0.0:6060
ExecStop=/bin/kill -WINCH ${MAINPID}
Restart=always
RestartSec=0
WatchdogSec=1min
LimitNOFILE=100
LimitNPROC=100

[Install]
WantedBy=multi-user.target

其中filebest-current只是软连接,连接到真实目录,便于后续维护升级。
脚本 filebeat-stop.sh

#!/bin/bash
pid=`ps aux | grep filebeat | grep -v grep | awk '{print$2}'`
sudo kill -9 $pid

分发 filebeat.service filebeat-stop.sh

pscp -h list_filebeat filebeat.service /tmp
pssh -h list_filebeat "sudo cp /tmp/filebeat.service /usr/lib/systemd/system/"
pscp -h list_filebeat filebeat-stop.sh /home/admin/soft/filebeat-current/
pssh -h list_filebeat "sudo systemctl daemon-reload"
pssh -h list_filebeat "sudo systemctl enable filebeat"

启动/停止脚本:

sudo systemd start filebeat
sudo systemd stop filebeat

注意,所采集的日志需要有 admin 用户的读权限,并且路径必须有执行权限。

Step4. Kibana 中加载 Index Pattern

在 Kibana 的 Discover 模块中,可以添加 filebeat-* 作为 Index Pattern。看到如下界面,说明添加成功:

Index Pattern 添加成功

我们可以根据 Fields 进行日志索引,还可以对其进行排序。

Q & A

Q: Discover: Fielddata is disabled on text fields by default. Set fielddata=true on [message] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.

A: Fielddata 会使用大量的堆内存,尤其是加载了大量的 text fileds。一旦 fileddata 被加载进入了堆,在生命周期内会一直常驻。同时,加载 fileddata 非常耗时,影响用户体验。这就是为什么默认禁止了 fielddata。如果尝试对 text field 进行排序、聚合,就会报错如上。在尝试开启 fielddata 之前应该想想为什么要这么做,因为通常情况下不需要。

使用 Kibana Discover 搜索日志

Discover界面主要是通过各种过滤器搜索日志,如时间、type、loglevel等,并对所搜索到的日志做简单统计。界面如下所示,index 栏显示当前选择的 elasticsearch 中的 index。以下只做引导式介绍。

Discover 界面
  • Search 表示的是搜索栏,输入想要搜索的关键字;
  • filebeat 表示的是 index pattern 栏,我们之前导入的是 filbeat-*
  • Selected Fields 表示的是已选字段,右侧的内容框只会显示已选字段数据;
  • Available Fileds 可以对预定义字段进行筛选,可以对 Popular 中显示的可选字段进行筛选;
  • Popular 显示的是最常用的字段;
  • 右上角的 Last 15 minutes 是用来选择时间区间的,也可以选择定时刷新 Auto Refresh

搜索栏的使用

  • 全字段匹配:搜索功能的后台支持是elasticsearch,属于全文搜索引擎,可以通过双引号进行任何字符串的匹配,如"write_bytes=383",搜索结果为 message 字段包含了该字符串的 日志数据:
全字段匹配
  • 使用字段和逻辑表达:Elasticsearch的数据源是经过logstash格式化的日志,该格式通过elasticsearch的mapping API对应到kibana的字段。在文档栏的 source 中可以查看到格式化后的日志,以及原日志。搜索时可以使用字段和逻辑表达,如type: log等。这里注意,输入过程中kibana的搜索栏会动态解析搜索内容,搜索表达式输入过程中可能会显示红框,提示无法解析,待全部输入完全即可:
使用字段和逻辑表达
  • 使用过滤器:过滤器可以叠加使用,左侧边栏只能够对已有字段进行设置。鼠标移动到对应字段,字段会变灰,并显示该字段统计量前五的数据,如下所示:
使用过滤器

点击对应+(正向过滤)、-(反向过滤)进行过滤。对所有字段的过滤,可以在文档栏的 source 中进行选择,如下所示:

所有字段过滤

选择后的过滤器会显示在搜索栏下方,便于进行设置:

编辑过滤器

图标和文字可以达到相同的功能,分别是过滤器 Enable、Disable、反选、锁定(更改搜索内容不变更)和删除。

工具栏的使用

过滤器设置好后,可以对该设置在工具栏中进行保存,作为visualize的数据源。三个图标分别是开始一个新的搜索(New)、保存搜索(Save)、打开搜索(Open)、分享搜索(Share)。

工具栏

柱状图统计

柱状图实时对搜索内容进行统计,以时间作为横坐标,显示搜索到的总日志条数。也可以通过箭头按钮展开或折叠显示相应的文本记录。默认一页最多显示500条。鼠标移动到相应柱状,可显示对应条数,数遍变为十字,可以进行放大(zoom in)或缩小(zoom out)。

文档栏字段选择

默认文档栏显示所有字段,需要调整显示字段,可以在页面左边字段选择框添加和删除。鼠标移动到相应字段,字段变灰,同时出现add或remove按钮。所选字段也可以进行移动布局,或排序。字段是否作为popular field,在settings中进行设置。

结合 Discover 和 Visualize 进行可视化图标展示

假设我们需要对来自2台 Filebeat 采集到的 message 数量按照 host 进行区别统计 sum。

首先我们在 Discover 中定义一个 SearchSelected Fields 选择 host message

定义 Search

点击 Save 进行保存,命名为 test1。

然后我们在 VisualizeVertical Bar Chart ,在右侧的 Or, From a Saved Search 里搜索 test1,并且进入编辑。Y-AxisX-Axis 分别配置如下:

Y 轴配置
X 轴配置

点击Apply Changes所得到的图表如下:

柱状图

点击 Save,我们可以很方便的在 DashboardAdd 这个视图。

Q & A

Q: 启动 ES 的时候报错:system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
A: SecComp fails on CentOS 6,修改 elasticsearch.yml ,在 Memory 的配置下面添加:bootstrap.system_call_filter: false

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

推荐阅读更多精彩内容