负载均衡之--Nginx、LVS、HAProxy
1、概况
1.1 应用场景
Nginx/LVS/HAProxy的基于 Linux的开源免费的负载均衡软件。对于大型的,需要进行高并发的网站或者对网络不太严格的场景,可以使用Nginx;对于大型的Web服务器的时候可以使用Haproxy;对性能有严格要求的时候可以使用LVS,就单纯从负载均衡的角度来说,LVS也许会成为主流,更适合现在大型的互联网公司。本文采用HAproxy+keepalived+mysql主从方案来解决业务架构高可用。
1.2 LVS/Nginx/HAProxy特点
LVS
1)抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的;
2)配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率;
3)工作稳定,自身有完整的双机热备方案,如LVS+Keepalived和LVS+Heartbeat,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived;
4)无流量,保证了均衡器IO的性能不会收到大流量的影响;
5)应用范围比较广,可以对所有应用做负载均衡;
6)软件本身不支持正则处理,不能做动静分离,这个就比较遗憾了;其实现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在。
7)如果是网站应用比较庞大的话,实施LVS/DR+Keepalived起来就比较复杂了,特别后面有Windows Server应用的机器的话,如果实施及配置还有维护过程就比较复杂了。
Nginx
1)工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构,它的正则规则比HAProxy更为强大和灵活,这也是许多朋友喜欢它的原因之一;
2)Nginx对网络的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势所在;
3)Nginx安装和配置比较简单,测试起来比较方便;
4)也可以承担高的负载压力且稳定,一般能支撑超过几万次的并发量;
5)Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url来检测;
6)Nginx仅能支持http和Email,这样就在适用范围上面小很多,这个它的弱势;
7)Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP现在也是非常流行的web架构,大有和以前最流行的LAMP架构分庭抗争之势,在高流量的环境中也有很好的效果。
8)Nginx现在作为Web反向加速缓存越来越成熟了,很多朋友都已在生产环境下投入生产了,而且反映效果不错,速度比传统的Squid服务器更快,有兴趣的朋友可以考虑用其作为反向代理加速器。
HAProxy
1)支持两种代理模式:TCP(四层)和HTTP(七层)HAProxy是支持虚拟主机的。
2)能够补充Nginx的一些缺点比如Session的保持,Cookie的引导等工作
3)支持url检测后端的服务器出问题的检测会有很好的帮助。
4)它跟LVS一样,本身仅仅就只是一款负载均衡软件;单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。
5)HAProxy可以对Mysql读进行负载均衡,对后端的MySQL节点进行检测和负载均衡,不过在后端的MySQL slaves数量超过10台时性能不如LVS。
6)HAProxy的算法现在也越来越多了,算法特别灵活
2.1 Keepalived工作原理
keepalived:顾名思义是保持存活,常用来搭建设备的高可用,防止业务核心设备出现单点故障。keepalived基于VRRP协议来实现高可用,主要用作realserver的健康检查以及负载均衡主机和backup主机之间的故障漂移。如果将TCP/IP划分为5层,则Keepalived就是一个类似于3~5层 交换机制的软件,具有3~5层交换功能,其主要作用是检测web服务器的状态,如果某台web服务器故障,Keepalived将检测到并将其从 系统中剔除,当该web服务器工作正常后Keepalived自动将其加入到服务器群中,这些工作全部自动完成,而不需要人工干预,只需要人工修复故障的web服务器即可。
三层机理是发送ICMP数据包即PING给某台服务器,如果不通,则认为其故障,并从服务器群中剔除;四层机理是检测TCP端口号状态来判断某台服务器是否故障,如果检测端口存在异常,则从服务器群中剔除;五层机理是根据用户的设定检查某个服务器应用程序是否正常运行,如果不正常,则从服务器群中剔除。
2.2 HAproxy工作原理
Haproxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案,反向代理服务器,支持双机热备支持虚拟主机,但其配置简单,拥有非常不错的服务器健康检查功能,当其代理的后端服务器出现故障, HAProxy会自动将该服务器摘除,故障恢复后再自动将该服务器加入。
Keepalived
keepalived是什么
keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于 heartbeat,用来防止单点故障。
keepalived工作原理
keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即 虚拟路由冗余协议。
虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip(该路由器所在局域网内其他机器的默认路由为该vip),master会发组播,当backup收不到vrrp包时就认为master宕掉了,这时就需要根据 VRRP的优先级来 选举一个backup当master。这样的话就可以保证路由器的高可用了。
keepalived主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式。vrrp模块是来实现VRRP协议的。
keepalived的配置文件
keepalived只有一个配置文件keepalived.conf,里面主要包括以下几个配置区域,分别是global_defs、static_ipaddress、static_routes、vrrp_script、vrrp_instance和virtual_server。
global_defs区域
主要是配置故障发生时的通知对象以及机器标识
global_defs { notification_email { a@abc.com b@abc.com ... } notification_email_from alert@abc.com smtp_server smtp.abc.com smtp_connect_timeout 30 enable_traps router_id host163 }
-
notification_email 故障发生时给谁发邮件通知。
- notification_email_from 通知邮件从哪个地址发出。
- smpt_server 通知邮件的smtp地址。
- smtp_connect_timeout 连接smtp服务器的超时时间。
- enable_traps 开启SNMP陷阱( Simple Network Management Protocol)。
- router_id 标识本节点的字条串,通常为hostname,但不一定非得是hostname。故障发生时,邮件通知会用到。
static_ipaddress和static_routes区域
static_ipaddress和static_routes区域配置的是是本节点的IP和路由信息。如果你的机器上已经配置了IP和路由,那么这两个区域可以不用配置。其实,一般情况下你的机器都会有IP地址和路由信息的,因此没必要再在这两个区域配置。
static_ipaddress { 10.210.214.163/24 brd 10.210.214.255 dev eth0 ...} static_routes { 10.0.0.0/8 via 10.210.214.1 dev eth0 ...}
以上分别表示启动/关闭keepalived时在本机执行的如下命令:
/sbin/ip addr add 10.210.214.163/24 brd 10.210.214.255 dev eth0
# /sbin/ip route add 10.0.0.0/8 via 10.210.214.1 dev eth0
# /sbin/ip addr del 10.210.214.163/24 brd 10.210.214.255 dev eth0
# /sbin/ip route del 10.0.0.0/8 via 10.210.214.1 dev eth0
注意: 请忽略这两个区域,因为我坚信你的机器肯定已经配置了IP和路由。
vrrp_script区域
用来做健康检查的,当时检查失败时会将
vrrp_instance
的
priority
减少相应的值。
vrrp_script chk_http_port { script "以上意思是如果
script
中的指令执行失败,那么相应的vrrp_instance
的优先级会减少10个点。vrrp_instance和vrrp_sync_group区域
vrrp_instance用来定义对外提供服务的VIP区域及其相关属性。
vrrp_rsync_group用来定义vrrp_intance组,使得这个组内成员动作一致。举个例子来说明一下其功能:
两个vrrp_instance同属于一个vrrp_rsync_group,那么其中一个vrrp_instance发生故障切换时,另一个vrrp_instance也会跟着切换(即使这个instance没有发生故障)。
vrrp_sync_group VG_1 { group { inside_network # name of vrrp_instance (below) outside_network # One for each moveable IP. ... } notify_master /path/to_master.sh notify_backup /path/to_backup.sh notify_fault "/path/fault.sh VG_1" notify /path/notify.sh smtp_alert } vrrp_instance VI_1 { state MASTER interface eth0 use_vmacdont_track_primary track_interface { eth0 eth1 } mcast_src_ip lvs_sync_daemon_interface eth1 garp_master_delay 10 virtual_router_id 1 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 12345678 } virtual_ipaddress { 10.210.214.253/24 brd 10.210.214.255 dev eth0 192.168.1.11/24 brd 192.168.1.255 dev eth1 } virtual_routes { 172.16.0.0/12 via 10.210.214.1 192.168.1.0/24 via 192.168.1.1 dev eth1 default via 202.102.152.1 } track_script { chk_http_port } nopreempt preempt_delay 300 debug notify_master | notify_backup | notify_fault | notify | smtp_alert }
-
notify_master/backup/fault 分别表示切换为主/备/出错时所执行的脚本。
- notify 表示任何一状态切换时都会调用该脚本,并且该脚本在以上三个脚本执行完成之后进行调用,keepalived会自动传递三个参数( 1 = “ G R O U P " | " I N S T A N C E ” , 2 = name of group or instance,$3 = target state of transition(MASTER/BACKUP/FAULT))。
- smtp_alert 表示是否开启邮件通知(用全局区域的邮件设置来发通知)。
- state 可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER,因此该项其实没有实质用途。
- interface 节点固有IP(非VIP)的网卡,用来发VRRP包。
- use_vmac 是否使用VRRP的虚拟MAC地址。
- dont_track_primary 忽略VRRP网卡错误。(默认未设置)
- track_interface 监控以下网卡,如果任何一个不通就会切换到FALT状态。(可选项)
- mcast_src_ip 修改vrrp组播包的源地址,默认源地址为master的IP。(由于是组播,因此即使修改了源地址,该master还是能收到回应的)
- lvs_sync_daemon_interface 绑定lvs syncd的网卡。
- garp_master_delay 当切为主状态后多久更新ARP缓存,默认5秒。
- virtual_router_id 取值在0-255之间,用来区分多个instance的VRRP组播。
注意: 同一网段中virtual_router_id的值不能重复,否则会出错,相关错误信息如下。
Keepalived_vrrp[27120]: ip address associated with VRID not present in received packet :
one or more VIP associated with VRID mismatch actual MASTER advert
bogus VRRP packet received on eth1 !!!
receive an invalid ip number count associated with VRID!
VRRP_Instance(xxx) ignoring received advertisment...
可以用这条命令来查看该网络中所存在的vrid:
tcpdump -nn -i any net 224.0.0.0/8
- priority 用来选举master的,要成为master,那么这个选项的值 最好高于其他机器50个点,该项 取值范围是1-255(在此范围之外会被识别成默认值100)。
- advert_int 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)。
- authentication 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)。
- virtual_ipaddress vip,不解释了。
- virtual_routes 虚拟路由,当IP漂过来之后需要添加的路由信息。
- virtual_ipaddress_excluded 发送的VRRP包里不包含的IP地址,为减少回应VRRP包的个数。在网卡上绑定的IP地址比较多的时候用。
- nopreempt 允许一个priority比较低的节点作为master,即使有priority更高的节点启动。
首先nopreemt必须在state为BACKUP的节点上才生效(因为是BACKUP节点决定是否来成为MASTER的),其次要实现类似于关闭auto failback的功能需要将所有节点的state都设置为BACKUP,或者将master节点的priority设置的比BACKUP低。我个人推荐使用将所有节点的state都设置成BACKUP并且都加上nopreempt选项,这样就完成了关于autofailback功能,当想手动将某节点切换为MASTER时只需去掉该节点的nopreempt选项并且将priority改的比其他节点大,然后重新加载配置文件即可(等MASTER切过来之后再将配置文件改回去再reload一下)。
当使用
track_script
时可以不用加
nopreempt
,只需要加上
preempt_delay 5
,这里的间隔时间要大于
vrrp_script
中定义的时长。
- preempt_delay master启动多久之后进行接管资源(VIP/Route信息等),并提是没有
nopreempt
选项。
上述的文字来自于 这里,一般我们使用keepalived就是用上述的功能来监测服务,主从切换时自动地将vip进行漂移。
其实keepalived也可以用来作负载均衡,如下。
virtual_server_group和virtual_server区域
virtual_server_group一般在超大型的LVS中用到,一般LVS用不过这东西,因此不多说。
virtual_server IP Port { delay_looplb_algo rr|wrr|lc|wlc|lblc|sh|dh lb_kind NAT|DR|TUN persistence_timeout persistence_granularity protocol TCP ha_suspend virtualhost alpha omega quorum hysteresis quorum_up | quorum_down | sorry_server real_server { weight inhibit_on_failure notify_up | notify_down | # HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK HTTP_GET|SSL_GET { url { path # Digest computed with genhash digest status_code } connect_port connect_timeout nb_get_retry delay_before_retry } } }
-
delay_loop 延迟轮询时间(单位秒)。
- lb_algo 后端调试算法(load balancing algorithm)。
- lb_kind LVS调度类型 NAT/ DR/ TUN。
- virtualhost 用来给HTTP_GET和SSL_GET配置请求header的。
- sorry_server 当所有real server宕掉时,sorry server顶替。
- real_server 真正提供服务的服务器。
- weight 权重。
- notify_up/down 当real server宕掉或启动时执行的脚本。
- 健康检查的方式,N多种方式。
- path 请求real serserver上的路径。
- digest/status_code 分别表示用genhash算出的结果和http状态码。
- connect_port 健康检查,如果端口通则认为服务器正常。
- connect_timeout,nb_get_retry,delay_before_retry分别表示超时时长、重试次数,下次重试的时间延迟。
其他选项暂时不作说明。
keepalived主从切换
主从切换比较让人蛋疼,需要将backup配置文件的priority选项的值调整的比master高50个点,然后reload配置文件就可以切换了。当时你也可以将master的keepalived停止,这样也可以进行主从切换。
HAProxy
HAProxy是什么
HAProxy是一个免费的负载均衡软件,可以运行于大部分主流的Linux操作系统上。
HAProxy提供了L4(TCP)和L7(HTTP)两种负载均衡能力,具备丰富的功能。HAProxy的社区非常活跃,版本更新快速(最新稳定版1.7.2于2017/01/13推出)。最关键的是,HAProxy具备媲美商用负载均衡器的性能和稳定性。
因为HAProxy的上述优点,它当前不仅仅是免费负载均衡软件的首选,更几乎成为了唯一选择。
HAProxy的核心能力和关键特性
HAProxy的核心功能
- 负载均衡:L4和L7两种模式,支持RR/静态RR/LC/IP Hash/URI Hash/URL_PARAM Hash/HTTP_HEADER Hash等丰富的负载均衡算法
- 健康检查:支持TCP和HTTP两种健康检查模式
- 会话保持:对于未实现会话共享的应用集群,可通过Insert Cookie/Rewrite Cookie/Prefix Cookie,以及上述的多种Hash方式实现会话保持
- SSL:HAProxy可以解析HTTPS协议,并能够将请求解密为HTTP后向后端传输
- HTTP请求重写与重定向
- 监控与统计:HAProxy提供了基于Web的统计信息页面,展现健康状态和流量数据。基于此功能,使用者可以开发监控程序来监控HAProxy的状态
从这个核心功能来看,haproxy实现的功能类似于nginx的L4、L7反向代理。
HAProxy的关键特性
性能
- 采用单线程、事件驱动、非阻塞模型,减少上下文切换的消耗,能在1ms内处理数百个请求。并且每个会话只占用数KB的内存。
- 大量精细的性能优化,如O(1)复杂度的事件检查器、延迟更新技术、Single-buffereing、Zero-copy forwarding等等,这些技术使得HAProxy在中等负载下只占用极低的CPU资源。
- HAProxy大量利用操作系统本身的功能特性,使得其在处理请求时能发挥极高的性能,通常情况下,HAProxy自身只占用15%的处理时间,剩余的85%都是在系统内核层完成的。
- HAProxy作者在8年前(2009)年使用1.4版本进行了一次测试,单个HAProxy进程的处理能力突破了10万请求/秒,并轻松占满了10Gbps的网络带宽。
稳定性
作为建议以单进程模式运行的程序,HAProxy对稳定性的要求是十分严苛的。按照作者的说法,HAProxy在13年间从未出现过一个会导致其崩溃的BUG,HAProxy一旦成功启动,除非操作系统或硬件故障,否则就不会崩溃(我觉得可能多少还是有夸大的成分)。
在上文中提到过,HAProxy的大部分工作都是在操作系统内核完成的,所以HAProxy的稳定性主要依赖于操作系统,作者建议使用2.6或3.x的Linux内核,对sysctls参数进行精细的优化,并且确保主机有足够的内存。这样HAProxy就能够持续满负载稳定运行数年之久。
HAProxy关键配置详解
总览
HAProxy的配置文件共有5个域
- global:用于配置全局参数
- default:用于配置所有frontend和backend的默认属性
- frontend:用于配置前端服务(即HAProxy自身提供的服务)实例
- backend:用于配置后端服务(即HAProxy后面接的服务)实例组
- listen:frontend+backend的组合配置,可以理解成更简洁的配置方法
global域的关键配置
- daemon:指定HAProxy以后台模式运行,通常情况下都应该使用这一配置
- user [username] :指定HAProxy进程所属的用户
- group [groupname] :指定HAProxy进程所属的用户组
-
log [address][device][maxlevel][minlevel]
:日志输出配置,如log 127.0.0.1 local0 info warning,即向本机rsyslog或syslog的local0输出info到warning级别的日志。其中[minlevel]可以省略。HAProxy的日志共有8个级别,从高到低为emerg/alert/crit/err/warning/notice/info/debug - pidfile :指定记录HAProxy进程号的文件绝对路径。主要用于HAProxy进程的停止和重启动作。
- maxconn :HAProxy进程同时处理的连接数,当连接数达到这一数值时,HAProxy将停止接收连接请求
frontend域的关键配置
-
acl [name][criterion] [flags][operator] [value]
:定义一条ACL,ACL是根据数据包的指定属性以指定表达式计算出的true/false值。如"acl url_ms1 path_beg -i /ms1/“定义了名为url_ms1的ACL,该ACL在请求uri以/ms1/开头(忽略大小写)时为true - bind [ip]:[port]:frontend服务监听的端口
- default_backend [name]:frontend对应的默认backend
- disabled:禁用此frontend
-
http-request [operation][condition]
:对所有到达此frontend的HTTP请求应用的策略,例如可以拒绝、要求认证、添加header、替换header、定义ACL等等。 -
http-response [operation][condition]
:对所有从此frontend返回的HTTP响应应用的策略,大体同上 - log:同global域的log配置,仅应用于此frontend。如果要沿用global域的log配置,则此处配置为log global
- maxconn:同global域的maxconn,仅应用于此frontend
- mode:此frontend的工作模式,主要有http和tcp两种,对应L7和L4两种负载均衡模式
- option forwardfor:在请求中添加X-Forwarded-For Header,记录客户端ip
- option http-keep-alive:以KeepAlive模式提供服务
- option httpclose:与http-keep-alive对应,关闭KeepAlive模式,如果HAProxy主要提供的是接口类型的服务,可以考虑采用httpclose模式,以节省连接数资源。但如果这样做了,接口的调用端将不能使用HTTP连接池
- option httplog:开启httplog,HAProxy将会以类似Apache HTTP或Nginx的格式来记录请求日志
- option tcplog:开启tcplog,HAProxy将会在日志中记录数据包在传输层的更多属性
- stats uri [uri]:在此frontend上开启监控页面,通过[uri]访问
- stats refresh [time]:监控数据刷新周期
- stats auth [user]:[password]:监控页面的认证用户名密码
- timeout client [time]:指连接创建后,客户端持续不发送数据的超时时间
- timeout http-request [time]:指连接创建后,客户端没能发送完整HTTP请求的超时时间,主要用于防止DoS类攻击,即创建连接后,以非常缓慢的速度发送请求包,导致HAProxy连接被长时间占用
- use_backend [backend] if|unless [acl]:与ACL搭配使用,在满足/不满足ACL时转发至指定的backend
backend域的关键配置
- acl:同frontend域
- balance [algorithm]:在此backend下所有server间的负载均衡算法,常用的有roundrobin和source,完整的算法说明见官方文档 configuration.html#4.2-balance
- cookie:在backend server间启用基于cookie的会话保持策略,最常用的是insert方式,如cookie HA_STICKY_ms1 insert indirect nocache,指HAProxy将在响应中插入名为HA_STICKY_ms1的cookie,其值为对应的server定义中指定的值,并根据请求中此cookie的值决定转发至哪个server。indirect代表如果请求中已经带有合法的HA_STICK_ms1 cookie,则HAProxy不会在响应中再次插入此cookie,nocache则代表禁止链路上的所有网关和缓存服务器缓存带有Set-Cookie头的响应。
- default-server:用于指定此backend下所有server的默认设置。具体见下面的server配置。
- disabled:禁用此backend
- http-request/http-response:同frontend域
- log:同frontend域
- mode:同frontend域
- option forwardfor:同frontend域
- option http-keep-alive:同frontend域
- option httpclose:同frontend域
-
option httpchk [METHOD][URL] [VERSION]
:定义以http方式进行的健康检查策略。如option httpchk GET /healthCheck.html HTTP/1.1 - option httplog:同frontend域
- option tcplog:同frontend域
-
server [name][ip]:[port][params]
:定义backend中的一个后端server,[params]用于指定这个server的参数,常用的包括有:
check:指定此参数时,HAProxy将会对此server执行健康检查,检查方法在option httpchk中配置。同时还可以在check后指定inter, rise, fall三个参数,分别代表健康检查的周期、连续几次成功认为server UP,连续几次失败认为server DOWN,默认值是inter 2000ms rise 2 fall 3 cookie [value]:用于配合基于cookie的会话保持,如cookie ms1.srv1代表交由此server处理的请求会在响应中写入值为ms1.srv1的cookie(具体的cookie名则在backend域中的cookie设置中指定) maxconn:指HAProxy最多同时向此server发起的连接数,当连接数到达maxconn后,向此server发起的新连接会进入等待队列。默认为0,即无限 maxqueue:等待队列的长度,当队列已满后,后续请求将会发至此backend下的其他server,默认为0,即无限 weight:server的权重,0-256,权重越大,分给这个server的请求就越多。weight为0的server将不会被分配任何新的连接。所有server默认weight为1
- timeout connect [time]:指HAProxy尝试与backend server创建连接的超时时间
- timeout check [time]:默认情况下,健康检查的连接+响应超时时间为server命令中指定的inter值,如果配置了timeout check,HAProxy会以inter作为健康检查请求的连接超时时间,并以timeout check的值作为健康检查请求的响应超时时间
- timeout server [time]:指backend server响应HAProxy请求的超时时间
default域
上文所属的frontend和backend域关键配置中,除acl、bind、http-request、http-response、use_backend外,其余的均可以配置在default域中。default域中配置了的项目,如果在frontend或backend域中没有配置,将会使用default域中的配置。
listen域
listen域是frontend域和backend域的组合,frontend域和backend域中所有的配置都可以配置在listen域下
官方配置文档
HAProxy的配置项非常多,支持非常丰富的功能,上文只列出了作为L7负载均衡器使用HAProxy时的一些关键参数。完整的参数说明请参见官方文档 configuration.html
使用实例
使用HAProxy搭建L7负载均衡器
总体方案
本节中,我们将使用HAProxy搭建一个L7负载均衡器,应用如下功能
-
负载均衡
-
会话保持
-
健康检查
-
根据URI前缀向不同的后端集群转发
-
监控页面
HAProxy配置文件
global
daemon
maxconn 30000 #ulimit -n至少为60018
user ha
pidfile /home/ha/haproxy/conf/haproxy.pid
log 127.0.0.1 local0 info
log 127.0.0.1 local1 warning
defaults
mode http
log global
option http-keep-alive #使用keepAlive连接
option forwardfor #记录客户端IP在X-Forwarded-For头域中
option httplog #开启httplog,HAProxy会记录更丰富的请求信息
timeout connect 5000ms
timeout client 10000ms
timeout server 50000ms
timeout http-request 20000ms #从连接创建开始到从客户端读取完整HTTP请求的超时时间,用于避免类DoS攻击
option httpchk GET /healthCheck.html #定义默认的健康检查策略
frontend http-in
bind *:9001
maxconn 30000 #定义此端口上的maxconn
acl url_ms1 path_beg -i /ms1/ #定义ACL,当uri以/ms1/开头时,ACL[url_ms1]为true
acl url_ms2 path_beg -i /ms2/ #同上,url_ms2
use_backend ms1 if url_ms1 #当[url_ms1]为true时,定向到后端服务群ms1中
use_backend ms2 if url_ms2 #当[url_ms2]为true时,定向到后端服务群ms2中
default_backend default_servers #其他情况时,定向到后端服务群default_servers中
backend ms1 #定义后端服务群ms1
balance roundrobin #使用RR负载均衡算法
cookie HA_STICKY_ms1 insert indirect nocache #会话保持策略,insert名为"HA_STICKY_ms1"的cookie
#定义后端server[ms1.srv1],请求定向到该server时会在响应中写入cookie值[ms1.srv1]
#针对此server的maxconn设置为300
#应用默认健康检查策略,健康检查间隔和超时时间为2000ms,两次成功视为节点UP,三次失败视为节点DOWN
server ms1.srv1 192.168.8.111:8080 cookie ms1.srv1 maxconn 300 check inter 2000ms rise 2 fall 3
#同上,inter 2000ms rise 2 fall 3是默认值,可以省略
server ms1.srv2 192.168.8.112:8080 cookie ms1.srv2 maxconn 300 check
backend ms2 #定义后端服务群ms2
balance roundrobin
cookie HA_STICKY_ms2 insert indirect nocache
server ms2.srv1 192.168.8.111:8081 cookie ms2.srv1 maxconn 300 check
server ms2.srv2 192.168.8.112:8081 cookie ms2.srv2 maxconn 300 check
backend default_servers #定义后端服务群default_servers
balance roundrobin
cookie HA_STICKY_def insert indirect nocache
server def.srv1 192.168.8.111:8082 cookie def.srv1 maxconn 300 check
server def.srv2 192.168.8.112:8082 cookie def.srv2 maxconn 300 check
listen stats #定义监控页面
bind *:1080 #绑定端口1080
stats refresh 30s #每30秒更新监控数据
stats uri /stats #访问监控页面的uri
stats realm HAProxy\ Stats #监控页面的认证提示
stats auth admin:admin #监控页面的用户名和密码
使用HAProxy搭建L4负载均衡器
HAProxy作为L4负载均衡器工作时,不会去解析任何与HTTP协议相关的内容,只在传输层对数据包进行处理。也就是说,以L4模式运行的HAProxy,无法实现根据URL向不同后端转发、通过cookie实现会话保持等功能。
同时,在L4模式下工作的HAProxy也无法提供监控页面。
但作为L4负载均衡器的HAProxy能够提供更高的性能,适合于基于套接字的服务(如数据库、消息队列、RPC、邮件服务、Redis等),或不需要逻辑规则判断,并已实现了会话共享的HTTP服务。
HAProxy配置文件
global
daemon
maxconn 30000 #ulimit -n至少为60018
user ha
pidfile /home/ha/haproxy/conf/haproxy.pid
log 127.0.0.1 local0 info
log 127.0.0.1 local1 warning
defaults
mode tcp
log global
option tcplog #开启tcplog
timeout connect 5000ms
timeout client 10000ms
timeout server 10000ms #TCP模式下,应将timeout client和timeout server设置为一样的值,以防止出现问题
option httpchk GET /healthCheck.html #定义默认的健康检查策略
frontend http-in
bind *:9002
maxconn 30000 #定义此端口上的maxconn
default_backend default_servers #请求定向至后端服务群default_servers
backend default_servers #定义后端服务群default_servers
balance source #基于客户端IP的会话保持
server def.srv1 192.168.8.111:8082 maxconn 300 check
server def.srv2 192.168.8.112:8082 maxconn 300 check
使用Keepalived实现HAProxy高可用
尽管HAProxy非常稳定,但仍然无法规避操作系统故障、主机硬件故障、网络故障甚至断电带来的风险。所以必须对HAProxy实施高可用方案。
下文将介绍利用Keepalived实现的HAProxy热备方案。即两台主机上的两个HAProxy实例同时在线,其中权重较高的实例为MASTER,MASTER出现问题时,另一台实例自动接管所有流量。
原理
在两台HAProxy的主机上分别运行着一个Keepalived实例,这两个Keepalived争抢同一个虚IP地址,两个HAProxy也尝试去绑定这同一个虚IP地址上的端口。 显然,同时只能有一个Keepalived抢到这个虚IP,抢到了这个虚IP的Keepalived主机上的HAProxy便是当前的MASTER。 Keepalived内部维护一个权重值,权重值最高的Keepalived实例能够抢到虚IP。同时Keepalived会定期check本主机上的HAProxy状态,状态OK时权重值增加。
keepalived配置文件
global_defs {
router_id LVS_DEVEL #虚拟路由名称
}
#HAProxy健康检查配置
vrrp_script chk_haproxy {
script "killall -0 haproxy" #使用killall -0检查haproxy实例是否存在,性能高于ps命令
interval 2 #脚本运行周期
weight 2 #每次检查的加权权重值
}
#虚拟路由配置
vrrp_instance VI_1 {
state MASTER #本机实例状态,MASTER/BACKUP,备机配置文件中请写BACKUP
interface enp0s25 #本机网卡名称,使用ifconfig命令查看
virtual_router_id 51 #虚拟路由编号,主备机保持一致
priority 101 #本机初始权重,备机请填写小于主机的值(例如100)
advert_int 1 #争抢虚地址的周期,秒
virtual_ipaddress {
192.168.8.201 #虚地址IP,主备机保持一致
}
track_script {
chk_haproxy #对应的健康检查配置
}
}
参考
- https://github.com/chenzhiwei/linux/tree/master/keepalived
- https://www.jianshu.com/p/c9f6d55288c0
- http://seanlook.com/2015/05/18/nginx-keepalived-ha/
LVS负载均衡内功心法+外功招式
LVS是 Linux Virtual Server 的缩写,即 Linux 虚拟服务器,是由章文嵩博士主导开发的开源负载均衡项目,目前 LVS 已经被集成到 Linuxd 内核模块中。章文嵩博士曾任淘宝网技术总监、阿里副总裁、阿里云 CTO , 2016 年任滴滴出行高级副总裁。章博士曾经总结道:做技术不仅要有一份执着和细致的心,还要有一份平静的心态。就拿开源项目来讲,都是免费的,没有收入,收获的是自己的满足感,而非金钱,这时候更需要冷静和平和的心态。把这句话送给我自己,也送给大家。(貌似有点扯远了)
21世纪人类进入以网络为中心的信息时代,人们对互联网的使用呈指数级增长,单机模式已经无法满足业务服务高性能、高可用、可伸缩的需求了。
通过高性能网络或局域网互联的服务器集群正成为实现高性能、高可用、可伸缩的有效架构。LVS项目给出了基于 IP的数据请求负载均衡调度方案。在 LVS集群中,服务器集群对客户端来说是透明的,客户端访问负载均衡服务器,请求会发给 LVS调度器,调度器根据设定的算法决定将请求发送给后端某台真实的服务器。后端多台服务器共同实现了集群的高性能,可伸缩性是通过在集群中透明的加入和剔除一个节点来达到,通过监测后端节点、重置系统达到集群的高可用性。
LVS集群架构主要由三部分组成:
1.负载调度器: 负责客户请求的分发,根据预设的算法选中后端一台真实的服务器上,然后将请求发送到这台真实服务器上。它可以是基于IP负载均衡技术的负载调度器,也可以是基于内容请求分发的负载调度器,或者是两者的结合。
2.服务器池: 是一组真正执行客户请求的服务器。
3.后端存储: 为服务器池提供一个共享的存储区,这样很容易使得服务器池拥有相同的内容,提供相同的服务。如果不采用共享存储的方式,这就要求每个后端服务器上都要有相同的内容。
2.DS:Director Server,指负载均衡节点。
3.RS:Real Server,后端真实的服务器。
4.VIP:Virtual IP,用户请求的目标IP地址,指LVS上的虚拟IP。
5.RIP:Real Server IP,后端服务器的IP地址。
6.CIP:Client IP,客户端的IP地址。
VS/NAT
NAT(
Network Address Translation)即网络地址转换,其原理是通过对数据报文头(目标地址、源地址和端口等)的修改,使位于企业内部的私有
IP可以访问外网,以及外部用户可以访问位于公司内部的私有
IP。,该模式下
LVS调度器一般配置两块网卡设置不同的
IP。当客户通过
VIP(
Virtual IP Address)访问网络服务时,调度器会根据连接调度算法从后台真实服务器中选出一台,将报文的目标地址
VIP改写成选中的服务器的
IP地址,报文的目标端口改写成选中的服务器的对应端口,最后将修改后的报文发给选中的服务器。同时,调度器会在连接
Hash表记录这个连接,当这个连接的下一个报文到达时,从连接
Hash 表中可以得到原选定服务器的地址和端口,进行同样的改写操作,并将报文传给原选定的服务器。当来自真实服务器的响应报文经过调度器时,调度器将报文的源地址和源端口改为
VIP和相应的端口,再把报文发给用户。这样,客户所看到的只是在
VIP上提供的服务,而服务器集群的结构对用户是透明的。
举个例子:
1.第一步用户通过对外提供的VIP( 126.124.1.1:80)访问服务器。这时候请求报文中含有以下源地址、目标地址和端口。
source | 202.103.2.1:40124 | dest | 126.124.1.1:80 |
2.LVS收到请求后,会根据预设定的算法从后端选出一台真实的服务器。在转发报文之前会把报文中的目标 IP和端口修改为被选中的后端真实服务器的 IP和端口(假设 192.168.94.2被选中),然后将数据包转发给真实服务器。
修改后:
source | 202.103.2.1:40124 | dest | 192.168.94.2:8080 |
3.后端真实服务器处理完之后将响应报文返回给LVS,此时报文的源地址端口是后端真实服务的
IP端口,调度器得到响应报文后会将源地址修改为
VIP和调度器对应端口。
修改前:
source | 192.168.94.2:8080 | dest | 202.103.2.1:40124 |
修改后:
source | 126.124.1.1:80 | dest | 202.103.2.1:40124 |
这样,客户就认为是从126.124.1.1:80得到的响应,而不知道后端真实服务器的存在。
在VS/NAT模式下,请求和响应都要通过负载调度器,当真实服务器数量较多时,调度器就会成为整个集群的瓶颈。我们知道,一般情况下请求报文一般要远小于响应报文,所以如果能将请求和响应分开处理,比如 LVS只负责请求而响应直接返回给客户,这样就能极大的提高集群的处理效率。
IP隧道( IP tunneling)是将一个 IP报文封装在另一个 IP报文的技术,这可以使得目标为一个 IP地址的数据报文能被封装和转发到另一个 IP地址,从而实现将一个目标地址为调度器 VIP的数据包封装,通过隧道转发给后端某台真实服务器。后端真实服务器收到报文后,先将报文解封获得原来目标地址为 VIP的报文,服务器发现 VIP地址被配置在本地的 IP隧道设备上,所以就处理这个请求,然后根据路由表将响应报文直接返回给客户。在这里,请求报文的目标地址为 VIP,响应报文的源地址也为 VIP,所以响应报文不需要作任何修改,可以直接返回给客户而不需要再经过调度器,客户不会知道是哪一台服务器处理的。
DR模式也叫直接路由模式,该模式下 LVS依然承担数据入站请求以及根据预设的算法选出合理的真实服务器,最终由后端真实服务器直接将响应包发送给客户。与 TUN模式不同的事,直接路由模式要求调度器和后端真实服务器必须在同一个局域网内, VIP地址需要在调度器和后端所有服务器间共享。
在VS/DR模式下,调度器根据各个服务器的负载情况,动态地选择一台服务器,不修改也不封装 IP报文,而是将数据帧的 MAC地址改为选出服务器的 MAC地址,再将修改后的数据帧在与服务器组的局域网上发送。因为数据帧的 MAC地址是选出的服务器,所以服务器肯定可以收到这个数据帧,从中可以获得该请求报文。在 VS/DR 中,请求报文的目标地址为 VIP,响应报文的源地址也为 VIP,所以响应报文不需要作任何修改,可以直接返回给客户,客户认为得到正常的服务,而不会知道是哪一台服务器处理的。
1. 轮询调度(RR )
轮叫调度(Round Robin Scheduling)算法就是以轮叫的方式依次将请求调度不同的服务器。轮叫调度算法假设所有服务器处理性能均相同,调度器会将请求平均分到后端真实服务器上。
2. 加权轮询调度(WRR )
加权轮询调度(Weighted Round-Robin Scheduling)比 RR算法多了一个加权的概念,可以给 RS设置权重,权重越高,分发的请求越多。比如服务器 A的权重是 1,服务器 B的权重是 2,则服务器 B收到的分发请求一般是 A的 2倍。
3. 目标地址散列调度(DH )
目标地址散列调度(Destination Hashing Scheduling)是针对目标 IP地址的负载均衡,它会以目标地址为关键字查找一个静态 hash表来获得需要的 RS。
4. 源地址散列调度(SH )
该算法正好与目标地址散列调度算法相反,它根据请求的源 IP 地址,作为散列键( Hash Key)从静态分配的散列表找出对应的服务器。一般情况下,在一定时间内,同一个 IP的请求会发往后端同一台服务器。
5. 最小连接调度(LC )
最小连接调度是一种动态调度算法,它通过服务器当前所活跃的连接数来估计服务器的负载情况。比如RS1的连接数比 RS2少,那么调度器就会优先把下一个请求发给 RS1。
6. 加权最小连接调度(WLC )
这个比LC算法多了一个加权的概念,当连接数相近时,权重越大,越优先被分配请求。
7. 基于局部性的最少链接(LBLC )
LBLC调度算法先根据请求的目标 IP地址找出该目标 IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于其一半的工作负载,则用“最少链接”的原则选出一个可用的服务器,将请求发送到该服务器。
8. 带复制的基于局部性最少链接(LBLCR )
该算法也是针对目标 IP 地址的负载均衡,目前主要用于 Cache集群系统,不太常用。
1.ipvsadm 参数
-A添加一个虚拟服务,使用IP地址、端口号、协议来定义一个虚拟服务。
-E编辑一个虚拟服务
-D删除一个虚拟服务
-C情况虚拟服务
-R从标准输入还原虚拟服务
-S保存虚拟服务规则至标准输出,输出的规则可以用-R还原
-a在虚拟服务中增加一个real server
-e在虚拟服务中编辑一台real server
-d在虚拟服务中删除一台real server
-L显示虚拟服务列表
-t使用TCP协议,该参数后需要跟主机和端口信息
-u使用UDP协议,该参数后需要跟主机和端口信息
-s指定lvs需要使用的调度算法
-r设置真实服务器的IP地址和端口
-g设置LVS工作模式为 DR模式
-i设置LVS工作模式为 TUN模式
-m设置LVS工作模式为 NAT模式
-w设置指定服务器的权重
-c显示连接状态,一般配合-L使用
-n数字格式输出,IP和端口信息会以数字格式输出
2.添加一个虚拟服务,设置调度算法为轮询算法,将发送到207.175.44.110:80端口的传入请求分配给后端 3台真实的服务器的 80端口上,本例中采用 NAT模式。
ipvsadm -A -t 207.175.44.110:80 -s rripvsadm -a -t 207.175.44.110:80 -r 192.168.10.1:80 -mipvsadm -a -t 207.175.44.110:80 -r 192.168.10.2:80 -mipvsadm -a -t 207.175.44.110:80 -r 192.168.10.3:80 -m
3.删除后端一台真实服务器192.168.10.1:80
ipvsadm –d –t 207.175.44.110:80 –r 192.168.10.1:80
4.编辑虚拟服务器的调度算法为加权轮询
ipvsadm –E –t 207.175.44.110:80 –s wrr
5.虚拟服务规则表的备份和还原
ipvsadm –Sn >/tmp/ipvs.bak #备份ipvsadm –C #情况规则表ipvsadm –R
6.查看IPVS调度状态
ipvsadm –Lnc
7.查看LVS规则
ipvsadm -Ln
keepalived顾名思义,保持存活,它是为 Linux系统提供简单高效的负载均衡及高可用的解决方案。它通过 VRRP( Virtual Router Redundancy Protocol)协议实现高可用架构。 VRRP协议是为了在静态路由环境下防止单点故障而设计的主从灾备协议,它可以实现在一个集群环境中,当主机发生故障时,能将业务自动切换到备机。 VRRP将多台设备虚拟成一个设备集群,对外只提供一个虚拟的 IP,正常情况下,只有一个设备可以拥有这个 IP,主设备会不断发送自己的状态给备机,当备机发现主机不可达时,会根据优先级选举出新的主机。
Keepalived主要配置文件是/etc/keepalived/keepalived.conf,配置文件主要分为全局配置、VRRP配置块、LVS配置块,具体核心参数解释如下:
1.
环境准备(redhat 6.9
)
1) 关闭 selinux :
vi /etc/selinux/config#把SELINUX=enforce 改成disabled
2) 关闭防火墙( NAT 负载模式需要根据业务需求配置 iptables,DR 模式需要直接关掉)
chkconfig --level 2345 iptables offchkconfig --level 2345 ip6tables offiptables -Fservice iptables stop
2. 配置本地yum 源(如果已有 yum 源,该步骤请忽略)
1) 挂载光盘
mkdir /mnt/mediamount -o loop /dev/cdrom /mnt/media#如果是光驱的话mount -t iso9660 /dev/sr0 /mnt/media
2) 新建本地 yum 源的配置文件
vi /etc/yum.repos.d/local.repo#加入以下信息:[Local]name=Localbaseurl=file:///mnt/mediaenable=1gpgcheck=0#/mnt/media根据实际挂载路径配置
3)清理yum
yum clean all
3. 安装部署ipvs 管理工具 ipvsadm
1) 确保 Linux 的 kernel 支持 ipvs 算法 , 检查内核是否支持
modprobe -l|grep ipvs
2) 使用 rpm 包安装
yum install ipvsadm*#建议用yum安装,rpm需要制定全路径rpm -ivh ipvsadm-1.24-13.el6.x86_64.rpm
3) 激活 IPVS 内核模块
modprobes ip_vs
4) 检查 ipvsadm 是否完整安装 ( modprob ip_vs 装载 )
lsmod|grep ip_vs #检查结果: ip_vs 125694 0 libcrc32c 1246 1 ip_vs ipv6
4. 高可用介质keepalived 安装 ( 采用编译安装的方式 , 也可直接安装 rpm 包 )
1) 安装编译工具
yum install make -y
2) 安装编译环境
yum install gcc* -y
3) 安装依赖程序
yum install kernel-devel -yyum install openssl* -yyum install popt-devel -y
4) 可以用此命令建立内核链接
ln -s /usr/src/kernels/$(uname -r)/ /usr/src/linux#uname -r 可显示对应的内核信息
5. 安装keepalived 软件
1) 解压程序包
tar -zxvf keepalived1.2.2.tar.gz
2) 配置编译环境
cd keepalived-1.2.2 ./configure configure后要注意 keepalived configuration ------------------------ Keepalived version : 1.2.2 Compiler : gcc Compiler flags : -g -O2 Extra Lib : -lpopt -lssl -lcrypto Use IPVS Framework : Yes(必须是yes) IPVS sync daemon support : Yes(必须是yes) IPVS use libnl : No(可以不是yes) Use VRRP Framework : Yes(必须是yes) Use Debug flags : No
注意上面的kernel 的链接,如果没有做链接,很可能导致
Use IPVS Framework : Yes (必须是 yes )
IPVS sync daemon support : Yes (必须是 yes )
这两个地方是NO
3) 编译安装
make && make install
6. 配置HA 为系统服务,并设置开机启动
cp /usr/local/etc/rc.d/init.d/keepalived /etc/init.d/ cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/ cp /usr/local/sbin/keepalived /usr/sbin/ chkconfig --add keepalived chkconfig --level 2345 keepalived on chkconfig --level 2345 ipvsadm on
7. 修改keepalived 配置文件,具体配置需要根据业务场景定制,示例可参考上一章节《 LVS
的黄金搭档-keepalived 》中的配图,本例采用 DR 模式。
修改完配置文件后启动keepalived ,启停命令如下:
停止:service keepalived stop启动:service keepalived start
8. 在LVS ( DR )模式下,所有的真实服务器都配置了 VIP 地址,因此需要设置服务器不进 行针对 VIP 地址的 ARP 广播, linux 中可以直接通过 arp_ignore 和 arp_announce 两个参数来实现。
arp_ignore :
0 :代表任何网络接口接到 ARP 请求后,如果本机的任意接口有该 IP ,则予以响应。
1 :某个网络接口收到 ARP 请求后,判断请求的 IP 是否在本接口,是则回应,否则不回应。 LVS 调度器会把客户请求发给真实服务器的某个本机接口(比如 eth0 )而真实服务器的 VIP 地址会配置在回环网卡上。
arp_announce :
0 :任何网络接口接收到 ARP 请求后,如果本机上任何接口有该 IP ,则给予响应。
1 :尽量避免响应 MAC 地址非本网络接口 IP 地址的 ARP 请求。
2 :不响应 MAC 地址非本网络接口 IP 地址的 ARP 请求。
具体脚本如下:
#!/bin/bash VIP=152.2.4.26 . /etc/rc.d/init.d/functions case "$1" in start) echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up /sbin/route add -host $VIP dev lo:0 sysctl -p > /dev/null 2>&1 echo "realserver start OK" ;; stop) echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce ifconfig lo:0 down /sbin/route del $VIP > /dev/null 2>&1 echo "realserver stoped" ;; status) # Status of LVS-DR real server. islothere=`/sbin/ifconfig lo:0 | grep $VIP` isrothere=`netstat -rn | grep "lo:0" | grep $VIP` if [ ! "$islothere" -o ! "isrothere" ];then # Either the route or the lo:0 device not found. echo "LVS-DR real server Stopped." else echo "LVS-DR real server Running." fi ;; *) echo "Usage:$0 {start|stop|status}" exit 1 esac exit 0
9. 注意事项
现在大多数网卡都具有lro 和 gro 功能,即网卡收包时将同一流的小包合并成大包( tcpdump 抓包时可以看到 >MTU 1500 bytes 的数据包)交给内核协议栈, lvs 内核模块在处理 >MTU ( Maximum Transmission Unit ,网络上传输的最大数据包, ifconfig 可以查看)的数据包时,会丢弃,如果 lvs 传输大文件时,容易出现丢包、传输速度慢的现象。
建议关掉lro 和 gro 。
查看网卡属性
ethtool -k eth0
关闭网卡gro 和 lro 功能
/usr/sbin/ethtool -K eth0 gro off/usr/sbin/ethtool -K eth0 lro off
About Me
........................................................................................................................ ● 本文作者:小麦苗,部分内容整理自网络,若有侵权请联系小麦苗删除 ● 本文在itpub、博客园、CSDN和个人微 信公众号( xiaomaimiaolhr)上有同步更新 ● 本文itpub地址: http://blog.itpub.net/26736162 ● 本文博客园地址: http://www.cnblogs.com/lhrbest ● 本文CSDN地址: https://blog.csdn.net/lihuarongaini ● 本文pdf版、个人简介及小麦苗云盘地址: http://blog.itpub.net/26736162/viewspace-1624453/ ● 数据库笔试面试题库及解答: http://blog.itpub.net/26736162/viewspace-2134706/ ● DBA宝典今日头条号地址: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826 ........................................................................................................................ ● QQ群号: 230161599 、618766405 ● 微 信群:可加我微 信,我拉大家进群,非诚勿扰 ● 联系我请加QQ好友 ( 646634621 ),注明添加缘由 ● 于 2020-02-01 06:00 ~ 2020-02-31 24:00 在西安完成 ● 最新修改时间:2020-02-01 06:00 ~ 2020-02-31 24:00 ● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解 ● 版权所有,欢迎分享本文,转载请保留出处 ........................................................................................................................ ● 小麦苗的微店: https://weidian.com/s/793741433?wfr=c&ifr=shopdetail ● 小麦苗出版的数据库类丛书: http://blog.itpub.net/26736162/viewspace-2142121/ ● 小麦苗OCP、OCM、高可用网络班: http://blog.itpub.net/26736162/viewspace-2148098/ ● 小麦苗腾讯课堂主页: https://lhr.ke.qq.com/ ........................................................................................................................ 使用 微 信客户端扫描下面的二维码来关注小麦苗的微 信公众号( xiaomaimiaolhr)及QQ群(DBA宝典)、添加小麦苗微 信, 学习最实用的数据库技术。
........................................................................................................................ |
![]() |
|