zoukankan      html  css  js  c++  java
  • centos6 cgroup及cgred简介和简单使用

    一、cgroup简介

      Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。这个项目最早是由Google的工程师在2006年发起(主要是Paul Menage和Rohit Seth),最早的名称为进程容器(process containers)。在2007年时,因为在Linux内核中,容器(container)这个名词太过广泛,为避免混乱,被重命名为cgroup,并且被合并到2.6.24版的内核中去。然后,其它开始了他的发展。 
    
      Linux CGroupCgroup 可​​​让​​​您​​​为​​​系​​​统​​​中​​​所​​​运​​​行​​​任​​​务​​​(进​​​程​​​)的​​​用​​​户​​​定​​​义​​​组​​​群​​​分​​​配​​​资​​​源​​​ — 比​​​如​​​ CPU 时​​​间​​​、​​​系​​​统​​​内​​​存​​​、​​​网​​​络​​​带​​​宽​​​或​​​者​​​这​​​些​​​资​​​源​​​的​​​组​​​合​​​。​​​您​​​可​​​以​​​监​​​控​​​您​​​配​​​置​​​的​​​ cgroup,拒​​​绝​​​ cgroup 访​​​问​​​某​​​些​​​资​​​源​​​,甚​​​至​​​在​​​运​​​行​​​的​​​系​​​统​​​中​​​动​​​态​​​配​​​置​​​您​​​的​​​ cgroup。

    主要功能:

    1 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
    2 优先级控制,CPU利用和磁盘IO吞吐。
    3 一些审计或一些统计,主要目的是为了计费。
    4 挂起进程,恢复执行进程。

    cgroups子系统:

     1 cpu 子系统,主要限制进程的 cpu 使用率。
     2 cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
     3 cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
     4 memory 子系统,可以限制进程的 memory 使用量。
     5 blkio 子系统,可以限制进程的块设备 io。
     6 devices 子系统,可以控制进程能够访问某些设备。
     7 net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
     8 net_prio — 这个子系统用来设计网络流量的优先级
     9 freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
    10 ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace
    11 hugetlb — 这个子系统主要针对于HugeTLB系统进行限制,这是一个大页文件系统。

    cgred简介

    Cgred 是​​​一​​​个​​​守​​​护​​​进​​​程​​​,它​​​可​​​根​​​据​​​在​​​ /etc/cgrules.conf 文​​​件​​​中​​​设​​​定​​​的​​​参​​​数​​​将​​​任​​​务​​​移​​​动​​​到​​​ cgroup 中​​​。​​​/etc/cgrules.conf 文​​​件​​​中​​​的​​​条​​​目​​​可​​​以​​​使​​​用​​​以​​​下​​​两​​​个​​​格​​​式​​​之​​​一​​​:
    user hierarchies control_group
    user:command hierarchies control_group
    例​​​如​​​:
    maria            devices        /usergroup/staff
    这​​​个​​​条​​​目​​​指​​​定​​​任​​​何​​​属​​​于​​​名​​​为​​​ maria 用​​​户​​​的​​​进​​​程​​​根​​​据​​​在​​​
    /usergroup/staff cgroup 中​​​指​​​定​​​的​​​参​​​数​​​访​​​问​​​设​​​备​​​子​​​系​​​统​​​。​​​要​​​将​​​具​​​体​​​命​​​令​​​与​​​具​​​体​​​ cgroup 关​​​联​​​,请​​​添​​​加​​​ command 参​​​数​​​,如​​​下​​​: maria:ftp devices /usergroup/staff/ftp
    该​​​条​​​目​​​现​​​在​​​指​​​定​​​何​​​时​​​名​​​为​​​ maria 的​​​用​​​户​​​使​​​用​​​ ftp 命​​​令​​​,自​​​动​​​将​​​该​​​进​​​程​​​移​​​动​​​到​​​包​​​含​​​ devices 子​​​系​​​统​​​的​​​层​​​级​​​中​​​的​​​
    /usergroup/staff/ftp cgroup 中​​​。​​​请​​​注​​​意​​​:该​​​守​​​护​​​进​​​程​​​只​​​有​​​在​​​符​​​合​​​适​​​当​​​的​​​条​​​件​​​后​​​才​​​可​​​将​​​该​​​进​​​程​​​移​​​动​​​到​​​该​​​ cgroup 中​​​。​​​因​​​此​​​,ftp 可​​​能​​​会​​​在​​​错​​​误​​​的​​​组​​​群​​​中​​​短​​​暂​​​运​​​行​​​。​​​再​​​有​​​,如​​​果​​​该​​​进​​​程​​​在​​​错​​​误​​​组​​​群​​​中​​​迅​​​速​​​生​​​出​​​子​​​进​​​程​​​,则​​​不​​​会​​​移​​​动​​​这​​​些​​​子​​​进​​​程​​​。​​​ /etc/cgrules.conf 文​​​件​​​中​​​的​​​条​​​目​​​可​​​包​​​括​​​以​​​下​​​额​​​外​​​符​​​号​​​: @ - 当​​​在​​​ user 使​​​用​​​前​​​缀​​​时​​​,代​​​表​​​是​​​一​​​个​​​组​​​群​​​而​​​不​​​是​​​单​​​独​​​用​​​户​​​。​​​例​​​如​​​:@admins 是​​​ admins 组​​​群​​​中​​​的​​​所​​​有​​​用​​​户​​​。​​​ * - 代​​​表​​​“​​​所​​​有​​​”​​​。​​​例​​​如​​​:subsystem 字​​​段​​​中​​​的​​​ * 代​​​表​​​所​​​有​​​子​​​系​​​统​​​。​​​ % - 代​​​表​​​与​​​以​​​上​​​行​​​中​​​项​​​目​​​相​​​同​​​的​​​项​​​目​​​。​​​例​​​如​​​: @adminstaff devices /admingroup @labstaff % %

    小结:通过cgroup设置我们想要的规则,通过cgred将规则应用到进程之上

    二、CPU限制

    1.查看已经使用的子系统

    [root@reddhat6_155_200 ~]# lssubsys -m
    cpuset /cgroup/cpuset
    cpu /cgroup/cpu
    cpuacct /cgroup/cpuacct
    memory /cgroup/memory
    devices /cgroup/devices
    freezer /cgroup/freezer
    net_cls /cgroup/net_cls
    blkio /cgroup/blkio

    2.编辑cgroup配置文件,添加两个group对CPU使用率的限制

    [root@reddhat6_155_200 ~]# vim /etc/cgconfig.conf  #添加以下两段
    group lesscpu{
        cpu{
    
    }
    }
    
    group morecpu{
        cpu{
    }
    }

    3.重启并查看CPU子系统目录

    [root@reddhat6_155_200 ~]# /etc/init.d/cgconfig restart
    Stopping cgconfig service:                                 [确定]
    Starting cgconfig service:                                 [确定]
    [root@reddhat6_155_200 ~]# ll /cgroup/cpu
    总用量 0
    --w--w--w-. 1 root root 0 2019-09-07 15:50 cgroup.event_control
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cgroup.procs
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cpu.cfs_period_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cpu.cfs_quota_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cpu.rt_period_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cpu.rt_runtime_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 cpu.shares
    -r--r--r--. 1 root root 0 2019-09-07 15:50 cpu.stat
    drwxr-xr-x. 2 root root 0 2019-09-07 15:50 lesscpu    #多出两个目录,和我们定义的group名称是一至的
    drwxr-xr-x. 2 root root 0 2019-09-07 15:50 morecpu
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 notify_on_release
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 release_agent
    -rw-r--r--. 1 root root 0 2019-09-07 15:50 tasks

    4.查看目录内容

    [root@reddhat6_155_200 ~]# ll /cgroup/cpu         仔细观察可以发现每个目录中的文件都是相同的,也就是默认情况下group会继承该子系统的所有规则
    [root@reddhat6_155_200 ~]# ll /cgroup/cpu/morecpu/   
    [root@reddhat6_155_200 ~]# ll /cgroup/cpu/morecpu/

    5.添加group规则

    [root@reddhat6_155_200 ~]# cat /cgroup/cpu/cpu.shares  #cpu.shares表示程序可以在​​​ cgroup 中​​​的​​​任​​​务​​​可​​​用​​​的​​​相​​​对​​​共​​​享​​​ CPU 时​​​间​​​的​​​整​​​数​​​值​​​,默认为1024
    1024
    [root@reddhat6_155_200 ~]# vim /etc/cgconfig.conf 
    group lesscpu{
        cpu{
              cpu.shares=100;    #该值不可以超过总大小(1024)
    }
    }
    
    group morecpu{
        cpu{
              cpu.shares=200;
    }
    }
    [root@reddhat6_155_200 ~]# /etc/init.d/cgconfig restart
    Stopping cgconfig service:                                 [确定]
    Starting cgconfig service:                                 [确定]

     [root@reddhat6_155_200 ~]# cat /cgroup/cpu/lesscpu/cpu.shares
     100
     [root@reddhat6_155_200 ~]# cat /cgroup/cpu/morecpu/cpu.shares
     200

    6.为了减少演示的复杂度,我们下线其他CPU,只保留一个CPU

    [root@reddhat6_155_200 ~]# lscpu |grep -A 1  "^CPU(s):"  #查看当前CPU个数及在线个数
    CPU(s):                2
    On-line CPU(s) list:   0,1
    [root@reddhat6_155_200 ~]# echo 0 > /sys/devices/system/cpu/cpu1/online   #将cpu1下线,cpu0为主cpu无法下线
    [root@reddhat6_155_200 ~]# lscpu |grep -A 1  "^CPU(s):"   #查看在线状态,目前只有cpu0在线
    CPU(s):                2
    On-line CPU(s) list:   0

    7.新开一个窗口,同时执行dd命令,分别选择lesscpu和morecpu

    [root@reddhat6_155_200 ~]# cgexec -g cpu:lesscpu time dd if=/dev/zero of=/dev/null bs=1M count=200000   #窗口1 分配少的先执行
    [root@reddhat6_155_200 ~]# cgexec -g cpu:morecpu time dd if=/dev/zero of=/dev/null bs=1M count=200000   #窗口2
    [root@reddhat6_155_200 ~]# top   #窗口3 使用top命令监控命令状态

    注意观察两个dd命令CPU使用率

    lesscpu结果:

    [root@reddhat6_155_200 ~]# cgexec -g cpu:lesscpu time dd if=/dev/zero of=/dev/null bs=1M count=200000
    记录了200000+0 的读入
    记录了200000+0 的写出
    209715200000字节(210 GB)已复制,21.7357 秒,9.6 GB/秒   #注意CPU使用时间
    0.01user 10.83system 0:21.73elapsed 33%CPU (0avgtext+0avgdata 7776maxresident)k   #注意CPU使用率
    0inputs+0outputs (0major+521minor)pagefaults 0swaps

    morecpu结果:

    [root@reddhat6_155_200 ~]# cgexec -g cpu:morecpu time dd if=/dev/zero of=/dev/null bs=1M count=200000
    记录了200000+0 的读入
    记录了200000+0 的写出
    209715200000字节(210 GB)已复制,16.26 秒,12.9 GB/0.02user 10.77system 0:16.26elapsed 66%CPU (0avgtext+0avgdata 7744maxresident)k
    0inputs+0outputs (0major+519minor)pagefaults 0swaps

     三、MEM限制

    1.编辑cgroup配置文件,添加一个mem限制

    [root@reddhat6_155_200 ~]# cat /cgroup/memory/memory.limit_in_bytes  #查看MEM(物理内存)默认限制大小 单位为字节 以目前机器配置,等同于无限制
    9223372036854775807
    [root@reddhat6_155_200 ~]# cat /cgroup/memory/memory.memsw.limit_in_bytes #查看MEM(物理内存)+Swap总的大小 此值必须大于等于 memory.limit_in_bytes 
    9223372036854775807
    [root@reddhat6_155_200 ~]# vim /etc/cgconfig.conf     #添加一个MEM 限制
    group poormem{
        memory{
            memory.limit_in_bytes=268435456;   #限制可以使用内存大小为256M
    }
    [root@reddhat6_155_200 ~]# /etc/init.d/cgconfig restart
    Stopping cgconfig service:                                 [确定]
    Starting cgconfig service:                                 [确定]
    [root@reddhat6_155_200 ~]# cat /cgroup/memory/poormem/memory.limit_in_bytes

    268435456

     2.创建一个内存盘

    [root@reddhat6_155_200 ~]# mkdir /mnt/tmpfs
    [root@reddhat6_155_200 ~]# mount -t tmpfs none /mnt/tmpfs  #注意没有挂载源 使用none
    [root@reddhat6_155_200 ~]# df -h
    Filesystem            Size  Used Avail Use% Mounted on
    /dev/mapper/vg_redhat6demo01-lv_root
                           50G  5.4G   42G  12% /
    tmpfs                 2.0G  224K  2.0G   1% /dev/shm
    /dev/vda1             477M   33M  419M   8% /boot
    /dev/mapper/vg_redhat6demo01-lv_home
                          5.5G   12M  5.2G   1% /home
    none                  2.0G     0  2.0G   0% /mnt/tmpfs   #大小2G,具体大小和系统剩余内存大小有关

    3.测试tmpfs特性

    [root@reddhat6_155_200 ~]# free -m  #查看当前内存大小
                 total       used       free     shared    buffers     cached
    Mem:          3959       2508       1451          2        246       1784
    -/+ buffers/cache:        477       3482
    Swap:         3967          0       3967
    [root@reddhat6_155_200 ~]# dd if=/dev/zero of=/mnt/tmpfs/test bs=1M count=1000  #向 tmpfs 挂载点写入1G内存
    记录了1000+0 的读入
    记录了1000+0 的写出
    1048576000字节(1.0 GB)已复制,0.466811 秒,2.2 GB/秒
    [root@reddhat6_155_200 ~]# free -m   #查看系统内存  少了1G
                 total       used       free     shared    buffers     cached
    Mem:          3959       3511        448       1002        246       2784
    -/+ buffers/cache:        480       3479
    Swap:         3967          0       3967
    [root@reddhat6_155_200 ~]# rm -f /mnt/tmpfs/test  #删除刚刚创建的文件
    [root@reddhat6_155_200 ~]# free -m   #查看当前剩余内存
                 total       used       free     shared    buffers     cached
    Mem:          3959       2509       1450          2        246       1784
    -/+ buffers/cache:        478       3481
    Swap:         3967          0       3967

    4.测试

    [root@reddhat6_155_200 ~]# cgexec -g memory:poormem dd if=/dev/zero of=/mnt/tmpfs/test bs=1M count=200 #配置的为256M 先创建一个200M 测试文件
    记录了200+0 的读入
    记录了200+0 的写出
    209715200字节(210 MB)已复制,0.097221 秒,2.2 GB/秒
    [root@reddhat6_155_200 ~]# rm -f /mnt/tmpfs/test 
    [root@reddhat6_155_200 ~]# cgexec -g memory:poormem dd if=/dev/zero of=/mnt/tmpfs/test bs=1M count=300 #创建一个300M测试文件 挂了  很奇怪,按照文档说明此处不应该挂的,应该不够的会从Swap中读取 只有 memory.memsw.limit_in_bytes 也设置了才会限制从Swap中读取 不知道为啥??????
    已杀死 [root@reddhat6_155_200 ~]# ll -h /mnt/tmpfs/test #查看大小只有
    255M -rw-r--r--. 1 root root 255M 2019-09-07 22:03 /mnt/tmpfs/test

    四、磁盘IO限制  #使用IO限制时当前系统调度算法必须为cfq算法

    [root@reddhat6_155_200 ~]# cat /sys/block/vda/queue/scheduler   #查看下当前系统磁盘调度算法 vda表示磁盘名称
    noop anticipatory deadline [cfq] 
    [root@reddhat6_155_200 ~]# cat /cgroup/blkio/blkio.weight       #查看磁盘io权重默认值
    1000
    [root@reddhat6_155_200 ~]# vim /etc/cgconfig.conf  #创建io限制规则
    group lowio{
            blkio{
              blkio.weight=100;   #设置io优先级 一个低 一个高
    }
    }
    
    group highio{
            blkio{
              blkio.weight=200;
    }
    }
    
    group ddio{
            blkio{
              blkio.throttle.read_bps_device="252:0 1000000";   
    #限制程序读取磁盘的速度 252表示当前主盘符号 0表示副盘符号 1000000表示读取速率 单位为字节 即1M 需要注意的是,如果是物理设备 SCSI设备重启后主副盘符会发生变化 可以通过设置逻辑卷 } } [root@reddhat6_155_200
    ~]# /etc/init.d/cgconfig restart Stopping cgconfig service: [确定] Starting cgconfig service: [确定]

    测试

    [root@reddhat6_155_200 ~]# dd if=/dev/zero of=/root/bigfile1 bs=1M count=10000 #创建两个大的文件用于实验
    [root@reddhat6_155_200 ~]# dd if=/dev/zero of=/root/bigfile2 bs=1M count=10000
    [root@reddhat6_155_200 ~]# echo 3 > /proc/sys/vm/drop_caches    #情况缓存 避免影响结果
    [root@reddhat6_155_200 ~]# iotop       #使用iotop命令监控io状态

    新开两个窗口,分别使用lowio和highio

    [root@reddhat6_155_200 ~]# cgexec -g blkio:lowio time cat /root/bigfile1 > /dev/null 
    [root@reddhat6_155_200 ~]# cgexec -g blkio:highio time cat /root/bigfile2 > /dev/null

    结果:当两个cat命令都读取时,使用highio磁盘速度大约是lowio的两倍

    当highio执行完成后lowio开始独占磁盘io

    [root@reddhat6_155_200 ~]# cgexec -g blkio:lowio time cat /root/bigfile1 > /dev/null 
    0.08user 7.52system 0:40.54elapsed 18%CPU (0avgtext+0avgdata 2416maxresident)k
    20480360inputs+0outputs (1major+182minor)pagefaults 0swaps
    
    [root@reddhat6_155_200 ~]# cgexec -g blkio:highio time cat /root/bigfile2 > /dev/null
    0.08user 7.16system 0:32.64elapsed 22%CPU (0avgtext+0avgdata 2432maxresident)k
    20480072inputs+0outputs (1major+183minor)pagefaults 0swaps

    限制指定用户执行指定命令

    [root@reddhat6_155_200 ~]# vim /etc/cgrules.conf 
    admin:dd    blkio   ddio/        #此行配置表示 admin用户执行dd命令时 使用 blkio子系统下ddio group进行限制  此处不仅可以现在命令也可以现在程序 添加程序的启动命令即可 例 nginx java等
    [root@reddhat6_155_200 ~]# /etc/init.d/cgred restart
    正在停止 CGroup Rules Engine 守护进程......                [确定]
    Starting CGroup Rules Engine Daemon:                    [确定]

    使用root用户测试dd命令

    [root@reddhat6_155_200 ~]# dd if=/tmp/bigfile1 of=/dev/null
    记录了20480000+0 的读入
    记录了20480000+0 的写出
    10485760000字节(10 GB)已复制,18.5243 秒,566 MB/秒  #速度正常

    切换至admin用户执行dd命令

    [root@reddhat6_155_200 ~]# mv /root/bigfile1 /tmp/
    [root@reddhat6_155_200 ~]# su -  admin
    [admin@reddhat6_155_200 ~]$ dd if=/tmp/bigfile1 of=/dev/null 

    新开一个窗口,使用iotop命令监控

    [admin@reddhat6_155_200 ~]$ dd if=/tmp/bigfile1 of=/dev/null 
    记录了210657+0 的读入
    记录了210656+0 的写出
    107855872字节(108 MB)已复制,107.986 秒,999 kB/秒  #注意此处的速率  时间是因为我提前中断了程序

    我们发现,无论怎样,IO读取不会大于1M

    注意事项:

    1 磁盘IO调度算法必须为cfq
    2 测试前需要先清空磁盘缓存
    3 不要使用SSD硬盘
    4 读取速率注意SCSI物理硬盘盘符会随机更改

    五、创建两个及以上资源控制子系统(默认每种资源只能单独控制)

    1.修改配置文件,配置一个多控制项的子系统

    [root@reddhat6_155_200 ~]# vim /etc/cgconfig.conf 
    mount {
        cpuset  = /cgroup/cpuset;
    #   cpu = /cgroup/cpu;                  #以CPU内存为例,注释cpu、memory字段
        cpuacct = /cgroup/cpuacct;
    #   memory  = /cgroup/memory;
        cpu = /cgroup/cpumem;               #新添加cpu、memory字段将其路径指向同一路径
        memory = /cgroup/cpumem;
        devices = /cgroup/devices;
        freezer = /cgroup/freezer;
        net_cls = /cgroup/net_cls;
        blkio   = /cgroup/blkio;
    }

    2.重启服务(注意:重启时需要退出/cgroup目录,否则会重启失败)

    [root@reddhat6_155_200 ~]# /etc/init.d/cgconfig restart
    Stopping cgconfig service:                                 [确定]
    Starting cgconfig service:                                 [确定]

    3.检查目录

    [root@reddhat6_155_200 ~]# ll /cgroup/
    总用量 8
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 blkio
    drwxr-xr-x. 2 root root 4096 2019-08-30 17:24 cpu
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 cpuacct
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 cpumem     #我们自定义的 
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 cpuset
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 devices
    drwxr-xr-x. 3 root root    0 2019-09-07 15:07 freezer
    drwxr-xr-x. 2 root root 4096 2019-08-30 17:24 memory
    drwxr-xr-x. 2 root root    0 2019-09-07 15:07 net_cls
    [root@reddhat6_155_200 ~]# ll /cgroup/cpu                  #原先的cpu及memory已经失效了
    总用量 0
    [root@reddhat6_155_200 ~]# ll /cgroup/memory/
    总用量 0
    [root@reddhat6_155_200 ~]# ll /cgroup/cpumem/              #所有mem和cpu配置都在cpumem目录下
    总用量 0
    --w--w--w-. 1 root root 0 2019-09-07 15:07 cgroup.event_control
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cgroup.procs
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cpu.cfs_period_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cpu.cfs_quota_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cpu.rt_period_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cpu.rt_runtime_us
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 cpu.shares
    -r--r--r--. 1 root root 0 2019-09-07 15:07 cpu.stat
    -rw-r--r--. 1 root root 0 2019-09-07 15:07 memory.failcnt
    --w-------. 1 root root 0 2019-09-07 15:07 memory.force_empty
    ......

    参考文档:https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/6/html/resource_management_guide/sec-moving_a_process_to_a_control_group#The_cgred_Daemon

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/panwenbin-logs/p/11481108.html
Copyright © 2011-2022 走看看