Nginx比Apache高效的原理

一、web服务器


基本的web服务器的特性

1.处理静态文件,索引文件以及自动索引,
    打开文件描述符缓存(最后一句是Nginx的重要特性,Nginx可以缓存页面的元数据,页面由元数据和数据组成)
2.使用缓存加速反向代理,简单负载均衡以及容错:
    在反向代理时,能实现后端服务器的健康状态检查,一旦发现故障立即清除,但是这种容错需要安装第三方模块才能实现,
    这个第三方模块不支持Nginx1.2的版本只支持1.0版本,淘宝对其做了扩充,把大量第三方模块整合到Nginx,
    并对其做了大量改进,所以二次发行版本,叫做Tengine
    Tengine
3.远程FastCGI(支持php,apache是做成模块的方式来支持php),uwsgi(支持python的web框架而且比FastCGI高效很多,不支持php),SCGI,和memcached服务的缓存加速支持
    varnish:缓存服务器
    squid:缓存服务器
    nginx也有缓存能力,缓存页面时是在磁盘上的,把打开的缓存描述符放到内存里
    httpd:也支持缓存,既可以支持磁盘,也可以支持内存
    memcached:nginx本身是模块化设计,可以直接联系memcached,管理静态内容时,可以将数据直接缓存到memcached中
4.模块化的架构,过滤器包括gzip压缩,ranges支持,chunkea响应,XSLT,SSI以及图像缩放,在SSI过滤器中,一个包含多个SSI的页面,如果经由FastCGI或反向代理处理,可悲并行处理
5.支持SSL,TLS,SNI

其他的HTTP服务器特性

1.基于名字和IIP的虚拟主机
2.Keepalive和pipelined连接支持
3.灵活的配置
4.重新加载配置以及在线升级时,不需要中断正在处理的请求
    Nginx热部署/平滑升级:不需要中断正在处理的请求
5.自定义访问日志格式,带缓存的日志写操作,以及快速日志轮转
6.重写(rewrite)模块,使用正则表达式的访问控制
7.支持验证HTTP_referer,支持反盗链机制
8.支持PUT,DELETE,MKCOL,COPY以及MOVE方法
9.支持FLV流和MP4流(能让客户变下载边播放)
10.速度限制
11.来自于同一地址的同时连接数和请求数限制
12.嵌入Perl语言

web服务器处理请求的过程


1:客户端发请求到服务器端,由服务器端的网卡接收

2:网卡接收后,发给内核,由内核处理

3:内核解包之后发现该包是发给80端口的,将包通过套接字发给web服务

4:web服务解包之后,知道客户端要请求的数据,然后进行系统调用,陷入内核

5,6:内核收到web服务的请求之后调用驱动程序到磁盘上找客户要的web资源

7:找到之后,内核将数据放到自己的缓冲区

8:内核把web资源放到,web进程自己的缓冲区中

9:web服务再次进行系统调用,将响应通过套接字发送给内核

10:内核将相应发送到网卡

11:由网卡最终发送给客户端


在上面的过程中,有两个I/O过程,一个是客户端请求的网络I/O,另一个是服务器端请求web资源时的磁盘I/O,接下来我们来看Linux的I/O模型。



二、I/O模型


web服务如果需要使用I/O资源时,需要进行系统调用,直到内核把数据放到web服务进程的缓冲区后,才是一次完整的I/O调用,就是上面 的第4,5,6,7,8阶段。

其中占用时间长的是,当从磁盘把资源放到内核的缓冲区(wait),而把资源从内核的缓冲区放到web服务进程的缓冲区(copy),这其实是不占时间的,因为是在内存里边折腾,当然用不了多长时间呀。

根据wait和copy阶段的处理等待的机制不同,可将I/O动作分为如下五种模式:

  • 阻塞I/O
  • 非阻塞I/O
  • I/O复用(select和poll)
  • 信号(事件)驱动I/O(SIGIO)
  • 异步I/O(aio)

 五种I/O模型中,前三种属于同步I/O,后两者属于异步I/O。

 在讨论着5种模式之前我们先来,了解阻塞,非阻塞,同步,异步

  *阻塞:在你得到这个资源之前,你都得一直等在那里

  *非阻塞:在你发出要得到这个资源之后,你不必一直等在那里,你可以去干其他事情,但是你需要一会来问一下好了没有,如果不这样做的话你怎么知道,你要的东西CPU给你准备好了没有。

  *同步:在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

  *异步:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

1.阻塞I/O

  说明:应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。 如果数据没有准备好,一直等待数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。这个不用多解释吧,阻塞套接字。下图是它调用过程的图示:(注,一般网络I/O都是阻塞I/O,客户端发出请求,Web服务器进程响应,在进程没有返回页面之前,这个请求会处于一直等待状态)


例子:我点了一份餐,但是这家餐厅,服务不是很好,我需要一直在那等我的餐做好。

2.非阻塞I/O

 我们把一个套接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误。这样我们的I/O操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间,所有一般Web服务器都不使用这种I/O模型。具体过程如下图:


    例子:我点了一份餐,这家餐厅服务依然不是很好,我不想等了,我就去干我自己的事情,干一会回来问一下我的餐好了没有。

3.I/O复用(select和poll)

 I/O复用模型会用到select或poll函数或epoll函数(Linux2.6以后的内核开始支持),这两个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。具体过程如下图:


  例子:我点了一份餐,这次餐厅升级了,安了一个液晶显示屏,上面轮流播放谁的餐做好了,我可以干我自己的事情,等下直接看屏幕就好了。

4.信号(事件)驱动I/O(SIGIO)

首先,我们允许套接口进行信号驱动I/O,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用I/O操作函数处理数据。

    水平触发:通知多次

    边沿触发:只通知一次

具体过程如下图:

 

   例子:我点了一份餐,餐厅又升级了,当我的餐做好之后,就会有人来告诉我餐好了,我直接去取。

5.异步I/O(aio)

 当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者的输入输出操作。具体过程如下图:


   例子:我点了一份餐,餐厅再次升级,我的餐好了之后,会有人直接把餐给我送过来,在这期间我想干什么就干什么。


三、I/O模型的实现

主要实现形式

  • select
  • poll
  • epoll
  • kqueue
  • /dev/poll
  • iocp

注,其中iocp是Windows实现的,select、poll、epoll是Linux实现的,kqueue是FreeBSD实现的,/dev/poll是SUN的Solaris实现的。select、poll对应第3种(I/O复用)模型,iocp对应第5种(异步I/O)模型,那么epoll、kqueue、/dev/poll呢?其实也同select属于同一种模型,只是更高级一些,可以看作有了第4种(信号驱动I/O)模型的某些特性,如callback机制。


select的几大缺点:

(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

(3)select支持的文件描述符数量太小了,默认是1024

select、poll、epoll三者的区别,http://blog.youkuaiyun.com/turkeyzhou/article/details/8504554


在上面的web服务器处理请求的流程中,我们可以发现,内核把资源从磁盘拿出来之后,给了web服务,然后web服务又把资源放到内核了,这样不就是web资源白白到用户态走了一圈,占用了CPU资源,那有没有什么机制,可以让资源不经过web的用户态,就直接发送出去?

sendfile机制:

Linux 2.1版本内核引入了sendfile函数,用于将文件通过socket传送。
sendfile(socket, file, len);
该函数通过一次系统调用完成了文件的传送,减少了原来 read/write方式的模式切换。此外更是减少了数据的copy

通过sendfile传送文件只需要一次系统调用,当调用 sendfile时:
1。首先通过DMA copy将数据从磁盘读取到kernel buffer
2。然后通过CPU copy将数据从kernel buffer copysokcet buffer
3。最终通过DMA copysocket buffer中数据copy到网卡buffer中发送
sendfileread/write方式相比,少了一次模式切换一次CPU copy。但是从上述过程中也可以发现从kernel buffer中将数据copysocket buffer是没必要的。


改进后的处理过程如下:
1
DMA copy将磁盘数据copykernel buffer
2
。向socket buffer中追加当前要发送的数据在kernel buffer中的位置和偏移量
3
DMA gather copy根据socket buffer中的位置和偏移量直接将kernel buffer中的数据copy到网卡上。
经过上述过程,数据只经过了2copy就从磁盘传送出去了。
(可能有人要纠结不是说ZeroCopy么?怎么还有两次copy,事实上这个Zero copy是针对内核来讲的,数据在内核模式下是Zerocopy的。话说回来,文件本身在瓷盘上要真是完全Zerocopy就能传送,那才见鬼了 呢)。
当前许多高性能http server都引入了sendfile机制,如nginxlighttpd等。


为什么epoll、kqueue、/dev/poll比select高级?

答案是,他们无轮询。因为他们用callback取代了。想想看,当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll、kqueue、/dev/poll做的。这样子说可能不好理解,那么我说一个现实中的例子,假设你在大学读书,住的宿舍楼有很多间房间,你的朋友要来找你。select版宿管大妈就会带着你的朋友挨个房间去找,直到找到你为止。而epoll版宿管大妈会先记下每位同学的房间号,你的朋友来时,只需告诉你的朋友你住在哪个房间即可,不用亲自带着你的朋友满大楼找人。如果来了10000个人,都要找自己住这栋楼的同学时,select版和epoll版宿管大妈,谁的效率更高,不言自明。同理,在高并发服务器中,轮询I/O是最耗时间的操作之一,select、epoll、/dev/poll的性能谁的性能更高,同样十分明了。

Windows or *nix (IOCP or kqueue、epoll、/dev/poll)?

诚然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系统,但是由于其系统本身的局限性,大型服务器还是在UNIX下。而且正如上面所述,kqueue、epoll、/dev/poll 与 IOCP相比,就是多了一层从内核copy数据到应用层的阻塞,从而不能算作asynchronous I/O类。但是,这层小小的阻塞无足轻重,kqueue、epoll、/dev/poll 已经做得很优秀了。

总结一些重点

只有IOCP(windows实现)是asynchronous I/O,其他机制或多或少都会有一点阻塞。

select(Linux实现)低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善

epoll(Linux实现)、kqueue(FreeBSD实现)、/dev/poll(Solaris实现)是Reacor模式,IOCP是Proactor模式。

Apache 2.2.9之前只支持select模型,2.2.9之后支持epoll模型

Nginx 支持epoll模型

Java nio包是select模型




四、Apache的工作模式

Apache通过MPM(多处理模块)来使用操作系统的资源,对进程和线程池进行管理。Apache为了能够获得最好的运行性能,针对不同的平台(Unix/Linux、Window)做了优化,为不同的平台提供了不同的MPM,用户可以根据实际情况进行选择,其中最常使用的MPM有 prefork和worker两种。由于大多数的Unix都不支持真正的线程,所以采用了预派生子进程(prefork)方式。

Apache服务的三种工作模式:prefork和worker和event
1、Prefork MPM

Prefork MPM实现了一个非线程的、预派生的web服务器。它在Apache启动之初,就先预派生一些子进程,然后等待连接;可以减少频繁创建和销毁进程的开销,每个子进程只有一个线程,在一个时间点内,只能处理一个请求。这是一个成熟稳定,可以兼容新老模块,也不需要担心线程安全问题,但是一个进程相对占用资源,消耗大量内存,不擅长处理高并发的场景。

prefork的具体工作原理是,控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足MinSpareServers设置的值为止。这就是预派生(prefork)的由来。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。

2、Worker MPM

和prefork模式相比,worker使用了多进程和多线程的混合模式,worker模式也同样会先预派生一些子进程,然后每个子进程创建一些线程,同时包括一个监听线程,每个请求过来会被分配到一个线程来服务。线程比起进程会更轻量,因为线程是通过共享父进程的内存空间,因此,内存的占用会减少一些,在高并发的场景下会比prefork有更多可用的线程,表现会更优秀一些;另外,如果一个线程出现了问题也会导致同一进程下的线程出现问题,如果是多个线程出现问题,也只是影响Apache的一部分,而不是全部。由于用到多进程多线程,需要考虑到线程的安全了,在使用keep-alive长连接的时候,某个线程会一直被占用,即使中间没有请求,需要等待到超时才会被释放(该问题在prefork模式下也存在)。

3、Event MPM

这是Apache最新的工作模式,它和worker模式很像,不同的是在于它解决了keep-alive长连接的时候占用线程资源被浪费的问题,在event工作模式中,会有一些专门的线程用来管理这些keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务器的线程,执行完毕后,又允许它释放。这增强了在高并发场景下的请求处理。

Apache httpd 能更好的为有特殊要求的站点定制。例如,要求 更高伸缩性的站点可以选择使用线程的 MPM,即 worker 或 event; 需要可靠性或者与旧软件兼容的站点可以使用 prefork。


关于这部分的详细介绍,http://blog.youkuaiyun.com/hguisu/article/details/7395181


五、Nginx的工作原理

Nginx 是一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够不间断服务的情况下进行软件版本的升级 .

Nginx可以做什么:

    1>是一个web服务器,具有基本web服务器所要求的所有功能,所以当用不到Apache所拥有的特有功能时,Nginx是首选
    2>轻量级的反向代理
        1)web
        2)mail:很少用到


Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均应以非特权用户身份运行。

主进程主要完成如下工作


  •     1.读取并验证配置信息
        2.创建,绑定及关闭套接字
        3.启动、终止及维护worker进程的个数
        4.无需终止服务而重新配置工作特性
        5.控制非中断式程序升级,启用新的二进制程序并在需要时回滚值老版本
        6.重新打开日志文件,实现日志滚动
        7.编译嵌入式perl脚本
       
  • worker进程主要完成的任务包括
        1.接收、传入并处理来自客户端的连接
        2.提供反向代理及过滤功能
        3.Nginx任何能完成其他任务

    cache loader进程主要完成的任务包括
        1.检查缓存存储中的缓存对象
        2.使用缓存元数据建立内存数据库

    cache manager进程的主要任务
        1.缓存的失效及过期检验

    Nginx的配置有着几个不同的上下文
        main:对任何功能都生效的配置,user,group,worker
        http:只对web服务器有效
        mail:对邮件服务器有效
        server:一般必须属于http
        upstream:实现定义反向代理
        location:属于server(还有)

注:如果负载以CPU密集型应用为主,如SSL或压缩应用,则worker数应与CPU数相同;如果负载以IO密集型为主,如响应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。


2.Nginx架构

Nginx的代码是由一个核心和一系列的模块组成, 核心主要用于提供Web Server的基本功能,以及Web和Mail反向代理的功能;还用于启用网络协议,创建必要的运行时环境以及确保不同的模块之间平滑地进行交互。不过,大多跟协议相关的功能和某应用特有的功能都是由nginx的模块实现的。这些功能模块大致可以分为事件模块、阶段性处理器、输出过滤器、变量处理器、协议、upstream和负载均衡几个类别,这些共同组成了nginx的http功能。事件模块主要用于提供OS独立的(不同操作系统的事件机制有所不同)事件通知机制如kqueue或epoll等。协议模块则负责实现nginx通过http、tls/ssl、smtp、pop3以及imap与对应的客户端建立会话。在Nginx内部,进程间的通信是通过模块的pipeline或chain实现的;换句话说,每一个功能或操作都由一个模块来实现。例如,压缩、通过FastCGI或uwsgi协议与upstream服务器通信,以及与memcached建立会话等。


3.Nginx基础功能

  • 处理静态文件,索引文件以及自动索引;
  • 反向代理加速(无缓存),简单的负载均衡和容错;
  • FastCGI,简单的负载均衡和容错;
  • 模块化的结构。过滤器包括gzipping, byte ranges, chunked responses, 以及 SSI-filter 。在SSI过滤器中,到同一个 proxy 或者 FastCGI 的多个子请求并发处理;
  • SSL 和 TLS SNI 支持;

4.Nginx IMAP/PHP3代理服务功能

  • 使用外部 HTTP 认证服务器重定向用户到 IMAP/POP3 后端;
  • 使用外部 HTTP 认证服务器认证用户后连接重定向到内部的 SMTP 后端;
  • 认证方法:
  • POP3: POP3 USER/PASS, APOP, AUTH LOGIN PLAIN CRAM-MD5;
  • IMAP: IMAP LOGIN;
  • SMTP: AUTH LOGIN PLAIN CRAM-MD5;
  • SSL 支持;
  • 在 IMAP 和 POP3 模式下的 STARTTLS 和 STLS 支持;

5.Nginx结构与扩展

  • 一个主进程和多个工作进程,工作进程运行于非特权用户;
  • kqueue (FreeBSD 4.1+), epoll (Linux 2.6+), rt signals (Linux 2.2.19+), /dev/poll (Solaris 7 11/99+), select, 以及 poll 支持;
  • kqueue支持的不同功能包括 EV_CLEAR, EV_DISABLE (临时禁止事件), NOTE_LOWAT, EV_EOF, 有效数据的数目,错误代码;
  • sendfile (FreeBSD 3.1+), sendfile (Linux 2.2+), sendfile64 (Linux 2.4.21+), 和 sendfilev (Solaris 8 7/01+) 支持;
  • 输入过滤 (FreeBSD 4.1+) 以及 TCP_DEFER_ACCEPT (Linux 2.4+) 支持;
  • 10,000 非活动的 HTTP keep-alive 连接仅需要 2.5M 内存。
  • 最小化的数据拷贝操作;

6.Nginx其他HTTP功能

  • 基于IP 和名称的虚拟主机服务;
  • Memcached 的 GET 接口;
  • 支持 keep-alive 和管道连接;
  • 灵活简单的配置;
  • 重新配置和在线升级而无须中断客户的工作进程;
  • 可定制的访问日志,日志写入缓存,以及快捷的日志回卷;
  • 4xx-5xx 错误代码重定向;
  • 基于 PCRE 的 rewrite 重写模块;
  • 基于客户端 IP 地址和 HTTP 基本认证的访问控制;
  • PUT, DELETE, 和 MKCOL 方法;
  • 支持 FLV (Flash 视频);
  • 带宽限制;

7.为什么选择Nginx

  • 在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型。
  • Nginx作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。
  • 作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验.
  • Nginx 安装非常的简单 , 配置文件非常简洁(还能够支持perl语法),Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够 不间断服务的情况下进行软件版本的升级 。
  • Nginx 的诞生主要解决C10K问题

8.如何提高web服务器的并发连接处理能力

有几个基本条件:

  • 基于线程,即一个进程生成多个线程,每个线程响应用户的每个请求。
  • 基于事件的模型,一个进程处理多个请求,并且通过epoll机制来通知用户请求完成。
  • 基于磁盘的AIO(异步I/O)
  • 支持mmap内存映射,mmap传统的web服务器,进行页面输入时,都是将磁盘的页面先输入到内核缓存中,再由内核缓存中复制一份到web服务器上,mmap机制就是让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去。

刚好,Nginx 支持以上所有特性。所以Nginx官网上说,Nginx支持50000并发,是有依据的。

 


六、Nginx与Apache的比较


作为 Web 服务器,Nginx的优点:

1.相比 Apache,Nginx 使用更少的资源

2.支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应,

3.高度模块化的设计,编写模块相对简单

4.社区活跃,各种高性能模块出品迅速啊


作为web服务器,Apache的优点

1.rewrite ,比nginx 的rewrite 强大

2.动态页面

3.模块超多,基本想到的都可以找到

4.少bug ,nginx 的bug 相对较多

5.超稳定


两者之间如何选择?

一般来说,需要性能的web 服务,用nginx 。如果不需要性能只求稳定,那就apache 吧。后者的各种功能模块实现得比前者,例如ssl 的模块就比前者好,可配置项多。这里要注意一点,epoll(freebsd 上是 kqueue )网络IO 模型是nginx 处理性能高的根本理由,但并不是所有的情况下都是epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文

件,apache 的select 模型或许比epoll 更高性能。当然,这只是根据网络IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。


服务器的选择


  1. Apache:属于重量级web服务器(重量级主要是在软件包的大小上比较大,软件的耦合度大),但是速度、性能不及其他轻量级web服务器,并且消费内存较高。使用传统的select模型,比较稳定的Prefork模式为多进程模式,需要经常派生子进程。所以消耗的cpu等服务器资源比较大。

  2. Lighttpd:轻量级web服务器,cpu占用低,效能好,模块丰富。

  3. Tomcat:运行:Servlet和Jsp web的应用软件的容器,静态和高并发处理弱。

  4. Nginx:轻量级,高性能http和反向代理服务器。高并发连接达到2-4万个,内存、cpu等系统资源消耗低。Rewrite重写规则(根据域名,URL的不同将HTTP请求分到不同的后端服务器群组),内置的健康检查功能(Nginx Proxy 后端的某台web服务器宕机也不会影响前端访问),节省带宽(支持GZIP压缩,可以添加浏览器本地缓存的Header头)。




参考文章:http://www.toxingwang.com/linux-unix/linux-basic/1712.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值