目录
2.总结redis cluster工作原理,并搭建集群实现扩缩容
3.总结LVS的NAT和DR模型的工作原理。并搭建完成DR模型实战。
1.总结哨兵机制实现原理,并搭建主从哨兵集群
(1)实现原理:
①步:多个sentinel(哨兵)发现并确认master有问题
②步:选举出一个sentinel作为领导
③步:选出一个slave作为新master
④步:通知其余slave成为新的master的slave
⑤步:通知客户端主从变化
⑥步:等待老的master复活成为新的master的slave
(2)搭建主从哨兵集群
10.0.0.10为主节点 10.0.0.20为从节点 10.0.0.30为从节点 ***************************先搭建主从同步*************************** #在三个节点上安装redis服务 [root@Rocky8 ~]#yum -y install redis #修改主节点redis配置 [root@Rocky8 ~]#vim /etc/redis.conf bind 0.0.0.0 masterauth 123456 #设置这项能成功实现哨兵功能 requirepass 123456 #登录时的密码验证 #开启主节点redis服务 [root@Rocky8 ~]#systemctl enable --now redis #修改2台从节点redis配置 [root@Rocky8 ~]#vim /etc/redis.conf replicaof 10.0.0.10 6379 masterauth 123456 #开启从节点redis服务 [root@Rocky8 ~]#systemctl enable --now redis #在主节点上查看主从是否搭建完成 [root@Rocky8 ~]#redis-cli -a 123456 info replication # Replication role:master connected_slaves:2 slave0:ip=10.0.0.30,port=6379,state=online,offset=745998,lag=0 slave1:ip=10.0.0.20,port=6379,state=online,offset=745998,lag=1 ************************************搭建哨兵集群********************* #这三台服务器即运行redis服务也同时运行redis-sentinel服务 #在从节点上执行以下脚本内容 #!/bin/bash MASTER_IP=10.0.0.10 PASSWD=123456 Sentinel_config () { sed -i -e "/^# bind/c bind 0.0.0.0" -e '/^logfile/c logfile "/var/log/redis/sentinel.log"' -e "/sentinel/s/127.0.0.1/$MASTER_IP/" -e "/sentinel/s/30000/3000/g" -e "/<master-name> <password>/a sentinel auth-pass mymaster $PASSWD" /etc/redis-sentinel.conf systemctl enable --now redis-sentinel } Sentinel_config #查看该哨兵功能是否实现 [root@Rocky8 ~]#redis-cli -p 26379 info sentinel #26379是sentinel的监听端口 # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=10.0.0.10:6379,slaves=2,sentinels=3 ****************************验证故障转移************************* #把主节点挂掉 [root@Rocky8 ~]#systemctl stop redis #观察日志情况 [root@Rocky8 ~]#tail -f /var/log/redis/sentinel.log 3254:X 12 Feb 2023 19:53:43.449 # +failover-end master mymaster 10.0.0.10 6379 3254:X 12 Feb 2023 19:53:43.449 # +switch-master mymaster 10.0.0.10 6379 10.0.0.30 6379 3254:X 12 Feb 2023 19:53:43.449 * +slave slave 10.0.0.20:6379 10.0.0.20 6379 @ mymaster 10.0.0.30 6379 3254:X 12 Feb 2023 19:53:43.449 * +slave slave 10.0.0.10:6379 10.0.0.10 6379 @ mymaster 10.0.0.30 6379 3254:X 12 Feb 2023 19:53:46.480 # +sdown slave 10.0.0.10:6379 10.0.0.10 6379 @ mymaster 10.0.0.30 6379
2.总结redis cluster工作原理,并搭建集群实现扩缩容
(1)总结工作原理:
①步:数据分区
数据分区通常采取顺序分布和hash分布。
顺序分布保障了数据的有序性,但是离散性低,可能导致某个分区的数据热度高,其他分区数据的热度 低,分区访问不均衡。
哈希分布也分为多种分布方式,比如区域哈希分区,一致性哈希分区等。而redis cluster采用的是虚拟 槽分区的方式。
②步:虚拟槽分区
redis cluster设置有0~16383的槽,每个槽映射一个数据子集,通过hash函数,将数据存放在不同的槽位中,每个集群的节点保存一部分的槽。 每个key存储时,先经过哈希函数CRC16(key)得到一个整数,然后整数与16384取余,得到槽的数值, 然后找到对应的节点,将数据存放入对应的槽中。
(2)搭建集群并实现扩缩容:
***********************修改3组集群的配置文件及自动化配置集群**************** #用脚本实现 #!/bin/bash MASTER1_IP=10.0.0.10 MASTER2_IP=10.0.0.20 MASTER3_IP=10.0.0.30 SLAVE1_IP=10.0.0.40 SLAVE2_IP=10.0.0.110 SLAVE3_IP=10.0.0.120 Env_config () { rpm -ql redis &> /dev/null || yum -y install redis sed -ri -e "s/(^bind) .*/\1 0.0.0.0/" -e "/requirepass/a requirepass 123456" -e "/masterauth/a masterauth 123456" -r -e "s/(^#) (cluster-e.*)/\2/" -r -e "s/(^#) (cluster-con.*)/\2/" -r -e "s/(^#) (cluster-req.*) (.*)/\2 no/" /etc/redis.conf systemctl start redis } Atm_config () { rpm -ql expect &> /dev/null || yum -y install expect expect << EOF spawn redis-cli -a 123456 --cluster create $MASTER1_IP:6379 $MASTER2_IP:6379 $MASTER3_IP:6379 $SLAVE1_IP:6379 $SLAVE2_IP:6379 $SLAVE3_IP:6379 --cluster-replicas 1 expect "):" { send "yes\n" } expect eof EOF } Env_config #所有服务器都执行该函数 Atm_config #只在一台服务器上执行就好了。 **********************验证状态******************************** #查看是否进入集群状态 [root@Rocky8 ~]#ps aux|grep redis redis 7968 0.1 0.5 53552 10088 ? Ssl 10:30 0:00 /usr/bin/redis-server 0.0.0.0:6379 [cluster] #查看集群对应关系 [root@Rocky8 ~]#cat /var/lib/redis/nodes-6379.conf 7c5226b40e1bae1bc9f21eccc03f89ee124d640e 10.0.0.10:6379@16379 myself,master - 0 1676258181000 1 connected 0-5460 0179c11aa1c478a74d8771cdbe010436753c9570 10.0.0.20:6379@16379 master - 0 1676258182000 2 connected 5461-10922 0f7d1f2fa960921e268607575609e87cf4ee3142 10.0.0.110:6379@16379 slave 0179c11aa1c478a74d8771cdbe010436753c9570 0 1676258183000 5 connected d1aade871153ccf1e5435ae3e8ce95de035bf82e 10.0.0.30:6379@16379 master - 0 1676258184000 3 connected 10923-16383 31625d6511c4cd8d2ffad3444f67ec222f035931 10.0.0.120:6379@16379 slave d1aade871153ccf1e5435ae3e8ce95de035bf82e 0 1676258184064 6 connected dc146a49b969784c5dcf0e7fab422488da3ddebc 10.0.0.40:6379@16379 slave 7c5226b40e1bae1bc9f21eccc03f89ee124d640e 0 1676258183052 4 connected vars currentEpoch 6 lastVoteEpoch 0 #查看集群状态 [root@Rocky8 ~]#redis-cli -a 123456 CLUSTER INFO cluster_known_nodes:6 #6个节点 cluster_size:3 #3个集群 **************************测试集群写数据************************** #在10.0.0.10上写入数据,根据槽位的系统自动分配,数据写到了10.0.0.30上。 [root@Rocky8 ~]#redis-cli -a 123456 -c Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> set a b -> Redirected to slot [15495] located at 10.0.0.30:6379 OK 10.0.0.30:6379> keys * 1) "a" ************************集群扩容****************************** 新增节点:10.0.0.130 10.0.0.140 #用脚本实现环境配置 #!/bin/bash Env_config () { rpm -ql redis &> /dev/null || yum -y install redis sed -ri -e "s/(^bind) .*/\1 0.0.0.0/" -e "/requirepass/a requirepass 123456" -e "/masterauth/a masterauth 123456" -r -e "s/(^#) (cluster-e.*)/\2/" -r -e "s/(^#) (cluster-con.*)/\2/" -r -e "s/(^#) (cluster-req.*) (.*)/\2 no/" /etc/redis.conf systemctl start redis } Env_config #把10.0.0.130加入集群 [root@CentOS ~]#redis-cli -a 123456 --cluster add-node 10.0.0.130:6379 10.0.0.10:6379 #分配槽位 [root@CentOS ~]#redis-cli -a 123456 --cluster reshard 10.0.0.10:6379 #把10.0.0.140加入集群并成为10.0.0.130的从节点 [root@CentOS ~]#redis-cli -a 123456 --cluster add-node 10.0.0.140:6379 10.0.0.10:6379 --cluster-slave --cluster-master-id 7a85702e16187882b97aadb078ce74f103730bc2 ********************************集群缩容************************* #重新分配槽位 [root@CentOS ~]#redis-cli -a 123456 --cluster reshard 10.0.0.10:6379 #为了分配均匀,建议挪三次。每次挪走的槽位就是当时从其他主机挪过来的槽位数量 ********************************集群中删除服务器****************** [root@CentOS ~]#[root@CentOS ~]#redis-cli -a 123456 --cluster del-node 10.0.0.130:6379 7a85702e16187882b97aadb078ce74f103730bc2
3.总结LVS的NAT和DR模型的工作原理。并搭建完成DR模型实战。
(1)NAT模型工作原理:
lvs-nat本质是多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发。
①RIP和DIP应在同一IP网络,且应使用私网地址。RS的网关要指向DIP
②请求报文和响应报文都必须经由Director转发,Director易成为系统瓶颈
③支持端口映射,可修改请求报文的目标PORT
④VS必须是linux系统,RS可也是任意OS系统
(2)DR模型的工作原理:
①Director和各RS都配有VIP
②确保前段路由器将目标IP为VIP的请求报文发往Director:修改内核参数以限制arp通告及应答级别
③RS的RIP可以是使用私网地址,也可以是公网地址,RIP与DIP在同一IP网络,RIP的网关不能指向DIP,以确保响应的报文不会经过Director
④RS和Director要在同一物理网络
⑤请求报文包经由Director,但响应报文不经由Director,而是由RS直接发往Client
⑥不支持端口映射
⑦无需开启ip-forward
⑧RS可使用大多数OS系统
(3)搭建DR模型:
#搭建好环境以后按以下步骤执行 #注意:作为路由器的服务器要打开ip_forward的功能 ******************************************************************* #第1步:修改RS(真实服务器)的内核参数,限制arp通告及应答级别 [root@Rocky8 ~]#vim /etc/sysctl.conf net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.lo.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2 net.ipv4.conf.lo.arp_announce = 2 [root@Rocky8 ~]#sysctl -p #生效 ********************************************************************** #第2步:修改RS(真实服务器)和Lvs服务器的网关,都指向10.0.0.131 [root@Rocky8 ~]#sed -i "s/10.0.0.2/10.0.0.131/" /etc/sysconfig/network-scripts/ifcfg-eth0 [root@Rocky8 ~]#nmcli con reload [root@Rocky8 ~]#nmcli con up eth0 ************************************************************************** #第3步:给RS(真实服务器)和Lvs服务器的lo(回环网卡)添加Vip(虚拟地址) [root@Rocky8 ~]#ip address add 10.0.0.100/32 dev lo label lo:1 ************************************************************************ #第4步:给Lvs服务器添加集群管理规则 [root@Rocky8 ~]#ipvsadm -A -t 10.0.0.100:80 -s rr [root@Rocky8 ~]#ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.10:80 -g [root@Rocky8 ~]#ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.20:80 -g [root@Rocky8 ~]#ipvsadm -ln *********************************************************************** #第5步:修改客户端的网关指向192.168.10.200 [root@Rocky8 ~]#sed -i "s/10.0.0.2/192.168.10.200/" /etc/sysconfig/network-scripts/ifcfg-eth0 [root@Rocky8 ~]#nmcli con reload [root@Rocky8 ~]#nmcli con up eth0 ************************************************************************
4.总结http协议的通信过程详解
(1)建立连接:接收或者拒绝连接请求
(2)接收请求:接收客户端请求报文中对某资源的一次请求的过程
web访问的响应模型:apache用的是多进程I/O模型,安全可靠,有性能瓶颈,适应于传统行业;nginx用的是复用I/O模型,支持高并发,适用于互联网行业。
(3)处理请求:服务器对请求报文进行解析,并获取请求的资源及请求方法等相关信息,根据方法、资源、首部、和可选的主机部分对请求进行处理。
(4)访问资源:服务器对获取请求报文中的请求的资源WEB服务器,即存放了WEB资源的服务器,负责向请求者提供对方请求的静态资源,或动态运行后生成的资源
(5)构建响应报文:响应报文中,包含有响应状态码,响应首部,如果生成了响应主体的话,还包括响应主体
(6)发送响应报文:Web服务器通过连接发送数据时也会面临与接收数据一样的问题。服务器可能有很多条到各个客户 端的连接,有些是空闲的,有些在向服务器发送数据,还有一些在向客户端回送响应数据。服务器要记 录连接的状态,还要特别注意对持久连接的处理。对非持久连接而言,服务器应该在发送了整条报文之 后,关闭自己这一端的连接。对持久连接来说,连接可能仍保持打开状态,在这种情况下,服务器要正 确地计算Content-Length首部,不然客户端就无法知道响应什么时候结束
(7)记录日志:最后当事务结束,web服务器会在日志文件中添加一个条目,来描述已执行的事务。
5.总结网络IO模型和nginx结构
(1)总结网络IO模型:
阻塞型、非阻塞型、复用型、信号驱动型、异步
阻塞型I/O模型:用户线程通过系统调用read发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然后将 接收的数据拷贝到用户空间,完成read操作 用户需要等待read将数据读取到buffer后,才继续处理接收的数据。整个I/O请求的过程中,用户线程是 被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够
非阻塞型I/O模型:程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进 程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成。这么做往往会耗费大量CPU时间, 实际使用很少
I/O多路复用型(I/O multiplexing)模型:一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程。一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLL或EPOLL等系统调用,从而实现多路复用IO。
信号驱动型I/O模型:通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后 主程序可以继续向下执行,当有I/O操作准备就绪,即内核数据就绪时,内核会为该进程产生一个 SIGIO信号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据,将用户进程所需要的数据从内核空间拷贝到用户空间此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。
异步I/O模型:用户进程进行aio_read系统调用之后,无论内核数据是否准备 好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。
(2)nginx结构:
6.完成nginx编译安装脚本
#!/bin/bash core_number=`grep "processor" /proc/cpuinfo |wc -l` nginx_install () { yum -y install gcc pcre-devel openssl-devel zlib-devel wget http://nginx.org/download/nginx-1.22.1.tar.gz -P /usr/local/src/ cd /usr/local/src/ tar xf nginx-1.22.1.tar.gz cd nginx-1.22.1/ useradd -s /sbin/nologin nginx ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module make -j $core_number install chown -R nginx.nginx /usr/local/nginx cat>/usr/lib/systemd/system/nginx.service<<EOF [Unit] Description=nginx - high performance web server Documentation=http://nginx.org/en/docs/ After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID LimitNOFILE=100000 [Install] WantedBy=multi-user.target EOF ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin gzip -c /usr/local/src/nginx-1.22.1/man/nginx.8 > /usr/share/man/man8/nginx.8.gz systemctl enable --now nginx } nginx_install
7.总结nginx核心配置,并实现nginx多虚拟主机
(1)核心配置:
①:user nginx nginx; #启动Nginx工作进程的用户和组
②:worker_processes [number | auto]; #启动Nginx工作进程的数量,一般设为和CPU核心数相同
③:worker_cpu_affinity 00000001 00000010 00000100 00001000 | auto ; #将Nginx工作进程绑 定到指定的CPU核心,默认Nginx是不进行进程绑定的,绑定并不是意味着当前nginx进程独占以一核心CPU, 但是可以保证此进程不会运行在其他核心上,这就极大减少了nginx的工作进程在不同的cpu核心上的来回跳 转,减少了CPU对进程的资源分配与回收以及内存管理等,因此可以有效的提升nginx服务器的性能。
④:worker_priority 0; #工作进程优先级,-20~19
⑤:worker_rlimit_nofile 65536; #所有worker进程能打开的文件数量上限,包括:Nginx的所有连接(例 如与代理服务器的连接等),而不仅仅是与客户端的连接,另一个考虑因素是实际的并发连接数不能超过系统级 别的最大打开文件数的限制.最好与ulimit -n 或者limits.conf的值保持一致。
⑥:daemon off; #前台运行Nginx服务用于测试、或者以容器运行时,需要设为off
⑦:master_process off|on; #是否开启Nginx的master-worker工作模式,仅用于开发调试场景,默认为on
⑧:events 语句块中
worker_connections 65536; #设置单个工作进程的最大并发连接数
accept_mutex on; #on为同一时刻一个请求轮流由worker进程处理,而防止被同时唤醒所 有worker,避免多个睡眠进程被唤醒的设置,默认为off,新请求会唤醒所有worker进程,此过程也称为"惊 群",因此nginx刚安装完以后要进行适当的优化。建议设置为on
multi_accept on; #on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接,此指令默认 为off,即默认为一个工作进程只能一次接受一个新的网络连接,打开后几个同时接受多个。建议设置为on
(2)Nginx多虚拟主机:
#!/bin/bash mkdir -p /data/nginx/html/{pc,mobile} #创建单独存放网页数据文件夹 echo "pc web">/data/nginx/html/pc/index.html echo "mobile web">/data/nginx/html/mobile/index.html mkdir /usr/local/nginx/conf.d/*.conf #创建子配置文件 sed -i "$ i include \/usr\/local\/nginx\/conf.d\/*.conf\;" /usr/local/nginx/conf/nginx.conf cat>/usr/local/nginx/conf.d/pc.conf<<EOF server { server_name www.zyb.com; root /data/nginx/html/pc; } EOF cat>/usr/local/nginx/conf.d/mobile.conf<<EOF server { server_name www.zhangyongbiao.com; root /data/nginx/html/mobile; } EOF
8.总结nginx日志格式定制(json)
①步:在nginx的主配置文件中,http语句块里面添加log_format指令应用json形式
②步:在创建的子配置文件中,在location语句块中添加access_log指令
***********************在主配置文件http语句块中添加*************************** http { include mime.types; server_tokens off; default_type application/octet-stream; log_format json '{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":"$body_bytes_sent",' '"responsetime":"$request_time",' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"uri":"$uri",' '"xff":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"tcp_xff":"$proxy_protocol_addr",' '"http_user_agent":"$http_user_agent",' '"status":"$status"}'; } ***********************在子配置文件的location语句块的添加*********************** server { server_name www.zyb.com; location / { access_log /usr/local/nginx/logs/json-access.log json; } root /data/nginx/html/pc; } #在客户端测试后,查看/usr/local/nginx/logs/json-access.log日志文件 [root@Rocky8 ~]#cat /usr/local/nginx/logs/json-access.log |jq { "@timestamp": "2023-02-21T22:28:06+08:00", "host": "10.0.0.10", "clientip": "10.0.0.131", "size": 7, "responsetime": 0.000, "upstreamtime": "-", "upstreamhost": "-", "http_host": "www.zyb.com", "uri": "/index.html", "xff": "-", "referer": "-", "tcp_xff": "-", "http_user_agent": "curl/7.81.0", "status": "200" }