热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

MySQL调优基础(四)Linux磁盘IO_MySQL

1.IO处理过程磁盘IO经常会成为系统的一个瓶颈,特别是对于运行数据库的系统而言。数据从磁盘读取到内存,在到CPU缓存和寄存器,然后进行处理,最后写回磁盘,中间要经过很多的过程,下图是一个以write为
1. IO处理过程

磁盘IO经常会成为系统的一个瓶颈,特别是对于运行数据库的系统而言。数据从磁盘读取到内存,在到CPU缓存和寄存器,然后进行处理,最后写回磁盘,中间要经过很多的过程,下图是一个以write为例的 Linux 磁盘IO子系统的架构:

可以看到IO操作分成了四个层面:

1)文件系统缓存:处理数据必须先从磁盘读到缓存,然后修改,然后刷会磁盘。缓存的刷新涉及到两个参数:vm.dirty_background_ratio、vm.dirty_ratio。还有刷新写回时,使用到 bio 结构,bio的组成是由磁盘上相邻的block组成的,所以这里进行了优化。

2)block layer:该层就涉及到 IO调度算法,IO调度算法在mysql服务器是一个很重要的调优手段。系统中所有进程申请的IO操作,全部在这里进行排队,等待调度,然后写回磁盘。调度算法有四种:

1> Anticipatory: 适用于个人PC,单磁盘系统;

2> CFQ(Complete Fair Queuing):默认的IO调度算法,完全公平的排队调度算法。每一个进程的IO请求会安排进一个专门的IO队列,然后按照进程组来公平的调度IO,也就是每一个进程组之间按照公平的方式来调度IO。显然他适合多用户的系统,但是极为不适合作为数据库系统的IO调度算法,因为显而易见,数据库系统中,数据库进程肯定是IO最多的一个进程组,然后它却只能获得和其它进程一样多的IO调度机会。所以显然这是极为不合理的。数据库系统绝对不要使用该调度算法。

3> Deadline: 按照截止期限来循环在各个IO队列中进行调度,所以它提供了一个近实时的IO系统,并且磁盘throughput也很好,也不会造成starvation.一般mysql系统建议采用该调度算法。

4> NOOP: 简单的FIFO队列进行调度,No operation的意思是,它没有进行额外的将临近的IO进行合并的操作,所以它对CPU的使用极少。该调度算法特别适合于SSD。因为SSD在对待顺序IO和随机IO没有什么区别。所以它不需要对临近的IO进行合并。避免了合并操作对CPU的使用。

所以一般而言,对于mysql的系统,如果是SSD,那么应该使用NOOP调度算法,如果是磁盘,就应该使用Deadline调度算法。

查看与修改IO调度算法:

临时修改:

[root@localhost ~]# cat /sys/block/sda/queue/scheduler

noop anticipatory deadline [cfq]

[root@localhost ~]# echo noop > /sys/block/sda/queue/scheduler

[root@localhost ~]# cat /sys/block/sda/queue/scheduler

[noop] anticipatory deadline cfq

永久修改:

# vi /boot/grub/menu.lst

更改到如下内容:

kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet

重启之后,查看调度方法:

# cat /sys/block/sda/queue/scheduler

noop anticipatory [deadline] cfq

已经是deadline了

3)磁盘驱动层:对于顺序读系统而言,很容易在磁盘接口层的带宽上成为瓶颈所在;

4)磁盘:对于随机读多的系统而言,磁盘很容易成为瓶颈所在,一般的优化就是使用RAID或者换SSD;

2. IO瓶颈检测

2.1 使用 iostat 查看磁盘IO

显示单位问题:默认iostat是以磁盘的block为单位,也可以使用 -k 来指定以 kilobytes 为单位,或者使用 -m 指定 megabytes 为单位;

统计开始时间问题:默认iostat和vmstat相似,默认第一次/行都是从开机到目前的一个数据,可以使用 -y 选项去掉第一次/行的数据;

CPU与磁盘: iostat 默认会显示cpu和磁盘的数据,如果只要cpu数据可以使用 -c 选项,如果只需要磁盘数据,可以使用 -d 选项;

时间间隔和重复次数:[interval [times]] 表示磁盘统计数据的间隔时间和次数;

-x : 该选项显示具体的扩展信息;

[root@localhost ~]# iostat
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.60    0.00    7.80    0.31    0.00   91.30

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
scd0              0.02         0.21         0.00        536          0
sda               2.00        78.60         8.43     198702      21312[root@localhost ~]# iostat -c
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.48    0.00    6.51    0.25    0.00   92.76
[root@localhost ~]# iostat -d -k
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
scd0              0.02         0.08         0.00        268          0
sda               1.69        31.17         4.15      99363      13224

[root@localhost ~]# iostat -d -m
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
scd0              0.02         0.00         0.00          0          0
sda               1.69         0.03         0.00         97         12

[root@localhost ~]# iostat -d -m -x
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.02     0.00    0.02    0.00     0.00     0.00    10.94     0.00    4.96   4.88   0.01
sda               1.22     0.48    1.13    0.56     0.03     0.00    41.66     0.01    6.83   5.27   0.89

[root@localhost ~]# iostat -d -m -x 2 3
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.02     0.00    0.01    0.00     0.00     0.00    10.94     0.00    4.96   4.88   0.01
sda               1.19     0.48    1.10    0.55     0.03     0.00    41.52     0.01    6.81   5.25   0.87

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda               0.00     0.00    0.00    0.51     0.00     0.00     8.00     0.00    3.00   3.00   0.15

[root@localhost ~]# iostat -y -d -m -x 2 3
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

字段含义:

Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn 分别表示:每秒读取block的个数,每秒写block的个数,总共读了多少个block,总共写了多少个block

tps: Indicate the number of transfers per second that were issued to the device. A transfer is an I/O request to the device. Multiple logical requests can be combined into a single I/O request to the device. A transfer is of indeterminate size.(就是对磁盘每秒请求多少次IO操作)

rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await svctm %util

rrqm/s wrqm/s 表示的磁盘读和写时每秒发生多少次相邻磁盘的merge操作;rrqm: read request merge; wrqm:write request merge

r/s w/s 表示每秒读的次数,写的次数;

rMB/s wMB/s 表示每秒读多少MB,写多少MB

avgrq-sz:The average size (in sectors) of the requests that were issued to the device. 平均一个IO请求涉及到多少个sector

avgqu-sz:The average queue length of the requests that were issued to the device. IO队列的平均长度,该数值很重要。

await:The average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them.平均每一个IO花费了多少毫秒(包括在IO队列中的排队时间和读写操作花费的时间)。这里可以理解为IO的响应时间,一般地系统IO响应时间应该低于5ms,如果大于10ms就比较大了。

svctm:弃用

%util :Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%. 在统计时间内所有处理IO时间,除以总共统计时间。例如,如果统计间隔1秒,该设备有0.8秒在处理IO,而0.2秒闲置,那么该设备 的%util = 0.8/1 = 80%,所以该参数暗示了设备的繁忙程度。一般地,如果该参数是100%表示设备已经接近满负荷运行了(当然如果是多磁盘,即使%util是100%,因 为磁盘的并发能力,所以磁盘使用未必就到了瓶颈)。

CPU的 %iowait io等待很高;

磁盘的 avgqu-sz数值很大;await数值很高;%util数值很高;都可能预示着磁盘存在瓶颈或者磁盘出现问题或者故障。

2.2 使用 iostat 查看磁盘每个分区的IO

上面查看的都是整个磁盘的IO情况,下面的命令可以查看具体某个磁盘的所有分区的IO情况:

[root@localhost ~]# iostat -x -d -m -p sda 2 3
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.82     0.43    0.76    0.52     0.02     0.00    38.49     0.01    6.27   4.82   0.62
sda1              0.80     0.42    0.53    0.51     0.02     0.00    45.09     0.01    6.92   5.50   0.57
sda2              0.01     0.02    0.12    0.01     0.00     0.00     9.70     0.00    2.95   2.79   0.04
sda3              0.01     0.00    0.07    0.00     0.00     0.00     8.67     0.00    3.72   3.65   0.03

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda2              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda3              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda2              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sda3              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00

[root@localhost ~]# iostat -d -m -p sda 2 3
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda               1.25         0.02         0.00         97         18
sda1              1.02         0.02         0.00         92         17
sda2              0.13         0.00         0.00          2          0
sda3              0.07         0.00         0.00          1          0

Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda               0.00         0.00         0.00          0          0
sda1              0.00         0.00         0.00          0          0
sda2              0.00         0.00         0.00          0          0
sda3              0.00         0.00         0.00          0          0

Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda               0.00         0.00         0.00          0          0
sda1              0.00         0.00         0.00          0          0
sda2              0.00         0.00         0.00          0          0
sda3              0.00         0.00         0.00          0          0

2.3 使用 vmstat 查看磁盘IO

[root@localhost ~]# vmstat 2 4
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 454900  21808  76776    0    0    20     4   97   81  0  5 95  0  0
 0  0      0 454892  21808  76772    0    0     0     8   83  106  0  3 97  0  0
 1  0      0 454760  21816  76772    0    0     0    44  101  153  1  5 94  0  0
 0  0      0 454760  21816  76784    0    0     0     0   57   68  0  1 99  0  0

bi: Blocks received from a block device (blocks/s). 每秒读取多少个block到内存

bo: Blocks sent to a block device (blocks/s). 每秒内存写出多少个block到磁盘

2.4 使用 sar -b 查看磁盘IO

[root@localhost ~]# sar -b 2 4
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/09/2015      _i686_  (1 CPU)

03:53:21 PM       tps      rtps      wtps   bread/s   bwrtn/s
03:53:23 PM      0.00      0.00      0.00      0.00      0.00
03:53:25 PM      0.00      0.00      0.00      0.00      0.00
03:53:27 PM      0.00      0.00      0.00      0.00      0.00
03:53:29 PM      0.00      0.00      0.00      0.00      0.00
Average:         0.00      0.00      0.00      0.00      0.00

tps: 上面有介绍;rtps: 表示读的tps;wtps: 表示写的tps;

bread/s: 每秒读多少个block;bwrtn/s: 每秒写多少个block;

2.5 使用 iotop 找到IO最多的进程/线程

iotop类似于top命令,默认按照IO排序:

iotop :

iotop 是可以交互的:

Use the left and right arrows to change the sorting, r to reverse the sorting order, o to toggle the --only

option, p to toggle the --processes option, a to toggle the --accumulated option, q to quit or i to change the

priority of a thread or a process’ thread(s). Any other key will force a refresh.

1)利用左右键 可以选择排序的字段,默认按照IO>倒序,可以按照SWAPIN,DISK WRITE 等等字段排序,使用左右方向键即可;

2)利用 p键 可以在按照 进程显示 和按照 线程显示之间切换;

3)r 键可以改变排序的方向:倒序 和 顺序

查看mysqld的IO:

iotop -k -u mysql (-k 表示KB,-u mysql表示显示mysql用户的所有进程的IO):

3. 实例分析

$iostat -d -k 1 |grep sda10
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda10            60.72        18.95        71.53  395637647 1493241908
sda10           299.02      4266.67       129.41       4352        132
sda10           483.84      4589.90      4117.17       4544       4076
sda10           218.00      3360.00       100.00       3360        100
sda10           546.00      8784.00       124.00       8784        124
sda10           827.00     13232.00       136.00      13232        136

上面看到,磁盘每秒传输次数平均约400;每秒磁盘读取约5MB,写入约1MB。

iostat -d -x -k 1

Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util

sda 1.56 28.31 7.84 31.50 43.65 3.16 21.82 1.58 1.19 0.03 0.80 2.61 10.29

sda 1.98 24.75 419.80 6.93 13465.35 253.47 6732.67 126.73 32.15 2.00 4.70 2.00 85.25

sda 3.06 41.84 444.90 54.08 14204.08 2048.98 7102.04 1024.49 32.57 2.10 4.21 1.85 92.24

可以看到磁盘的平均响应时间<5ms,磁盘使用率>80。磁盘响应正常,但是已经很繁忙了。

4. 磁盘IO优化

磁盘IO在优化之前,首先要弄清楚系统的IO情况,是随机IO多,还是顺序IO多,是大文件IO多,还是小文件IO多(小文件IO一般也就是随机IO)。比如随机IO多,那么就可以通过加磁盘使用RAID技术来优化,如果是顺序IO遇到瓶颈,一般可能是磁盘驱动的带宽有瓶颈,就可以换一个更快的disk controller。搞清楚是磁盘有瓶颈,还是磁盘驱动的带宽有瓶颈。

因为磁盘IO的操作分成了4个层面,所以IO的优化也可以从这四个方面入手:

1)正对mysql系统的调优,还需要选择正确的IO调度算法,如果是SSD,选择NOOP调度算法,如果是磁盘,那么选择deadline调度算法;

2)针对mysql还显然可以通过maser-slave来读写分离进行磁盘IO优化。

3)另外增大内存,可以对更多的磁盘文件进行缓存,也能减轻IO压力。

4)还有文件系统的挂载选项 noatime, nodiratime也能减轻IO压力,另外选择正确的文件系统也能提高磁盘的tps. mysql数据库推荐使用XFS文件系统。

注:上面显示的磁盘IO的数据,很多都是0,这是因为数据来自于虚拟机中的Linux系统。

推荐阅读
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Paxos的世界中关于复制日志与状态机的概念和重要性。通过存储日志来实现数据的持久化,并通过日志流来记录数据的变化,而不是直接持久化数据本身。这样做的好处是简化了持久化存储的操作,并且方便多机之间的数据同步。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
author-avatar
主播新鲜看连
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有