Hadoop初探

前言

近几年,大数据,云计算,机器学习成为了非常热门的话题,这些技术运用在了很多的领域,也是在未来很有发展前景的技术。自己最近在接触一些大数据的东西,学习大数据的话自然很有必要先学习Hadoop和Spark。这里我们就来一探Hadoop的究竟吧。


hadoop-pic1.png

Hadoop是什么

Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
核心设计:

  1. HDFS: HDFS为海量的数据提供了存储
  2. MapReduce: MapReduce为海量的数据提供了计算

Hadoop的作者是Doug Cutting,他受到谷歌的三篇论文的启发GFS(分布式存储系统),MapReduce(分布式运行模型), BigTable(大表),然后用Java去实现了这三个功能,然后就有了Hadoop,不得不感叹,牛人真的是牛人啊

Hadoop是专为离线和大规模数据分析而设计的,并不适合那种对几个记录随机读写的在线事务处理模式,数据来源可以来自任何的形式,无论数据采用什么形式,最终都会转换成key-value的形式,key/value是基本数据单元
简单总结来说,Hadoop是一种分布式计算的解决方案

解决了什么问题

Hadoop就是解决了大数据(大到一台计算机无法进行存储,一台计算机无法在要求的时间内进行处理)的可靠存储和处理的问题。
也就是两个核心的设计,HDFS和MapReduce

HDFS

设计特点

1、大数据文件,非常适合上T级别的大文件或者一堆大数据文件的存储,现在互联网上的数据量非常庞大,动不动上T的数据,所以非常适合Hadoop。
2、文件分块存储,HDFS会将一个完整的大文件平均分块存储到不同计算器上,它的意义在于读取文件时可以同时从多个主机取不同区块的文件,多主机读取比单主机读取效率要高得多。
3、流式数据访问,一次写入多次读写,这种模式跟传统文件不同,它不支持动态改变文件内容,而是要求让文件一次写入就不做变化,要变化也只能在文件末添加内容。
4、廉价硬件,HDFS可以应用在普通PC机上,这种机制能够让给一些公司用几十台廉价的计算机就可以撑起一个大数据集群。
5、硬件故障,HDFS认为所有计算机都可能会出问题,为了防止某个主机失效读取不到该主机的块文件,它将同一个文件块副本分配到其它某几个主机上,如果其中一台主机失效,可以迅速找另一块副本取文件。

关键元素

  1. Block:将一个文件进行分块,通常是128M。
  2. NameNode:保存整个文件系统的目录信息、文件信息及分块信息,这是由唯一一台主机专门保存,当然这台主机如果出错,NameNode就失效了。在Hadoop2.*开始支持activity-standy模式----如果主NameNode失效,启动备用主机运行NameNode。
  3. DataNode:分布在廉价的计算机上,用于存储Block块文件。
hdfs.gif

MapReduce

MapReduce是一套从海量源数据提取分析元素最后返回结果集的编程模型,将文件分布式存储到硬盘是第一步,而从海量数据中提取分析我们需要的内容就是MapReduce做的事了。

举个例子吧,假如说你想统计一个巨大的文本文件存储在HDFS上,你想要知道这个文本里各个词的出现频率。我们把我们要运算的逻辑分发到各个节点上,在每个节点上进行运算和统计,假如在各个节点上对这些单词进行统计,我们输入的格式是一行一行的文本,而统计的结果像key-value的形式,比如在第一个节点上(hello, 30), (world, 22), (hadoop, 60),第二个节点上(hello, 20), (world, 32), (spark, 70),也就是说将任何形式的数据转换成key-value的形式,这个过程就是Map。
然后我们要统计整个文本的单词出现的次数,就要对这些节点上的数据进行汇总,将这些节点上的数据按照key分组,合并,也就是(a, num1),(a, num2), (b, num3),(b, num4(合并后就变成(a, num1 + num2), (b, num3 + num4),按照上面的结果合并就是
(hello, 50), (world, 54), (hadoop, 60), spark(70),这个过程就是Reduce


mapreduce.jpg

适用场景

hadoop擅长离线日志分析,facebook就用Hive来进行日志分析,2009年时facebook就有非编程人员的30%的人使用HiveQL进行数据分析;淘宝搜索中的自定义筛选也使用的Hive;利用Pig还可以做高级的数据处理,包括Twitter、LinkedIn上用于发现您可能认识的人,可以实现类似Amazon.com的协同过滤的推荐效果。淘宝的商品推荐也是!在Yahoo!的40%的Hadoop作业是用pig运行的,包括垃圾邮件的识别和过滤,还有用户特征建模。(2012年8月25新更新,天猫的推荐系统是hive,少量尝试mahout!)
不过从现在企业的使用趋势来看,Pig慢慢有点从企业的视野中淡化了。

Hadoop伪分布式的安装

好了,我们了解和学习了Hadoop的概念之后就来学习一下如何安装Hadoop吧,这里我们先来学习伪分布式的安装,也就是NameNode和DataNoe都在同一台服务器上而且salve也是自己

环境准备

  1. 虚拟机Vmware
  2. Centos 6.9
  3. Hadoop 2.7.3
  4. JDK 1.8

配置网络

IP

我们首先先安装好Centos,然后配置好网络,虚拟机与主机的连接方式选择NAT,然后cmd命令输入ipconfig
,记录下VMware Network Adapter VMnet8 下的IP,在虚拟机中输入

vim /etc/sysconfig/network-scripts/ifcfg-eth0

IP地址要和VMware Network Adapter VMnet8 下的IP在同一个网段,我的IP是192.168.109.1,贴一个自己的配置

DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.109.3
NETMASK=255.255.255.0
GATEWAY=192.168.109.2
DNS1=192.168.109.2

然后使用命令service network restart重启网络

修改主机名

vim /etc/sysconfig/network

NETWORKING=yes
HOSTNAME=hadoop1

修改主机名和IP的映射关系

vim /etc/hosts

192.168.109.3 hadoop1

关闭防火墙

这里我们需要关闭我们的防火墙,开启防火墙会有访问限制,在虚拟机局域网内我们也不需要做访问限制,索性就把防火墙关了

#查看防火墙状态
service iptables status
#关闭防火墙
service iptables stop
#查看防火墙开机启动状态
chkconfig iptables --list
#关闭防火墙开机启动
chkconfig iptables off

创建用户

我们一般不直接使用root用户,会创建一个新的用户来完成我们的实验,这里我们新建一个hadoop用户
user add hadoop
接下来为hadoop用户设置密码
passwd hadoop
然后我们为hadoop用户授予root权限
vim /etc/sudoer
找到root ALL=(ALL) ALL 并下面加入以下

## Allow root to run any commands anywhere 
root    ALL=(ALL)       ALL
hadoop    ALL=(ALL)       ALL

切换用户

现在我们切换到hadoop用户下进行操作

su hadoop

安装软件

我们在根目录下创建一个app文件夹, mkdir app,然后我们将需要弄的文件都解压到app文件夹里面
用winscp上传JDK,Hadoop的文件,解压JDK, 执行命令

tar -zxvf jdk-8u131-linux-x64.tar.gz -C app

解压Hadoop

tar -zxvf hadoop-2.7.3.tar.gz -C app

这个时候我们将jdk和hadoop都解压到app目录下,接下来我们就开始配置环境了

配置环境

配置JDK

vim /etc/profile

在文件最后添加如下:

export JAVA_HOME=/home/hadoop/app/jdk1.8.0_131
export PATH=$PATH:$JAVA_HOME/bin

刷新配置

source /etc/profile

配置Hadoop

注意:hadoop2.x的配置文件$HADOOP_HOME/etc/hadoop,这里我们的目录就是在/home/hadoop/app/hadoop-2.7.3/etc/下
伪分布式需要修改5个配置文件

  1. hadoop-env.sh
    这个文件表示hadoop运行环境的文件,找到25行,改成export JAVA_HOME=/home/hadoop/app/jdk1.8.0_131
    这个值原来是${JAVA_HOME},但是有点问题,老是获取不到正确的值,所以这里我们就直接将它写死
  2. core-site.xml
    配置如下:
<configuration>
    <!-- 指定HADOOP所使用的文件系统schema(URI),HDFS的老大(NameNode)的地址 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop1:9000</value>
    </property>
    <!-- 指定hadoop运行时产生文件的存储目录 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/home/hadoop/app/hadoop-2.7.3/tmp</value>
    </property>
</configuration>
  1. hdfs-site.xml
    配置如下:
<configuration>
    <!-- 指定HDFS副本的数量 -->
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>
  1. mapred-site.xml
    这里先执行一个命令,重命名模板文件mv mapred-site.xml.template mapred-site.xml
    然后再修改vim mapred-site.xml
    配置如下:
<configuration>
    <!-- 指定mr运行在yarn上 -->
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>
  1. yarn-site.xml
    配置如下:
<configuration>
<!-- Site specific YARN configuration properties -->
    <!-- 指定YARN的老大(ResourceManager)的地址 -->
    <property>
        <name>yarn.resourcemanager.hostname</name>
        <value>hadoop1</value>
    </property>
    <!-- reducer获取数据的方式 -->
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
     </property>
</configuration>

5个文件都修改完成后,我们需要将hadoop添加到环境中
vim /etc/proflie
加上HADOOP_HOME, 修改文件内容如下:

export JAVA_HOME=/home/hadoop/app/jdk1.8.0_131
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/home/hadoop/app/hadoop-2.7.3
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

格式化hdfs

第一次启动的时候我们需要格式化namenode,对namenode进行初始化,执行以下命令

hdfs namenode -format (hadoop namenode -format)

成功的话,会看到 “successfully formatted” 和 “Exitting with status 0″ 的提示,若为 “Exitting with status 1″ 则是出错。

启动hadoop

先启动HDFS: start-dfs.sh
再启动YARN: start-yarn.sh
期间会让你多次输入密码,我们在后面配置SSH免密登录之后就不用输入密码了
验证是否启动成功,使用jps命令验证

27408 NameNode
28218 Jps
27643 SecondaryNameNode
28066 NodeManager
27803 ResourceManager
27512 DataNode

看到以上进程的时候,就说明我们启动成功了

配置SSH免登录

生成ssh免登陆密钥,进入到我的home目录
cd ~/.ssh,执行

ssh-keygen -t rsa (四个回车)

执行完这个命令后,会生成两个文件id_rsa(私钥)、id_rsa.pub(公钥)
将公钥拷贝到要免登陆的机器上
ssh-copy-id localhost
然后我们执行ssh localhost 就可以不用输入密码登录这台机器了

进入Web管理界面

我们在浏览器里面输入http://192.168.109.3:50070/
可以看到如下图片


web页面1.png

web页面2.png

说明我们的hadooop已经开启成功了

运行mapreduce程序

好了,我们的环境也搭建成功了,现在来试着跑一下mapreduce程序,进入hadoop的share目录下

cd /home/hadoop/app/hadoop-2.7.3/share/hadoop/mapreduce

看到有以下文件:

hadoop-mapreduce-client-app-2.7.3.jar
hadoop-mapreduce-client-common-2.7.3.jar
hadoop-mapreduce-client-core-2.7.3.jar
hadoop-mapreduce-client-hs-2.7.3.jar
hadoop-mapreduce-client-hs-plugins-2.7.3.jar
hadoop-mapreduce-client-jobclient-2.7.3.jar
hadoop-mapreduce-client-jobclient-2.7.3-tests.jar
hadoop-mapreduce-client-shuffle-2.7.3.jar
hadoop-mapreduce-examples-2.7.3.jar
lib
lib-examples
sources

运算PI圆周率

这里我们用hadoop-mapreduce-examples-2.7.3.jar的例子跑一下,执行的命令为
hadoop jar hadoop-mapreduce-examples-2.7.3.jar pi 5 10
pi是运算圆周率,后面的两个参数代表map的任务数量和map的取样数,取样数越大,运算的结果越精确,这里我们取了5和10作为参数,结果如下

Number of Maps  = 5
Samples per Map = 10
Wrote input for Map #0
Wrote input for Map #1
17/07/20 22:34:51 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)
Wrote input for Map #2
17/07/20 22:34:51 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)
Wrote input for Map #3
17/07/20 22:34:51 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)
Wrote input for Map #4
Starting Job
17/07/20 22:34:51 INFO client.RMProxy: Connecting to ResourceManager at hadoop1/192.168.109.3:8032
17/07/20 22:34:52 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeInternal(DFSOutputStream.java:577)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:573)
17/07/20 22:34:52 INFO input.FileInputFormat: Total input paths to process : 5
17/07/20 22:34:52 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)
17/07/20 22:34:52 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)
17/07/20 22:34:52 INFO mapreduce.JobSubmitter: number of splits:5
17/07/20 22:34:52 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1500560388081_0003
17/07/20 22:34:53 INFO impl.YarnClientImpl: Submitted application application_1500560388081_0003
17/07/20 22:34:53 INFO mapreduce.Job: The url to track the job: http://hadoop1:8088/proxy/application_1500560388081_0003/
17/07/20 22:34:53 INFO mapreduce.Job: Running job: job_1500560388081_0003
17/07/20 22:35:08 INFO mapreduce.Job: Job job_1500560388081_0003 running in uber mode : false
17/07/20 22:35:08 INFO mapreduce.Job:  map 0% reduce 0%
17/07/20 22:36:14 INFO mapreduce.Job:  map 100% reduce 0%
17/07/20 22:36:28 INFO mapreduce.Job:  map 100% reduce 100%
17/07/20 22:36:29 INFO mapreduce.Job: Job job_1500560388081_0003 completed successfully
17/07/20 22:36:29 INFO mapreduce.Job: Counters: 49
        File System Counters
                FILE: Number of bytes read=116
                FILE: Number of bytes written=714243
                FILE: Number of read operations=0
                FILE: Number of large read operations=0
                FILE: Number of write operations=0
                HDFS: Number of bytes read=1320
                HDFS: Number of bytes written=215
                HDFS: Number of read operations=23
                HDFS: Number of large read operations=0
                HDFS: Number of write operations=3
        Job Counters
                Launched map tasks=5
                Launched reduce tasks=1
                Data-local map tasks=5
                Total time spent by all maps in occupied slots (ms)=325021
                Total time spent by all reduces in occupied slots (ms)=8256
                Total time spent by all map tasks (ms)=325021
                Total time spent by all reduce tasks (ms)=8256
                Total vcore-milliseconds taken by all map tasks=325021
                Total vcore-milliseconds taken by all reduce tasks=8256
                Total megabyte-milliseconds taken by all map tasks=332821504
                Total megabyte-milliseconds taken by all reduce tasks=8454144
        Map-Reduce Framework
                Map input records=5
                Map output records=10
                Map output bytes=90
                Map output materialized bytes=140
                Input split bytes=730
                Combine input records=0
                Combine output records=0
                Reduce input groups=2
                Reduce shuffle bytes=140
                Reduce input records=10
                Reduce output records=0
                Spilled Records=20
                Shuffled Maps =5
                Failed Shuffles=0
                Merged Map outputs=5
                GC time elapsed (ms)=8989
                CPU time spent (ms)=9260
                Physical memory (bytes) snapshot=458428416
                Virtual memory (bytes) snapshot=12371886080
                Total committed heap usage (bytes)=624766976
        Shuffle Errors
                BAD_ID=0
                CONNECTION=0
                IO_ERROR=0
                WRONG_LENGTH=0
                WRONG_MAP=0
                WRONG_REDUCE=0
        File Input Format Counters
                Bytes Read=590
        File Output Format Counters
                Bytes Written=97
Job Finished in 98.692 seconds
Estimated value of Pi is 3.28000000000000000000

我们看最后一行,得出结果为3.28,是我们的样本数量太少了,要是样本数量大一点,结果应该更接近3.14
还发现个问题,运行中出现了多次警告

17/07/20 22:34:52 WARN hdfs.DFSClient: Caught exception
java.lang.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Thread.join(Thread.java:1252)
        at java.lang.Thread.join(Thread.java:1326)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.closeResponder(DFSOutputStream.java:609)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.endBlock(DFSOutputStream.java:370)
        at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:546)

我google了一下,再hadoop issue里面找到了答案https://issues.apache.org/jira/browse/HDFS-10429,发现是bug,忽略就好了,换个hadoop版本也许就没事了,或者修改日志的输出级别

计算单词数量wordcount

首先我们先新建一个words.txt文件,内容如下

hello world
hello tom
hello kevin
hello jerry
hello baby
tom and jerry

然后在hdfs里创建一个目录

hadoop fs -mkdir -p /wordcount/input

把文件上传到该目录下

hadoop fs -put words.txt /wordcount/input

查看文件是否上传上去了

hadoop fs -ls /wordcount/input

我们可以看到我们的文件已经成功上传上去了
我们发现操作hdfs的命令和操作linux的命令大致都是一样的,大家可以自行去看官方的文档
回到刚才的share目录下,继续执行刚才的那个示例文件

hadoop jar hadoop-mapreduce-examples-2.7.3.jar wordcount /wordcount/input /wordcount/output

这里执行的方法是wordcount,第一个参数是输入的文件位置,第二个参数是输出的结果的文件位置
执行结束后,我们来看一下输出目录hadoop fs -ls /wordcount/output,发下目录下生成了两个文件

Found 2 items
-rw-r--r--   1 hadoop supergroup          0 2017-07-20 23:07 /wordcount/output/_SUCCESS
-rw-r--r--   1 hadoop supergroup         51 2017-07-20 23:07 /wordcount/output/part-r-00000

查看一下part-r-00000这个文件

hadoop fs -cat /wordcount/output/part-r-00000

结果如下:

and     1
baby    1
hello   5
jerry   2
kevin   1
tom     2
world   1

可以看到,结果是正确的,大功告成

总结

接触一个新的技术,安装和配置环境的都是一件比较麻烦的事,可能你第一天就要花费很多时间在搭建环境上面了,可能期间你会遇到各种问题,不过也是锻炼耐心的一个过程,有一个不错的方法可以解决,那就是使用docker容器技术,使用别人搭建好的环境镜像,直接拿来用就可以,这样我们就可以不必花费太多时间在环境问题上,专心学我们的技术,有兴趣的同学可以自行了解下。还有这次的演示例子也只是拿官方的例子来做演示,后面需要自己写程序实现map-reduce,官网上也有很多的例子,所以我觉得看官方其实是最快了解一门技术的方法了,而且一些比较著名的开源项目的文档都是写的比较好的,基本上你看,然后照着demo敲一遍就可以上手了,而且那些资料还是最新的。还有这里也只是演示了伪分布的安装,其实hadoop有三种安装模式:
1.独立式:Hadoop运行所有的东西在无后台的单独的JVM中,这种模式适合在开发阶段测试与Debug MapReduce程序。
2.伪分布式:Hadoop做为后台应用运行在本地机器,模拟小集群。
3.全分布式:Hadoop做为后台应用运行真实的集群电脑中。
剩下的就留给读者自己探索吧!

个人博客: http://blog.zgj12138.cn
CSDN: http://blog.csdn.net/zgj12138

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

推荐阅读更多精彩内容