Linux下性能分析指南

看了很多文章,很多大牛都提到要关注自己程序的性能问题。比如说,除了你的程序可以work之外,还需要考虑你的程序的cpu占用率,内存占用率,io占用率等。整理一下性能问题一些指标和定位方法。


cpu相关

评价指标cpu的性能分析常用的两个指标是cpu利用率 和 平均负载

  • 平均负载
    在linux下面使用uptime命令可以查看到机器的平均负载。按照man uptime给出的定义,平均负载反应的是当前的机器的“活跃”进程数。

    $ man uptime
    DESCRIPTION
         uptime  gives  a  one line display of the following information.  The current time, how long the system has been running, how
         many users are currently logged on, and the system load averages for the past 1, 5, and 15 minutes.
    
         This is the same information contained in the header line displayed by w(1).
    
    $ uptime
     14:58:14 up 263 days, 18:18,  1 user,  load average: 0.93, 0.97, 1.05
    

    uptime的含义:
    uptime返回的是1,5,15分钟的“活跃”进程数。活跃的进程的定义是:
    处于R状态的进程 (处于运行状态的进程 或者是就绪状态的进程)
    处于D状态的进程 (处于等待IO的不可被信号中断)

    如果uptime高的话,那么可能的情况是:
    1)系统中有大量CPU密集型的进程,比如大量进程都在进行计算,此时的系统平均负载与CPU使用率的关联就很大。
    2)系统中有大量IO密集型进程,这些进程中有很多时间都在等待IO完成,此时系统平均负载高但是CPU使用率并不见得就高。
    3) 就绪队列中有大量处于就绪状态等待CPU资源的进程,这种情况下会导致系统平均负载升高,而且CPU使用率也变高。


cpu利用率

cpu利用率有两个维度,一个是机器某个cpu核心的利用率,另外一个是进程的cpu利用率。如果用top命令可以看到这两个维度分别的指标。下面这张图是某个cpu核心的利用率,图片中下面是各种进程的cpu利用率。

下面先从机器某个核心的cpu利用率说起

  • 1. 某个核心的cpu利用率
    通过top命令,经常可以看到机器上每个cpu核心的负载,如下图所示。

但是,top的数据是从哪里拿到的呢?了解linux系统的都知道/proc/stat 这个文件记录了每个cpu从启动之后在各个状态下面的节拍数。

翻译一下每列的含义:
us:CPU运行用户空间进程的时间比例
sy:CPU运行内核进程时间比例
ni:CPU 运行低优先级进程时间比例
id:CPU空闲状态时间比例
iowait: CPU等待I/O操作完成的时间比例
hi:CPU 处理硬件中断时间比例
si: CPU 处理软中断时间比例
steal:虚拟 CPU 被占用强制等待时间比例


cpu某个核心的利用率 = 1 - ((iowait时间 + idle时间)/ 总时间 。
因此,如果要计算某个时间点的cpu利用率,可以先取两个采样点读取/proc/stat文件,然后按照下面的公式计算

CPU Usage 
 = 1 - (△idle+△iowait) / △total_time
 = 1 - (idle2+iowait2 - idle1 - iowait1) / (total_time2 - total_time1)

  • 2. 某个进程的cpu利用率

如何计算某个进程的cpu利用率,计算的基本公式如下 = 这个进程自己的占用的cpu时间 * 核心数 / cpu每个核心各种状态的总时间。写的详细一点,大约是:

某个进程的cpu利用率 
= (进程用户态时间 + 内核态时间 + 用户态等待子进程的消耗
    + 内核态等待子进程的消耗)/ cpu总时间△t

对于某个进程,可以根据其pid找到在/proc/pid/stat 找打这个进程各种状态占用的cpu节拍数。

找到里面的关键几列,分别是:
utime :用户态时间
sttime :系统态时间
cutime : 子进程用户态时间
cstime : 子进程系统态时间


写个小脚本就可以统计这个事情:

# 打印该进程进程用户态时间 + 内核态时间 + 
# 用户态等待子进程的消耗 + 内核态等待子进程的消耗 占用的时间之和
$ cat /proc/16820/stat | awk '{print "cpu_total_slice : " $14+$15+$16+$17}'
cpu_total_slice : 4405

了解了cpu利用率的原理,那就不难写出一个类似于ps命令或top这样的工具去统计某个进程的cpu利用率或者机器cpu的利用率。用shell写一个demo,验证一下:

# 统计某个进程的cpu占用率
print_process_cpu_precent()
{
  cpu_total_time1=`cat /proc/stat | head -n1 |awk '{print $2+$3+$4+$5+$6+$7+$8}'`
  process_time1=`cat /proc/${PID}/stat | head -n1 | awk '{print $14+$15+$16+$17}'`
  sleep 1

  cpu_total_time2=`cat /proc/stat | head -n1 |awk '{print $2+$3+$4+$5+$6+$7+$8}'`
  process_time2=`cat /proc/${PID}/stat | head -n1 | awk '{print $14+$15+$16+$17}'`

  cpu_time=$((cpu_total_time2 - cpu_total_time1))
  process_time=$((process_time2 - process_time1))

  cpu_percent=$((100 * process_time * cpu_core_num / cpu_time))

  echo "process : $PID, cpu percent : $cpu_percent"
}

封装成一个脚本跑起来:
https://github.com/zhaozhengcoder/CoderNoteBook/blob/master/example_code/shell/cpu.sh


通过stress命令模拟cpu和io密集型的任务来对应这个脚本统计的结果和pidstat,mpstat的结果对比效果准不准。

#产生一个io密集型的进程供测试
stress -i 1

$ pidstat -p 18493 1 100
04:01:48 PM     18493    0.00   36.00    0.00   36.00     0  stress
04:01:49 PM     18493    0.00   42.00    0.00   42.00     0  stress
04:01:50 PM     18493    0.00   37.00    0.00   37.00     0  stress
04:01:51 PM     18493    0.00   40.00    0.00   40.00     0  stress
04:01:52 PM     18493    0.00   37.00    0.00   37.00     0  stress
04:01:53 PM     18493    0.00   41.00    0.00   41.00     0  stress
04:01:54 PM     18493    0.00   36.00    0.00   36.00     0  stress
04:01:55 PM     18493    0.00   43.00    0.00   43.00     0  stress
04:01:56 PM     18493    0.00   40.00    0.00   40.00     0  stress
04:01:57 PM     18493    0.00   53.00    0.00   53.00     0  stress

./test_cpu.sh 18493
process : 18493, cpu percent : 40
process : 18493, cpu percent : 40
process : 18493, cpu percent : 40
process : 18493, cpu percent : 44
process : 18493, cpu percent : 37
process : 18493, cpu percent : 42
process : 18493, cpu percent : 38
process : 18493, cpu percent : 40
process : 18493, cpu percent : 44
process : 18493, cpu percent : 54  

// 总的来说还是比较接近,相差不大
mpstat -P ALL 1 100
04:05:04 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
04:05:05 PM  all    6.16    0.00    5.90    3.46    0.00    0.00    0.00    0.00   84.48
04:05:05 PM    0    2.02    0.00   42.42   53.54    0.00    0.00    0.00    0.00    2.02
04:05:05 PM    1   14.00    0.00    3.00    0.00    0.00    0.00    0.00    0.00   83.00
04:05:05 PM    2    3.19    0.00    4.26    0.00    0.00    0.00    0.00    0.00   92.55
04:05:05 PM    3   18.18    0.00    3.03    0.00    0.00    0.00    0.00    0.00   78.79
04:05:05 PM    4    6.52    0.00   13.04    0.00    0.00    0.00    0.00    0.00   80.43
04:05:05 PM    5    5.05    0.00    1.01    1.01    0.00    0.00    0.00    0.00   92.93
04:05:05 PM    6    1.01    0.00    2.02    0.00    0.00    0.00    0.00    0.00   96.97
04:05:05 PM    7    3.16    0.00    1.05    0.00    0.00    0.00    0.00    0.00   95.79
04:05:05 PM    8    5.15    0.00    3.09    0.00    0.00    0.00    0.00    0.00   91.75
04:05:05 PM    9    3.03    0.00    2.02    0.00    0.00    0.00    0.00    0.00   94.95
04:05:05 PM   10    3.23    0.00    2.15    0.00    0.00    0.00    0.00    0.00   94.62
04:05:05 PM   11   26.73    0.00    5.94    0.00    0.00    0.00    0.00    0.00   67.33
04:05:05 PM   12    3.06    0.00    0.00    0.00    0.00    0.00    0.00    0.00   96.94
04:05:05 PM   13    0.99    0.00    2.97    0.99    0.00    0.00    0.00    0.00   95.05
04:05:05 PM   14    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.00
04:05:05 PM   15    4.30    0.00    4.30    0.00    0.00    0.00    0.00    0.00   91.40

$ ./test_cpu.sh 18493
[cpu 1] user percent : 3, syc percent 35
[cpu 2] user percent : 13, syc percent 3
[cpu 3] user percent : 3, syc percent 5
[cpu 4] user percent : 10, syc percent 4
[cpu 5] user percent : 6, syc percent 10
[cpu 6] user percent : 5, syc percent 0
[cpu 7] user percent : 0, syc percent 0
[cpu 8] user percent : 5, syc percent 0
[cpu 9] user percent : 4, syc percent 3
[cpu 10] user percent : 0, syc percent 0
[cpu 11] user percent : 0, syc percent 10
[cpu 12] user percent : 20, syc percent 5
[cpu 13] user percent : 5, syc percent 15
[cpu 14] user percent : 1, syc percent 3
[cpu 15] user percent : 5, syc percent 10
[cpu 16] user percent : 3, syc percent 4
  • cpu利用率是否会把子线程的利用率计算进去?
    关于cpu利用率,cpu的利用率是否会包含子线程占用cpu的比例么?比如对于如下的进程,ps看到的cpu利用率是多少呢? 测试结果如下,cpu的占用率是包含自己的子线程的。
    void threadfunc1()
    {
        int val = 1;
        for (int i = 0; i < max_print_times;)
        {
            val = (val + 1) * val;
        }
    }
    
    int main()
    {
        std::thread t1(threadfunc1);
        t1.join();   
        return 0;
    }
    

  • 关于查看线程的一些命令
    # 查看进程下面有几个线程
    $ pstree -p 1
    init(1)─┬─init(7)───zsh(8)───pstree(103)
          └─{init}(6)
    
    # 显示系统的线程
    $ ps -efT 
    $ top 命令之后,输入H
    
    # 查看一个进程下那个子线程的cpu比较高
    $ top -H -p 5680
     PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                           
     5681 user+  20   0   26116   1128    924 R 99.9  0.0   8:23.30 a.out                                                                             
     5680 user+  20   0   26116   1128    924 S  0.0  0.0   0:00.00 a.out                                                                             
    

在日常的开发中,我常用top命令看一下各种进程的状态。如果是想确定某个操作是否会影响cpu的性能。我一般会top -b > profile.log, 然后触发某个操作,最后打开统计的log,观察这段时间内性能指标的各种变化。如果可以确定是某个进程的话,也可以使用pidstat -p xxxx 1的方式观察。


内存相关
  • 相关指标
    可以用free,top命令看到关于内存的指标:

    $free -g
                  total        used        free      shared  buff/cache   available
      Mem:             15           1           9           1           4          12
      Swap:             0           0           0
    
    $top
    VIRT    RES    SHR   %MEM
    
    VIRT: 进程申请的虚拟内存
    RES : 进程当前占用的物理内存(不包括共享内存)
    SHR : 进程当前占用的共享内存
    %MEM : 进程当前先用的物理内存的比例 (RES/物理内存)
    

    关于VIRT,需要注意的是进程malloc内存之后,并不会立刻使VIRT升高,只用写内存的时候,才会是VIRT升高。换句话说,malloc的时候,不会立刻给进程分配内存,只有写入的时候,才会触发分配(cow机制)。
    做一个对比的测试,下面这两段代码占用的内存(VIRT占用)完全不一样。区别只是一个申请了内存之后,什么都没有做,另外一个是申请之后,对内存进行了写入。

    const long mem_size = 10 * 1024* 1024;
    int times = 10;
    for (int i = 0; i <times; i++)
    {
      int * mem_arr = new int[mem_size];
      for (int j = 0; j < mem_size; j++)
      {
        mem_arr[j] = j;
      }
    }
    
    const long mem_size = 10 * 1024* 1024;
    int times = 10;
    for (int i = 0; i <times; i++)
    {
        int * mem_arr = new int[mem_size];
        // for (int j = 0; j < mem_size; j++)
        // {
        //     mem_arr[j] = j;
        // }
    }
    
  • 常用的定位内存问题的命令:

    查看当前机器内存占用的情况
    free -g 
    
    top 命名输入之后,输入M(按照内存占用高低排序)
    
    观察机器内存的变化
    $ vmstat 1 
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     0  0      0 11327748 2178472 1960200    0    0     0     5    0    0  0  0 100  0  0
     0  0      0 11327768 2178472 1960200    0    0     0     0  875  890  0  0 100  0  0
     0  0      0 11327628 2178472 1960200    0    0     0     0  857  906  0  0 100  0  0
     0  0      0 11327628 2178472 1960200    0    0     0    96  845  896  0  0 100  0  0
    
  • buff和cache是什么含义?
    在日常的开发中,如果打开打开一个大文件再次打开会更快一些。linux在内存和磁盘之后,构建了buff和cache来作为缓存。以前一直有一个错误印象,cache是读缓存,buff是写缓存。准确的说,cache是读写文件系统的缓存,buff是写磁盘系统的缓存。

    # 清空缓存
    $ echo 3 > /proc/sys/vm/drop_caches
    
    写文件
    $ dd if=/dev/urandom of=/tmp/file bs=1M count=50
    读文件
    $ dd if=/tmp/file of=/dev/null
    
    写磁盘
    $ dd if=/dev/urandom of=/dev/sdb1 bs=1M count=2048
    读磁盘:
    $ dd if=/dev/sda1 of=/dev/null bs=1M count=1024
    
    # 使用vmstat观察cache和buff的变化
    vmstat -1
    

  • oom问题
    比如某个进程申请的内存过大(或者是由于bug导致申请多过的内存),导致机器没有内存的时候,会出现oom。oom发生的时候,并不一定会kill正在申请内存的进程,而是会根据每个进程的score分数去kill掉一个。于是就会出现是服务a的bug,疯狂申请内存,最后导致oom去kill了服务b。这个问题不难理解,有的时候出现某个服务莫名其妙的挂了,逻辑上并没有什么错误,可以排查一下是否是oom导致。

    cat /var/message/log | grep "Out of memory"
    

    举一个自己遇到的关于内存的问题:有一个物理机部署某个进程启动的时候,在init的逻辑在读取一个系统文件时候,返回了false,导致进程启动失败。排查过程:

    - 查看日志,发现是init阶段某个系统调用失败,导致init失败
    
    - 使用strace 启动
    trace -o out.txt -e trace=all ./xxxx 
    
    - 在日志中看到如下错误:
    open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
    
    - 看提示是内存分配失败,使用free -g查看可用内存,可用内存不足。
    
    - 最终排查下来,这类问题的学名称为:
    fork/clone failures with ENOMEM
    
    - 解决办法除了让物理机保持足够的可用内存之外
    还可以临时修改了linux vm分配内存的策略,vm overcommit 修改为1。
    
    https://stackoverflow.com/questions/1367373/python-subprocess-popen-oserror-errno-12-cannot-allocate-memory
    

io相关

基本指标:
io利用率:指的是磁盘处理 I/O 的时间百分比
io吞吐量:每秒的 I/O 请求大小,比如xxMB每秒
IOPS:每秒的 I/O 请求数

常用命令:

iotop
pidstat -d 1
lsof -p 18940 

  • 如何定位高io的进程?

    // 测试代码如下,死循环打印日志到文件
    while(1)
    {
      LOG(INFO) << "this is infor message";
      LOG(ERROR) << "this is error message";
    }
    
  • iostat看到io的利用率升高:

    iostat -d -x 1
    %util 升高
    wkB/s 有数据在写入磁盘
    
    Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
    vda               0.00     0.00    0.00   50.00     0.00 20480.00   819.20     0.88   17.60    0.00   17.60   2.64  13.20
    vdb               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
    scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
    

    iotop命令

    Total DISK READ :       0.00 B/s | Total DISK WRITE :      16.40 M/s
    Actual DISK READ:       0.00 B/s | Actual DISK WRITE:      15.69 M/s
    TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                                                                                          
    26098 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.01 % [kworker/4:2]
    11106 be/4 root        0.00 B/s    3.92 K/s  0.00 %  0.00 % sap1007
    13627 be/4 user_zhao 0.00 B/s   16.39 M/s  0.00 %  0.00 % ./test
      1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd
    
  • 如何定位到具体进程:

    # 找到在io的进程
    $ pidstat -d 1   
    11:02:54      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
    11:02:55     1000      8721      0.00  18459.41      0.00  test
    
  • 如果定位到具体的io的文件:

    $ lsof -p 8721
    test    8721 user_zhao    4w   REG  252,1 369094695 1444369  /home//src/test_ERROR20210525-110157.8721
    
    $strace -p 8721
    write(4, "E0525 11:26:09.772125 11740 test"..., 68) = 68
    write(5, "E0525 11:26:09.772125 11740 test"..., 68) = 68
    write(3, ":48] this is error glog message\n"..., 4096) = 4096
    write(2, "E0525 11:26:09.772125 11740 test"..., 68) = 68
    gettid()                                = 11740
    gettid()                                = 11740
    
    $ pstack 8721
    #0  0x00007fcb3ede0850 in __write_nocancel () from /lib64/libc.so.6
    #1  0x00007fcb3ed6cfb3 in _IO_new_file_write () from /lib64/libc.so.6
    #2  0x00007fcb3ed6d74f in __GI__IO_file_xsputn () from /lib64/libc.so.6
    #3  0x00007fcb3ed6303d in fwrite () from /lib64/libc.so.6
    #4  0x00007fcb3fb05b36 in ?? ()
    #5  0x0000000001304800 in ?? ()
    #6  0x00007fcb3fb10606 in ?? ()
    #7  0x000000000000003f in ?? ()
    #8  0x0000000060ac6edb in ?? ()
    #9  0x0000000000000001 in ?? ()
    #10 0x00000000013047a8 in ?? ()
    #11 0x00007fff26baba10 in ?? ()
    #12 0x9a65cc0f603d7500 in ?? ()
    #13 0x0000000000000000 in ?? ()
    

网络相关

todo


从进程的角度分析

上面是站在系统的角度去分析cpu,内存,io等各种系统指标。另外一个中情况是我想看某个进程做什么,他的cpu,io,内存是什么样,它打开哪些文件,进行了哪些系统调用,哪些热点函数导致了cpu负载的上升等。

# 查看进程的各种性能指标
pidstat -p xxx
# 查看进程的系统调用
strace -p xxxx

# 查看进程当前的调用栈
pstack -p xxxx

# 查看进程的打开文件表
lsof -p xxxxx

# strace根据线程
strace -p PID后加上-f,多进程和多线程都可以跟踪。

  • 计算机各种操作耗时



其他补充
  • 热点函数定位
    发现某个进程cpu过载后,要如何定位到具体是哪段逻辑导致的呢?可以使用perf工具在进一步定位问题。故意写一段大循环的逻辑,使用perf命令进行定位热点函数。对于下面的一段代码进行分析,完整的代码:
    https://github.com/zhaozhengcoder/CoderNoteBook/blob/master/example_code/linux_perf_example/perf_demo.c 使用perf命令对进程进行采样,找到热点函数。

    perf 常用的命令:

    sudo perf record -F 99 -a -g ./demo1
    # -F 99 
    表示采样的频率 
    # -a
    录取所有CPU的事件
    # -g
    使能函数调用图功能
    -o  指定录取保存数据的文件名
    -g  使能函数调用图功能
    -C 录取指定CPU的事件
    
    # 生成报告的预览
    perf report
    

perf report的输出可以看到在执行过程中,每个函数的占比。可以看到在下图中,main,func1,func2函数占了很高的比例。


# 产生比较详细的报告 
sudo perf report -n --stdio

如果是一个已经启动好的进程,也可以attach上去进行分析分析

sudo perf record -F 99 -p 4989 -g 

# -p 
指明进程的pid
  • 画火焰图
git clone --depth 1 https://github.com/brendangregg/FlameGraph.git

# 到处out.perf 文件
sudo perf script > out.perf

# 折叠调用栈
FlameGraph/stackcollapse-perf.pl out.perf > out.folded

# 生成火焰图
$ FlameGraph/flamegraph.pl out.folded > out.svg

刚才是一个简单的例子,也可以用perf去观测一下nginx work的进程,生成火焰图。

# 压测一下
ab -n 10000 -c 10 http://127.0.0.1/

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

推荐阅读更多精彩内容