您的位置:首页 > 运维架构 > Linux

Linux运维 第三阶段 (十八) haproxy

2016-01-08 21:35 656 查看
Linux运维 第三阶段 (十八) haproxy
一、相关概念:
nginx作为reverse proxy(若用户请求的资源nginx上没有,这时nginx就要转发;若用户请求的uri,nginx上就没定义,则nginx直接返回错误页面(一般403禁止访问、404未找到、502网关错误)
squid在实现向后端转发时是同步的(将前端的连接直接到后端,后端server的压力会很大);而nginx是异步转发模式(将前端报文转至后端时可以对其处理,例如,proxy_set_header X-Real-IP $remote_addr,add_header X-Via $server_addr,add_header X-Cache $upstream_cache_status)
nginx的调优之一就是调整内存空间大小(调cache/buffer的大小,nginx是异步模型,client请求连接进来要使用内存空间暂存用户会话,后端server响应后,报文必须先接收下来暂存在本地内存中,而后再封装响应给client,这些内存空间多大为最优,需要根据实际服务器的计算能力和业务需求调整(cache/buffer有很多,如打开文件的cache、打开日志的cache、fastcgi的cache、reverse_proxy的cache、gzip压缩的cache),若调大可缓存更多内容,但太大短时间内的请求蜂拥而至,实际内存不够用系统就崩溃了)
tengine(tengine.taobao.org,附带很多nginx不具备的功能,进程名仍是nginx,tengine的命令行比nginx更简单明晰,支持动态模块加载DSO(nginx是高度模块化的,必须在开始安装时就编译好相关模块,tengine支持动态模块,类似httpd可单独编译模块再装载至httpd中),tengine对于worker_processes不用配置可自动选择将进程绑定CPU(亲缘性,将CPU核心与进程绑定,可避免进程切换,能最大发挥CPU性能))

haproxy(the reliable、high performance、tcp/http LB):
工作在四层、七层,主要实现对http协议实施反向代理和负载均衡(reverse proxy server或load balance server),也扩展支持众多的tcp协议(如memcached)
haproxy:
类似nginx,nginx、haproxy都具有一定的ha功能(这种ha功能不是自身提供的,而是将用户请求代理至后端时可自动检查后端server的health_check,如可剔除那些不正常的RS,当RS正常后又会加回来)

两种模式的reverse proxy:
工作在内核,如LVS,功能及特性不够丰富(也有直接在内核上工作的web server);
工作在用户空间,CS进程上下文切换,内核<-->用户空间之间转换(系统调用)不可避免,而且这些CS、空间转换相当耗费资源

nginx、haproxy无法避免打开最大套接字文件的限制(一个计算机打开的文件(如socket文件)最多为65535个,意味着代理时最大的并发连接达到几万个就不错了(系统本身运行时也要使用,同时还要运行其它程序),如nginx能达到3-4W个经优化甚至最多能达到5W个,但LVS突破了这个限制(单从性能上LVS大大超过了nginx和haproxy,但相较于nginx、haproxy,LVS的功能简单配置复杂,若要用到七层功能的一些特性,nginx和haproxy是首选)
只要并发连接数不是很大(若并发连接很大非LVS莫属),haproxy自带的有一个web接口(显示界面非常直观,强大且易于管理),可安装上haproxy后,打开一个web页面,能查看当前有多少个连接,每一个后端server建立了多少连接,后端server的health状况,最大接受的连接数等,还可对后端RS进行管理,如将某个RS给down
haproxy在转发的特性上比nginx有着更强的可订制性,但在转发同样的连接上比nginx所需更多的资源(内存、CPU等)
haproxy基于event-driven,用单一进程来响应众多连接(nginx可启用多个worker进程,而haproxy完全使用一个进程响应(向后代理),虽然也可开启多进程模式,但官方不建议这么做)

haproxy版本有两个1.3和1.4,这两个版本都是根据1.2发展而来,所以1.4不是1.3的升级版,1.3和1.4的着眼点不同(侧重点不同),1.1版本默认默认使用polling机制,为提高性能,1.2.5以上版本在2.6以上内核使用epoll模型(haproxy借助OS上这些先进技术实现性能最大化)
1.4特性(more flexibility,client-side keepalive,tcp speedups,response buffering,RDP protocol,source-based stickiness(类似ip_hash,基于URL调度,提高缓存命中率,适用于http代理至缓存服务器,这也是很多站点使用haproxy的原因),a much better stats interface,a more verbose health checks,traffic-based health,http authentication,server management from the CLE,acl-based persistence,log analyzer)
1.3特性:
单进程使用event-driven降低了CS及内存占用;
O(1)事件检查器event checker(一个程序随着进程队列增长性能始终平稳,始终是一条平行的直线),在高并发连接中对任何连接的任何事件实现即时探测;
single buffering,类似mmap,在各module间实现数据共享;
在2.6.27.19以上内核使用splice()系统调用,类似sendfile,实现0复制转发,数据从内核空间直接响应(linux内核中内部带宽也是有限的,在内部实现数据处理,不考虑硬件,每秒达到10G左右,如果频繁的在内部复制数据它也会占用大量的内核带宽)
MRU内存分配器(这种机制比slab allocator更强)
树型存储(实现了以O(log(N))(性能仅次于O(1))低开销来保持计时器命令,保持运行队列命令,管理轮询,最少连接队列)
优化的HTTP首部分析(haproxy在http首部分析上比nginx更强,注意若分析的越多越消耗资源)
降低了昂贵的系统调用,大部分工作在用户空间完成(时间读取,缓冲聚合,文件描述符的启用和禁用)

评估负载均衡器的性能从三方面考虑:
会话率(单位时间完成的会话数);
会话并发能力(同时持有的会话数);
数据率(单位时间实现数据交换的能力)

haproxy处理三类主要参数来源:
最优先处理命令行参数;
global配置段,设定全局参数,有与服务定义相关的(进程相关的)和优化相关的;
proxy相关配置段,真正实现reverse proxy,有defaults、listen NAME、frontend NAME、backend NAME
注:listen(通过关联前端和后端定义了一个完整的代理,相当于将frontend和backend结合起来实现的功能)
frontend NAME(定义一系列监听的socket,这些socket可接受客户端请求并与之建立连接)
backend NAME(定义一系列后端服务器,代理会将对应客户端请求转发到这里定义的后端server)注:frontend NAME和backend NAME单独定义,比listen有更好的灵活性
代理名称自定义,通常是ASCII码,大小写字母、数字、中线-、下划线_、点.、冒号:(ACL名称会区分大小写字母)

配置文件中global配置段中的参数有(global中的参数为进程级别参数,通常与运行的OS相关):
进程管理及安全相关:
log <address> <facility> [max level[min level]](<address>定义日志信息发到哪个server上;max level指日志中的低级别,比这个级别高的都记录,min level指日志的高级别;如log 127.0.0.1 local2)
log-send-hostname [string](没有string则日志记录到syslog中时添加主机名,有string则在日志中添加指定信息)
chroot <jail dir>(定义假根,提升安全)
pidfile /var/run/haproxy.pid
user haproxy(此处也可用uid,使用一种即可)
group haproxy(此处也可用gid,使用一种即可)
daemon(以守护进程方式工作在后台)
nbproc <number>(启动的进程个数,只能用在守护进程模式,否则不起作用,默认只启动一个进程)
ulimit-n(设定单个进程打开的文件描述符个数,默认情况下会自动计算不要更改)
stats socket /var/lib/haproxy/stats
node(定义当前node名称,用于HA场景中多haproxy进程共享同一个IP地址)
description(当前实例的描述信息)
性能调整相关的参数:
maxconn <number>(设定每个进程所接受的最大并发连接数,会自动根据ulimit -n计算)
maxpipes <number>(haproxy使用pipe完成基于内核的tcp报文重组,此项设置每进程所允许使用的最大pipe个数,每个pipe会打开两个文件描述符)
noepoll
nosplice
nopoll
nosepoll
nokqueue
spread-checks <0-50,in percent>(LVS|nginx|haproxy都能实现对后端server的health_check,若后端server有100台,定义2S检查一次,每次要发出100个检测报文,要占据带宽可能会影响正常服务,所以此项实现检查报文分散发送,若指定百分比为25,则0.25*2是延长的时间,更精细的配置)
tune.bufsize <number>(设定buffer大小,同样的内存,较小的值可让haproxy有能力接受更多的并发连接,较大的值可让某些应用程序使用较大的cookie信息,默认16384,建议使用默认值)
tune.chksize <number>(设定检查缓冲区大小,haproxy可实现在协议报文中的文本搜索(文本查找)查找完后再根据条件进程转发,较大的值有助于在较大页面中完成基于字符串或模式的文本查找但会占用更多的系统资源,默认即可)
tune.maxaccept <number>(设定haproxy进程内核调度运行一次性可接受的连接的个数,较大值可有较大的吞吐率,默认在单进程模式下是100,多进程模式下是8,按默认即可;若server只有颗CPU,haproxy的进程不是每次都在CPU上运行,内核有可能调度其它进程在CPU上运行,haproxy没运行就不能接受用户请求,过一会内核调度到haproxy运行,这时client有很多等待连接,此项就是定义一批接受多少请求进来,剩余的请求继续等待,等到下次内核再调度到haproxy进程时再接进来)
tune.maxpollevents <number>(event-driven模型中每一次实现多少个回调,一次性系统调用能完成多少个事件的查看,默认256)
tune.maxrewrite <number>(设定为首部重写或追加而预留的缓冲空间,默认1024,若空间不够haproxy会自动增加)
tune.sndbuf.client <number>(以下几项不建议更改,使用默认值)
tune.rcvbuf.client <number>
tune.sndbuf.server <number>
bune.rcvbuf.server <number>
注:在reverse proxy上,一个连接打开4个缓冲区,而client和server各使用一个socket文件;nginx上计算client的最大连接数要除以4(现在的浏览器都是双线程,用于发送、接收)

配置文件中的关键字有(21项):
1、balance(定义调度算法,用在defaults,listen,backend段)
balance <algorithm> [arguments]
balance url_param <param> [check_port [max_wait]]
roundrobin(动态,权重可在运行时调整,每个后端server最多接受4128个连接)
static-rr(静态,运行时调整权重不会生效,后端server在连接数上没限制)
leastconn(此算法适用于较长时间会话的场景,如LDAP、SQL;不适用于较短会话的应用层协议,如http)
source(类似ip_hash,是将请求的源地址hash运算除以后端server的总权重数,所得的值可定位至某个后端server,但在后端server增加或减少时会带来抖动,此算法常用于LB无cookie功能的基于tcp的协议,默认为静态,可使用hash-_type修改此特性)
uri(如http://www.magedu.com/admin.php?a=3&b=4,对uri的前半部分(问号之前的部分admin.php)或整个uri进行hash运算再除以后端server的总权重数所得的结果可定位至某个后端server,同样在后端server增加或减少时会带来抖动,此算法常用于代理缓存或反病毒代理以提高缓存的命中率(而且仅应用在http后端server场景中),默认为静态算法,不过也可使用hash_type修改此特性)
2、bind(定义一个或几个监听的套接字,用在frontend、listen段)
bind [address]:<port_range>[,……]
bind [address]:<port_range>[,……] interface <interface>
3、mode(设定实例的运行模式或协议,每个listen可理解为一个实例,前端后端要是同一种协议,一般是http模式)
mode tcp|http(默认为tcp,tcp的应用有ssl,ssh,smtp,mysql)
4、hash_type(仅是算法source和uri的补充,用于将hash码映射到后端server的方法,方法有map-based和consistent,推荐使用map-based,不能用于frontend段)
map-based(静态方法,对于缓存server不适用)
consistent(一致性hash,适用于cache-server,但算法不平滑,要不时调整权重获得更好的均衡性)
5、log(为每个实例启用事件和流量日志,可用于所有段,每个client或frontend可指定两个log参数)
log global
log <address> <facility> [level[minlevel]]
6、maxconn(设定前端的并发连接数,默认2000,不能用于backend,此处最大值不能超出global中定义的,haproxy为每个连接维持两个缓冲,每个缓存大小8K,再加上其它数据,每个连接占用大约17K的RAM空间,这意味着适当优化后,有1G的RAM可维持4-5W个并发连接)
maxconn <number>
7、default_backend(在没有匹配的use_backend规则时使用默认关联的后端,不能用于backend段,通常在frontend和listen段定义use_backend匹配规则,而没有被匹配到的请求由default_backend参数指定的后端接收)
default_backend <backend>
举例:
use_backend DYNAMIC if URL_DYNAMIC
use_backend STATIC if URL_CSS URL_IMG URL_IMG EXTENSION_IMG
default_backend DYNAMIC
8、server(为后端声明一个server,用在backend和listen)
server <name> <address>[:port] [param]
param有:
backup(设定备用服务器,类似keepalived中的sorry_server)
check(启动对此处定义的服务器进行health_check,可用更细粒度的参数进行控制,例如inter <delay>定义检查的时间间隔,单位毫秒ms,默认2000(2s);rise <count>定义从离线到在线要确认几次;fall <count>定义在线到离线检查几次)
cookie <value>(为指定server设定cookie值,用户访问的每个网站都会给用户发送cookie(用户的身份标识),为避免cookie被滥用,为cookie设定作用域(通常与domain或domain下的uri相关),而用户在下次访问时只发送与这个网站对应的cookie,此处指定的cookie值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,目的在于实现持久连接)
maxconn <maxconn>(指定该server接受的最大并发连接数,若转发的连接超过此处的值时,请求就要放在请求队列,并处于等待状态)
maxqueue <maxqueue>(设定请求队列的最大长度,若超出此处设定的值,后续的请求将被拒绝)
observe <mode>(通过观察服务器的通信状况来判定其健康状态,默认禁用,支持的类型有layer4和layer7,layer7只能用于http代理场景)
redir <prefix>(启用重定向功能,将发往此server的GET和HEAD请求均以302状态码响应,prefix后不能使用/且不能使用相对地址,以免造成循环)
weight <weight>(默认为1,最大256,0表示不参与LB)
检查方法:
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <verison>
举例:
server SRV1 192.168.41.135:1080 cookie first check inter 1000
server SRV2 192.168.41.136:1080 cookie second check inter 1000
9、capture request header(捕获请求报文首部并记录到日志中,用在frontend和listen段,捕获并记录指定的请求首部最近一次出现时的第一个值,常用的首部有Host、content-length、User-agent、X-Forwarded-For)
注:虚拟主机环境中使用的Host,上传请求首部中的content-length,快速区别真实用户和网络机器人的User-agent(client的浏览器类型不同此项就不同,tencent和baidu有网络机器人和网络蜘蛛等,还可用curl来请求来源,curl的user-agent就是libcurl),代理环境中记录真实请求来源的X-Forwarded-For(将前端用户请求的真实IP记录到后端server,如nginx中的X-Real-IP)
capture request header <name> len <length>
10、capture response header(捕获并记录响应首部)
11、stats enable(启用gui接口,状态监控界面,启用基于程序编译时默认设置的统计报告,以下stats*设定均不能用于frontend段)
举例:
backend public_www
server websrv1 192.168.41.134:80
stats enable
stats hide-version
stats scope .
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth statsadmin:password
stats auth statsmaster:password
12、stats hide-version(隐藏版本号)
13、stats realm <realm>(在认证时显示在浏览器中的输账号密码上方的提示信息,此参数仅在与stats auth配置使用时才有意义,haproxy在获取realm时会将其视作一个单词,因此中间的空白字符要转义)
14、stats scope <name>|.(限定区段,点指当前区域)
15、stats auth <user>:<passwd>(授权用户帐号)
16、stats admin if|unless <condition>(默认打开图形界面是不能操作后端server的,此项可用于开启管理功能,如启用或禁用某server,但要设定条件)
举例1:
backend stats_localhost
stats enable
stats admin if LOCALHOST(通过本地连接就可启用管理接口)
举例2:
backend stats_auth
stats enable
stats auth haproxyadmin:password
stats admin if TRUE(通过上一条认证就可管理)17、option httplog [clf](启用记录HTTP请求、会话状态、计时器的功能,此项会使得日志变量丰富,一般在reverse proxy下此项要开启;通常在仅支持CLF格式的日志分析器时才需要使用此格式(使用CLF格式来代替haproxy默认的HTTP格式))
举例:
listen http_proxy 0.0.0.0:80
mode http
option httplog
option logasap
log 172.16.100.9 local2
18、option logasap
no option logasap(启用或禁用提前将HTTP请求记入日志,不能用在backend段,若启用在用户请求刚接入proxy,在后端server还未响应就记录,在传大对象时提前记录可不用长时间在缓冲区就可写入磁盘)
19、option forwardfor(将用户请求转发至后端时,在请求HTTP首部加入X-Forwarded-For记录真实的client地址,否则后端server记录的是proxy的地址;注意haproxy工作于隧道模式,其仅检查每一个连接的第一个请求,仅第一个请求被附加此首部,如果想为每一个请求都附加此首部,确保同时使用了这几个选项:option httpclose、option forceclose、option http-server-close)
option forwardfor [except <network>] [header <name>] [if-none]
举例:
frontend www
mode http
option forwardfor except 127.0.0.1
20、errorfile <code> <file>(当发生错误时返回指定文件中的内容给client,否则是由haproxy生成的错误代码及错误页面,用于所有段)
举例:
errorfile 400 /etc/haproxy/errorpages/400badreq.http
21、errorloc <code> <url>(请求错误时返回一个http重定向到某URL的信息给client,用于所有段)
errorloc302 <code> <url>
errorloc303 <code> <url>(前两种返回的都是302状态码,是用GET方法获取指定的URL,对于非GET方法的场景(POST)会产生问题,使用errorloc303返回状态码303给client)

二、操作:
环境:
[root@node1 ~]# uname -a
Linux node1.magedu.com2.6.32-358.el6.x86_64 #1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64GNU/Linux
准备:
node1(eth0:192.168.41.134,eth1:192.168.41.133,安装haproxy)(生产环境中两网卡一个是公网地址,一个是对内网用;注:由于公司环境是无线网且安装了iNODE智能客户端,虚拟机网络只能使用NAT,所以这里没将这两个网卡的网段区分开,若分开要将后端node{2,3}两个server的网关指向node1的内网IP)
node2(192.168.41.135,安装httpd)
node3(192.168.41.136,安装httpd)

[root@node1 ~]# ifconfig | grep -A 1 eth
eth0 Link encap:Ethernet HWaddr00:0C:29:E2:18:0E
inet addr:192.168.41.134 Bcast:192.168.41.255 Mask:255.255.255.0
--
eth1 Link encap:Ethernet HWaddr00:0C:29:E2:18:18
inet addr:192.168.41.133 Bcast:192.168.41.255 Mask:255.255.255.0
[root@node1 ~]# elinks -dump http://192.168.41.135 RS1.magedu.com
[root@node1 ~]# elinks -dump http://192.168.41.136 RS2.magedu.com
[root@node1 ~]# cd /mnt/cdrom/Packages/
[root@node1 Packages]# rpm -ivh haproxy-1.4.22-3.el6.x86_64.rpm
[root@node1 Packages]# cd
[root@node1 ~]# rpm -ql haproxy
/etc/haproxy
/etc/haproxy/haproxy.cfg
/etc/logrotate.d/haproxy
/etc/rc.d/init.d/haproxy
/usr/bin/halog
/usr/sbin/haproxy

[root@node1 ~]# man haproxy(fast and reliable http reverse proxy and load balancer)
#haproxy -f <configuration file> [-nmaxconn] [-N maxconn] [-d] [-D] [-q] [-V] [-c] [-p <pidfile>]
-n NUM(Set the high limit for the total number of simultaneous connections)
-N NUM(Set the high limit for the per-listener number of simultaneous connections)
-d(Start in foregreound with debugging mode enabled)
-D(Start in daemon mode)
-q(quiesce,Disable messages on output)
-V(verbose,Displays messages on output even when -q or ’quiet’ are specified)
-c(Only checks config file and exits with code 0 if no error was found, or exits with code 1 if a syntax error was found)
[root@node1 ~]# cd /etc/haproxy
[root@node1 haproxy]# cp haproxy.cfg haproxy.cfg.bak
[root@node1 haproxy]# vim /etc/sysconfig/rsyslog(SYSLOGD_OPTIONS=”-c 2 -r”其中-c 2表示使用兼容syslog模式;-r表示配置syslog接受网络日志事件,configure syslog to accept network log events)
SYSLOGD_OPTIONS="-c 2 -r"
[root@node1 haproxy]# vim /etc/rsyslog.conf(添加如下一行)
local2.* /var/log/haproxy.log
[root@node1 haproxy]# service rsyslog restart
关闭系统日志记录器: [确定]
启动系统日志记录器: [确定]

[root@node1 haproxy]# vim haproxy.cfg(option redispatch表示在session失败后是否允许重新分配)
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket/var/lib/haproxy/statsdefaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000listen stats
mode http
bind 0.0.0.0:1080
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth admin:admin
stats admin if TRUE
frontend http-in
bind *:80
mode http
log global
option httpclose
option logasap
option dontlognull
capture request header Host len20
capture request header Refererlen 60
default_backend servers
backend servers
balanceroundrobin
server websrv1 192.168.41.135:80 check maxconn 2000
server websrv2192.168.41.136:80 check maxconn 2000 [root@node1 haproxy]# haproxy -c -f haproxy.cfg
Configuration file is valid
[root@node1 haproxy]# service haproxy start
正在启动 haproxy: [确定]
[root@node1 haproxy]# netstat -tnlp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1883/haproxy
tcp 0 0 0.0.0.0:1080 0.0.0.0:* LISTEN 1883/haproxy
tcp 0 0 :::57802 :::* LISTEN 1185/rpc.statd
[root@node1 haproxy]# ps aux | grep haproxy | grep -v grep
haproxy 1883 0.0 0.4 18548 1140 ? Ss 12:13 0:00 /usr/sbin/haproxy -D-f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid




再次刷新后



访问此地址http://192.168.41.134:108/haproxyadmin?stats






[root@node2 ~]# service httpd stop(服务停止后再次刷新页面,查看websrv1一行)
停止 httpd: [确定]



[root@node2 ~]# service httpd start
正在启动 httpd: [确定]
注:最下方一行可实现启用或禁用哪个RS(不是向后端server发送命令)















[root@node2 ~]# vim /etc/httpd/conf/httpd.conf(想让后端记录真实client地址,更改如下)
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\"\"%{User-Agent}i\"" combined
[root@node2 ~]# tail -2 /var/log/httpd/access_log(实验的本机虚拟机网络是NAT模式,所以显示的是网关,下面两条记录是更改前和更改后的变化)
- - - [23/Dec/2015:15:55:49 +0800]"GET / HTTP/1.1" 200 15 "-" "Mozilla/4.0 (compatible;MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR3.5.30729; .NET CLR 3.0.30729; InfoPath.2)"
192.168.41.1 - - [23/Dec/2015:15:58:49+0800] "GET / HTTP/1.1" 200 15 "-" "Mozilla/4.0(compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727;.NET CLR 3.5.30729; .NET CLR 3.0.30729; InfoPath.2)"

附加:haproxy为mysql做LB(除管理接口模式为http,其它的都是tcp)
#vim haproxy.cfg
……
frontend mysql
bind *:3306
mode tcp
log global
default_backend mysqlservers
backend mysqlservers
balance leastconn
server dbsrv1 192.168.41.135:3306 check port 3306 maxconn 300
server dbsrv2 192.168.41.136:3306 check port 3306 maxconn 300

以上是学习《马哥运维课程》做的笔记。

本文出自 “Linux运维重难点学习笔记” 博客,请务必保留此出处http://jowin.blog.51cto.com/10090021/1733096
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: