Hadoop 3.2.0 在 CentOS 7 下搭建伪分布式和完全分布式集群的案例

环境及工具

  • Hadoop 3.2.0
  • Windows 10 1809
  • CentOS 7.6.1810
  • VMware 15.1.0
  • OpenJDK 8(Amazon Corretto 8.222.10.1)

注意事项:由于 javax.* 等扩展库的原因,使用 JDK 9 及以上版本无法启动 nodemanagerresourcemanager

分类

  • 伪分布式:只有一个节点
  • 完全分布式:多个节点

不管哪一种方式,都要完成公共部分的配置。

公共部分

1 安装操作系统

本案例使用标准安装版镜像。官方提供的 ISO 镜像文件如下:

  • CentOS-7-x86_64-DVD-1810.iso,标准安装版(本案例使用)
  • CentOS-7-x86_64-Everything-1810.iso,对完整版安装盘的软件进行补充,集成所有软件
  • CentOS-7-x86_64-LiveGNOME-1810.iso,GNOME桌面版
  • CentOS-7-x86_64-LiveKDE-1810.iso,KDE桌面版
  • CentOS-7-x86_64-Minimal-1810.iso,精简版
  • CentOS-7-x86_64-NetInstall-1810.iso,网络安装镜像

1.1 下载地址

1.2 安装

使用 VMware 加载镜像进入安装流程,按照提示操作即可,过程简单,略。

注意事项:安装完成重启进入系统时,用小键盘输入 root 账号的密码可能会出错。

2 网络参数配置

2.1 配置 VMware 虚拟网络

(1)从菜单栏依次进入:编辑虚拟网络编辑器

(2)点击开启 更改设置,修改 VMnet8 的配置:

  • 选择 类型NAT 模式
  • 取消 DHCP 服务,手动指定静态 IP 地址
  • 设置 子网 IP,如:192.168.80.0
  • 设置 子网掩码,如:255.255.255.0
  • 点击进入 NAT 设置,设置 网关 IP,如:192.168.80.2;可根据需要,进入 DNS 设置 指定 DNS 服务器地址

2.2 配置 CentOS 网络参数

(1)使用 ip addr 命令查看网卡信息。本案例中网卡名称为 ens33

(2)根据网卡名称使用命令 vi /etc/sysconfig/network-scripts/ifcfg-ens33 打开网络参数配置文件,按 i 进行编辑。

(3)修改配置文件的两个参数值:

BOOTPROTO=static  ##使用静态 IP
ONBOOT=yes  ##开机启动网卡

(4)根据之前配置的参数值,在配置文件增加以下内容:

IPADDR=192.168.80.80   ##指定本机静态 IP
NETMASK=255.255.255.0  ##子网掩码
GATEWAY=192.168.80.2  ##网关 IP
DNS1=223.5.5.5
DNS2=223.6.6.6

(5)更改完后,按 ESC 键,然后输入 :wq,退出并保存。

附加内容,vi 命令回顾:

:q!  不保存文件,强制退出 vi
:w  保存文件,但不退出 vi
:wq  保存文件,并退出 vi

(6)使用命令 service network restart 重启网络,可用 ping 命令测试是否配置成功。

2.3 配置本机虚拟网卡

要使用 SecureCRTPortable 连接虚拟机,要保证本机虚拟网卡 IP 地址与 VMware 虚拟网络在同一网段:

(1)从任务栏依次进入:网络和共享中心更改适配器设置VMnet8 Network Adapter,修改 IPv4 参数如下:

  • IP 地址:192.168.80.1
  • 子网掩码:255.255.255.0
  • 默认网关: 192.168.80.2(该项取值实际上并不影响连接,只要 IP 所在网段正确即可)

(2)开启 SecureCRTPortable,添加连接至 192.168.80.80 即可。

附加内容,如果 SecureCRTPortable 命令行出现乱码,需要修改字符编码:
从菜单栏依次进入:Options(选项)Session Options(会话选项)Terminal(终端)Appearance(外观),在右侧找到 Character encoding 选择 UTF-8 即可。

3 创建普通用户

(1)创建用户,使用命令 adduser username

(2)为用户设置密码,使用命令 passwd username

(3)授权 sudo 权限,需要修改 sudoers 文件:

  • 定位文件,使用命令 whereis sudoers,可知文件在 /etc/sudoers
  • 修改文件权限,默认为只读(若修改文件后使用 :wq! 直接覆盖,则忽略该步骤)
ls -l /etc/sudoers 查看文件权限 
chmod -v u+w /etc/sudoers 修改文件权限为可编辑
  • 修改文件,使用 vi /etc/sudoers 进入文件,按照 root 的格式增加以下内容:
root ALL=(ALL) ALL 
username ALL=(ALL) ALL
  • 还原文件的只读权限(若修改文件后使用 :wq! 直接覆盖,则忽略该步骤)
ls -l /etc/sudoers 查看文件权限 
chmod -v u-w /etc/sudoers 修改文件权限为只读

注意事项:安装 JDK 和 Hadoop 均使用普通用户进行。

附加内容,用户切换:

  • 普通用户切换为 root 用户,使用命令 su,输入密码后即可。
  • root 用户切换为普通用户,使用命令 su 用户名 即可。

4 配置主机名及其映射

4.1 修改默认主机名

使用命令:hostnamectl set-hostname node-1,设置主机名为 node-1,修改后可用 hostname 命令查看结果:

[root@localhost ~]# hostname
node-1

要看到命令行变更,则需要重启;如果是 SecureCRTPortable,重新连接即可看到效果:

[root@node-1 ~]# 

4.1 配置 IP 与主机名映射

使用命令 vi /etc/hosts 编辑 host 文件:

  • 伪分布式要配置 192.168.80.80 与主机名 node-1 的映射,可增加以下内容:
192.168.80.80 node-1
  • 完全分布式要配置 IP 与主机名的映射,可增加以下内容:
192.168.80.80 node-1
192.168.80.81 node-2
192.168.80.82 node-3

注意事项:多节点情况下,可使用 Send Chat to All Sessions 向全部节点发出指令,批量修改 hosts。

附加内容,向多个虚拟机发送相同命令:
从菜单栏进入 View(视图),勾选 Chat Window,在底部窗口右键选择 Send Chat to All Sessions

5 配置免密登录

(1)使用命令 ssh-keygen -t rsa 生成 ssh 密钥对,均使用默认选项即可,在 ~/.ssh 隐藏目录下生成 id_rsa(私钥)和 id_rsa.pub(公钥)

(2)将公钥复制到需要免密登录的机器上。例如:执行 ssh-copy-id 192.168.220.11ssh-copy-id node-2

注意事项:在 node-1 使用 ssh node-1 连接自身也会提示需要输入密码,因此自身也复制一份,执行 ssh-copy-id node-1 即可。

6 关闭防火墙

使用命令 systemctl status firewalld 查看防火墙状态,出现 Active: active (running) 说明防火墙开启;出现 Active: inactive (dead) 说明防火墙关闭。可使用如下命令操作防火墙:

  • 临时关闭防火墙:systemctl stop firewalld
  • 临时开启防火墙:systemctl start firewalld
  • 永久关闭防火墙:systemctl disable firewalld
  • 永久开启防火墙:systemctl enable firewalld

注意事项:临时关闭或开启防火墙,当重启时会回复之前的状态;永久开启或关闭防火墙,重启后生效。

7 安装 JDK

(1)切换到普通用户

(2)上传 amazon-corretto-8.222.10.1-linux-x64.tar.gz~ 目录

(3)在 home/username 目录下新建 java 文件夹

(4)执行命令:tar zxvf amazon-corretto-8.222.10.1-linux-x64.tar.gz -C java/

(5)修改 /etc/profile 文件,在末尾添加内容后保存:

#set java environment
export JAVA_HOME=/home/username/java/amazon-corretto-8.222.10.1-linux-x64
export JRE_HOME=/home/username/java/amazon-corretto-8.222.10.1-linux-x64/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$JAVA_HOME:$PATH

(5)使用命令:source /etc/profile,让环境变量生效

(6)输入命令:java -version,查看 JDK 是否安装成功,如果安装成功则显示版本号信息:

openjdk version "1.8.0_222"
OpenJDK Runtime Environment Corretto-8.222.10.1 (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM Corretto-8.222.10.1 (build 25.222-b10, mixed mode)

8 安装 Hadoop

(1)切换到普通用户

(2)下载压缩包:http://mirror.bit.edu.cn/apache/hadoop/common/hadoop-3.2.0/

(3)上传 hadoop-3.2.0.tar.gz~ 目录

(4)在 home/username 目录下新建 hadoop 文件夹

(5)执行命令:tar zxvf hadoop-3.2.0.tar.gz -C hadoop/

(6)修改 /etc/profile 文件,在末尾添加内容后保存:

# set hadoop and sbin path
export HADOOP_HOME=/home/username/hadoop/hadoop-3.2.0
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

(7)使用命令:source /etc/profile,让环境变量生效

(8)输入命令:hadoop version,查看是否安装成功,如果安装成功则显示版本号信息:

Hadoop 3.2.0
Source code repository https://github.com/apache/hadoop.git -r e97acb3bd8f3befd27418996fa5d4b50bf2e17bf
Compiled by sunilg on 2019-01-08T06:08Z
Compiled with protoc 2.5.0
From source with checksum d3f0795ed0d9dc378e2c785d3668f39
This command was run using /opt/hadoop/hadoop-3.2.0/share/hadoop/common/hadoop-common-3.2.0.jar

伪分布式的搭建

由于伪分布式仅有一个节点,使用 192.168.80.80 一个虚拟机即可完成,完成公共部分的步骤后,再进行如下配置:

1 配置文件

需要配置的文件如下:

  • hadoop-3.2.0/etc/hadoop/hadoop-env.sh
  • hadoop-3.2.0/etc/hadoop/core-site.xml
  • hadoop-3.2.0/etc/hadoop/hdfs-site.xml
  • hadoop-3.2.0/etc/hadoop/mapred-site.xml
  • hadoop-3.2.0/etc/hadoop/yarn-site.xml
  • hadoop-3.2.0/etc/hadoop/workers

注意事项:配置文件中尖括号前后、单词前后的不必要空格会导致启动失败!

1.1 hadoop-env.sh

在文件中找到以下内容,解开注释,添加 JAVA_HOME 路径:

# The java implementation to use. By default, this environment
# variable is REQUIRED on ALL platforms except OS X!
export JAVA_HOME=/home/username/java/amazon-corretto-8.222.10.1-linux-x64

1.2 core-site.xml

在该文件中添加如下内容:

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://node-1:9000</value>
    </property>

    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/hadoop/tmp</value>
    </property>
</configuration>

(1)指定 Hadoop 所使用的文件系统以及 namenode 地址,使用 IP 地址或主机名均可

(2)指定 namenode 上本地的 hadoop 临时文件夹

1.3 hdfs-site.xml

在该文件中添加如下内容:

<configuration> 
   <property>
       <name>dfs.replication</name>
       <value>1</value>
   </property>
</configuration>

指定 HDFS 副本个数,配置默认是 3,应小于 datanode 机器数量

1.4 mapred-site.xml

在该文件中添加如下内容:

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

指定 MapReduce 运行框架为 yarn,默认为 local

1.5 yarn-site.xml

在该文件中添加如下内容:

<configuration>
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>node-1</value>
    </property>

    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
</configuration>

(1)指定 resourcemanager 的地址,使用主机名

(2)nodemanager 运行的附属服务,要配置成 mapreduce_shuffle,才可以运行 MapReduce 程序默认值

1.6 workers

添加从节点。伪分布式模式中,只有一个 node-1 节点:

node-1

注:Hadoop 3.0 以前的版本是 slaves 文件

2 启动 Hadoop

2.1 格式化

启动 Hadoop 集群,需要分别启动 HDFS 集群和 Yarn 集群。首次启动前,HDFS 在物理上不存在,需要要进行格式化。使用以下命令:

hdfs namenode -format

注意事项:

  • 首次格式化之后,若集群启动成功,就不要再进行格式化
  • 如有必要(例如在管理界面 LiveNode 为 0,datanode 日志有异常时),应删除 tmp 文件夹内容后,重新格式化
  • 格式化应在 namenode 所在节点进行。

2.2 启动脚本

如果配置了免密登录、workers 文件,则可以使用启动脚本。在 /sbin 目录下有四个脚本文件:start-dfs.shstop-dfs.shstart-yarn.shstop-yarn.sh,分别用于启动或停止 HDFS 和 Yarn。

使用 start-dfs.shstart-yarn.sh 后,用 jps 命令查看进程,出现如下 6 个进程说明已经成功启动:

8306 Jps
7300 NameNode
7972 NodeManager
7845 ResourceManager
7446 DataNode
7627 SecondaryNameNode

2.3 可视化界面

  • YARN NodeManager:http://192.168.80.80:9870

  • YARN ResourceManager:http://192.168.80.80:8088

附加内容:Hadoop 3.x 端口号与 2.x 的比较

分类 应用 Haddop 2.x port Haddop 3.x port
NNPorts Namenode 8020 9820
NNPorts NN HTTP UI 50070 9870
NNPorts NN HTTPS UI 50470 9871
SNN ports SNN HTTP 50091 9869
SNN ports SNN HTTP UI 50090 9868
DN ports DN IPC 50020 9867
DN ports DN 50010 9866
DN ports DN HTTP UI 50075 9864
DN ports Namenode 50475 9865

完全分布式的搭建

以 3 个节点构成的集群为例,每个节点都需要完成公共部分的步骤。节点的部署如下表:

hostname IP NameNode DataNode SecondaryNameNode NodeManager ResourceManager
node-1 192.168.80.80
node-2 192.168.80.81
node-3 192.168.80.82

注意事项:

  • 各节点执行 JDK 安装、Hadoop 安装、格式化、文件下发、启动或停止集群的用户名要相同
  • 各节点的 hosts 要相同
  • 各节点的 Hadoop 配置文件要相同
  • 配置 node-1 分别到 node-2、node-3 的免密登录
  • 各节点要分别修改网络参数、主机名
  • 由于 ResourceManager 部署在 node-3,因此需要配置 node-3 分别到 node-1、node-2 的免密登录

1 同步时间

有手动同步和网络授时两种方式:

(1)手动同步
使用命令 date –s "2019-01-01 05:05:05"

(2)网络授时
安装插件 yum install ntpdate,安装成功后可使用命令 ntpdate cn.pool.ntp.org 进行网络授时。

2 配置文件

需要配置的文件如下:

  • hadoop-3.2.0/etc/hadoop/hadoop-env.sh
  • hadoop-3.2.0/etc/hadoop/core-site.xml
  • hadoop-3.2.0/etc/hadoop/hdfs-site.xml
  • hadoop-3.2.0/etc/hadoop/mapred-site.xml
  • hadoop-3.2.0/etc/hadoop/yarn-site.xml
  • hadoop-3.2.0/etc/hadoop/workers

注意事项:配置文件中尖括号前后、单词前后的不必要空格会导致启动失败!

2.1 hadoop-env.sh(与伪分布式相同)

在文件中找到以下内容,解开注释,添加 JAVA_HOME 路径:

# The java implementation to use. By default, this environment
# variable is REQUIRED on ALL platforms except OS X!
export JAVA_HOME=/home/username/java/amazon-corretto-8.222.10.1-linux-x64

2.2 core-site.xml(与伪分布式相同)

在该文件中添加如下内容:

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://node-1:9000</value>
    </property>

    <property>
        <name>hadoop.tmp.dir</name>
        <value>/home/username/hadoop/tmp</value>
    </property>
</configuration>

(1)指定 Hadoop 所使用的文件系统以及 namenode 地址,使用 IP 地址或主机名均可

(2)指定 namenode 上本地的 hadoop 临时文件夹

2.3 hdfs-site.xml

在该文件中添加如下内容:

<configuration> 
   <property>
       <name>dfs.replication</name>
       <value>2</value>
   </property>

    <property>
       <name>dfs.namenode.name.dir</name>
       <value>/home/username/hadoop/name</value>
   </property>

   <property>
       <name>dfs.datanode.data.dir</name>
       <value>/home/username/hadoop/data</value>
   </property>

    <property>
        <name>dfs.namenode.secondary.http-address</name>
        <value>node-2:9868</value>
   </property>
</configuration>

(1)指定 HDFS 副本个数,配置默认是 3,应小于 datanode 机器数量

(2)指定元数据存储位置

(3)指定 datanode 存储位置

(4)指定 SecondaryNameNode 地址,使用 IP 地址或主机名均可

2.4 mapred-site.xml(与伪分布式相同)

在该文件中添加如下内容:

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

指定 MapReduce 运行框架为 yarn,默认为 local

2.5 yarn-site.xml

在该文件中添加如下内容:

<configuration>
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>node-3</value>
    </property>

    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
</configuration>

(1)指定 resourcemanager 的地址,使用主机名

(2)nodemanager 运行的附属服务,要配置成 mapreduce_shuffle,才可以运行 MapReduce 程序默认值

2.6 workers

添加从节点:

node-1
node-2
node-3

注:Hadoop 3.0 以前的版本是 slaves 文件

3 下发文件

可通过 scp 命令下发文件给其他节点,保持文件一致性。

(1)将 node-1 的 /home/username/hadoop/hadoop-3.2.0/etc 所有文件下发到 node-2 的对应位置,可在 node-1 执行如下命令:

scp -r /home/username/hadoop/hadoop-3.2.0/etc username@node-2:/home/username/hadoop/hadoop-3.2.0/etc

(2)将 node-1 的环境变量下发到 node-2 的对应位置,可在 node-1 执行如下命令:

scp -r /etc/profile username@node-2:/etc/profile

(3)将 node-1 的 hosts 下发到 node-2 的对应位置,可在 node-1 执行如下命令:

scp -r /etc/hosts username@node-2:/etc/hosts

4 启动 Hadoop

4.1 格式化

启动 Hadoop 集群,需要分别启动 HDFS 集群和 Yarn 集群。首次启动前,HDFS 在物理上不存在,需要要进行格式化。使用以下命令:

hdfs namenode -format

注意事项:

  • 首次格式化之后,若集群启动成功,就不要再进行格式化
  • 如有必要(例如在管理界面 LiveNode 为 0,datanode 日志有异常时),应删除 tmp 文件夹内容后,重新格式化
  • 格式化应在 namenode 所在节点进行。

4.2 启动脚本

如果配置了免密登录、workers 文件,则可以使用启动脚本。在 /sbin 目录下有四个脚本文件:start-dfs.shstop-dfs.shstart-yarn.shstop-yarn.sh,分别用于启动或停止 HDFS 和 Yarn。

根据部署,在 node-1 使用 start-dfs.sh,在 node-3 使用 start-yarn.sh 后,用 jps 命令查看各节点进程如下:

[username@node-1 root]$ jps
7301 NameNode
7733 NodeManager
7446 DataNode
7847 Jps

[username@node-2 root]$ jps
7430 NodeManager
7543 Jps
7304 SecondaryNameNode
7225 DataNode

[username@node-3 root]$ jps
7209 DataNode
7385 ResourceManager
7849 Jps
7517 NodeManager

4.3 可视化界面

  • YARN NodeManager:http://192.168.80.80:9870

  • YARN ResourceManager:http://192.168.80.82:8088

其它

若以 root 身份登录时,启动集群可能报如下错误:

[root@node-1 sbin]# ./start-all.sh
Starting namenodes on [node-1]
ERROR: Attempting to operate on hdfs namenode as root
ERROR: but there is no HDFS_NAMENODE_USER defined. Aborting operation.
Starting datanodes
ERROR: Attempting to operate on hdfs datanode as root
ERROR: but there is no HDFS_DATANODE_USER defined. Aborting operation.
Starting secondary namenodes [node-2]
ERROR: Attempting to operate on hdfs secondarynamenode as root
ERROR: but there is no HDFS_SECONDARYNAMENODE_USER defined. Aborting operation.
Starting resourcemanager
ERROR: Attempting to operate on yarn resourcemanager as root
ERROR: but there is no YARN_RESOURCEMANAGER_USER defined. Aborting operation.
Starting nodemanagers
ERROR: Attempting to operate on yarn nodemanager as root
ERROR: but there is no YARN_NODEMANAGER_USER defined. Aborting operation.

解决方案 1:

(1)在 start-dfs.shstop-dfs.sh 文件开头添加以下参数:

HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root

(2)在 start-yarn.shstop-yarn.sh 文件开头添加以下参数:

YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn
YARN_NODEMANAGER_USER=root

解决方案 2:以非 root 身份登录。

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

推荐阅读更多精彩内容