重点·问题·原理·优化

mysql主从复制原理

slave每隔一段时间监听master,当master数据发生改变,master将数据写进二进制日志,slave开启一个io线程请求二进制日志,master在每个io线程上开启dump线程,将二进制日志传给slave,slave接收到二进制日志,将二进制日志放到中继日志,slave开启sql线程,将中继日志中的数据逐一执行

MHA工作原理

manager定时探测集群中的master节点,当master出现故障,manager会自动将最新数据的slave提升为新的master,然后将其他的slave指向新的master,整个故障转移过程对客户端应用程序完全透明

redis主从复制原理

(1)若启动一个Slave机器进程,则它会向Master机器发送一个“sync command”命令,请求同步连接。

(2)无论是第一次连接还是重新连接,Master机器都会启动一个后台进程,将数据快照保存到数据文件中,同时Master还会记录修改数据的所有命令并缓存在数据文件中。

(3)后台进程完成缓存操作之后,Master机器就会向Slave机器发送数据文件,Slave端机器将数据文件保存到硬盘上,然后将其加载到内存中,接着Master机器就会将修改数据的所有操作一并发送给Slave端机器。若Slave出现故障导致宕机,则恢复正常后会自动重新连接。

(4)Master机器收到Slave端机器的连接后,将其完整的数据文件发送给Slave端机器,如果Master同时收到多个Slave发来的同步请求,则Master会在后台启动一个进程以保存数据文件,然后将其发送给所有的Slave端机器,确保所有的Slave端机器都正常。

哨兵故障转移原理

(1)由哨兵节点定期监控发现主节点是否出现了故障。每个哨兵节点每隔1秒会向主节点、从节点及其它哨兵节点发送一次ping命令做一次心跳检测。如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的)。当超过半数哨兵节点认为该主节点主观下线了,这样就客观下线了。

(2)当主节点出现故障,此时哨兵节点会通过Raft算法实现选举机制共同选举出一个哨兵节点为leader,来负责处理主节点的故障转移和通知。所以整个运行哨兵的集群的数量不得少于3个节点。

(3)由leader哨兵节点执行故障转移,过程如下:

●将某一个从节点升级为新的主节点,让其它从节点指向新的主节点;

●若原主节点恢复也变成从节点,并指向新的主节点;

●通知客户端主节点已经更换。

需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。

集群数据分片的原理

Redis集群引入了哈希槽的概念

Redis集群有16384个哈希槽(编号0-16383)

集群的每组节点负责一部分哈希槽

每个Key通过CRC16校验后对16384取余来决定放置哪个哈希槽,通过这个值,去找到对应的插槽所对应的节点,

然后直接自动跳转到这个对应的节点上进行存取操作

集群模式和哨兵模式的区别

集群模式通过数据分片,解决了radis哨兵模式写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案

docker是什么

docker是用go语言开发并开源的容器引擎,用来运行容器里的应用。docker也是可用来管理容器和镜像的一种工具

容器与虚拟机的区别

容器 虚拟机
所有容器共享宿主机的内核 每个虚拟机都有独立的操作系统和内核
通过namespace实现资源隔离,通过cgroup实现限制资源的最大使用量 完全隔离。每个虚拟机都有独立的硬件资源
秒级启动速度 分钟级启动速度
容器相当于宿主机的进程,性能几乎没有损耗 需要通过hypervisor虚拟机管理程序对宿主机资源虚拟访问,有一定的性能损耗
单机容量能支持成百上千个容器     单机只能支持最多几十个虚拟机

namespace(命名空间)的隔离种类

UTS:主机名与域名

IPC:信号量,消息队列和共享内容

PID:进程号

NETWORK:网络设备,端口,网络栈

MOUNT:挂载点(文件系统)

USER:用户和用户组

docker的三个核心概念

镜像:是创建容器的基础,是一个只读的模板文件,里面包含运行容器中的应用程序所需要的所有内容(应用程序文件、配置文件、运行库文件、依赖包等)

容器:是用镜像运行的实例,容器可以被创建、启动、停止、删除,每个容器之间默认是相互隔离的

仓库:是用来集中保存镜像的地方,有公有仓库和私有仓库之分

docker run 的启动过程

(1)检查本地是否有镜像,如果有则直接使用本地镜像创建容器,如果没有则从仓库拉取镜像再创建容器

(2)在只读的镜像层上挂载一层可读可写的容器层

(3)从docker网桥给容器分配一个虚拟接口和IP

(4)使用镜像的默认启动命令或者指定的启动命令启动容器,直到容器中PID=1的主进程退出为止

docker网络模式

(1)bridge
docker的默认网络模式。使用此模式的每个容器都有独立的网络命名空间namespace,即每个容器都有独立的IP、端口范围(每个容器可以用同一个端口)、路由、iptables规则等网络资源。

(2)host
容器与宿主机共享网络namespace,即容器和宿主机使用同一个IP、端口范围(容器与宿主机或其它使用host模式的容器不能用同一个端口)、路由、iptables规则等网络资源。

(3)container
和指定已存在的容器共享网络namespace,即这两个容器使用同一个IP、端口范围(容器与指定的容器不能用同一个端口)、路由、iptables规则等网络资源。

(4)none
每个容器都有独立的网络namespace,但是容器没有自己的eth0网卡、IP、端口等,只有lo网卡。

创建镜像方法

(1)基于现有镜像创建

先用现有镜像创建启动容器    docker run

再进入容器进行内容更新      docker exec -it

最后提交成新的镜像          docker commit

(2)基于模板文件创建

先获取模板文件             将本地容器导出为模板文件  docker export  或从网上下载现成的模板文件

再将模板文件导入成镜像     docker import 

(3)基于Dockerfile创建

FROM               指定基础镜像(是Dockerfile的第一行指令)

MAINTAINER         指定镜像维护人信息(可选)

RUN                指定linux命令,尽量将多条linux命令合并在一个RUN指令里,用 ; 或 && 或 <

EXPOSE             指定容器要开启的应用的端口号

ENV                指定容器的环境变量

ADD|COPY           复制本地文件|目录到镜像里

VOLUME             指定容器的匿名数据卷(作用类似于 docker run -v /var/lib/docker/volumes/容器ID/:容器数据卷目录)

USER               指定容器的运行用户

WORKDIR            指定后续镜像层的工作目录

ARG                指定构建镜像时传入的参数变量(可通过 "docker build --build-arg 变量=值"  进行传入参数)

CMD|ENTRYPOINT     指定容器启动时执行的命令和参数

如何使用Dockerfile构建镜像

(1)编写Dockerfile文件,在第一行用 FROM 指令指定基础镜像

(2)用 MAINTAINER 指令指定镜像维护人信息(可选)

(3)用 RUN EXPOSE ENV ADD COPY 等指令编写构建镜像的过程

(4)在Dockerfile结尾用 CMD 或 ENTRYPOINT 指令指定容器启动时执行的命令

(5)用 docker build -t 镜像名:标签 .  命令来构建镜像

ADD 和 COPY 的区别

共同点:都可以将本地的文件|目录复制到镜像里

区别:ADD还可以通过URL地址下载文件并复制到镜像里,还能将本地的压缩包解压后再复制到镜像里(URL下载和压缩包解压特性不能同时生效,即通过URL下载的压缩包只能以压缩包的形式复制到镜像里) 

CMD 和 ENTRYPOINT 的区别         

共同点:都可以用来指定容器的启动命令

区别:ENTRYPOINT指定的容器启动命令优先级更高,如果CMD和ENTRYPOINT同时存在,那么CMD指定的内容将作为ENTRYPOINT指定的容器启动命令的选项或参数使用

如何缩小镜像的体积大小

(1)尽可能的使用较小体积的基础镜像(推荐使用 alpine 镜像)

(2)尽可能的减少Dockerfile指令的数量,从而来减少镜像的层数

(3)在RUN指令结尾添加安装软件后清空yum/apt缓存、软件包的命令

(4)在 RUN 之后放置 COPY,这样可以充分利用镜像缓存

(5)使用 .dockerignore 文件,将不复制到镜像的文件|目录定义在 .dockerignore 文件里

(6)容器镜像里一般只运行单个应用

(7)使用多阶段(多级)构建的方法      FROM 第一构建阶段的基础镜像 as 别名

Kafka是如何部署的

先说明 kafka 版本

如果是 2.X 版本,要先部署 3|5 节点的 zk 集群,然后再在每个 zk 节点上部署 kafka 应用。

如果是 3.X 版本,kafka 不再依赖 zk ,所以可以直接部署 3|5 节点的 kafka 集群。

kafka管理操作

#创建topic

kafka-topics.sh --zookeeper IP1:2181,IP2:2181,IP3:2181 --create --topic 队列名 --partitions 分区数 --replication-factor 副本数

#查看topic列表

kafka-topics.sh --zookeeper IP1:2181,IP2:2181,IP3:2181 --list

#查看topic详细信息

kafka-topics.sh --zookeeper IP1:2181,IP2:2181,IP3:2181 --discribe --topic 队列名

#修改topic分区配置

kafka-topics.sh --zookeeper IP1:2181,IP2:2181,IP3:2181 --alter --topic 队列名 --partitions 分区数(只能增不能减)

#删除topic

kafka-topics.sh --zookeeper IP1:2181,IP2:2181,IP3:2181 --delete --topic 队列名 

#向topic推送消息                           

kafka-console-producer.sh --broker-list IP1:9092,IP2:9092,IP3:9092 --topic 队列名 

#从topic拉取消息

kafka-console-consumer.sh --bootstrap-server IP1:9092,IP2:9092,IP3:9092 --topic 队列名 [--from-beginning]      

kafka·topic消息堆积解决方法         

  1. 增加消费者数量:增加消费者的数量可以提高消息的消费速度,从而减少消息堆积。

  2. 提高消费者处理能力:优化消费者的代码逻辑,提高处理消息的效率,从而加快消息的处理速度。

  3. 调整消息发送频率:如果消息发送频率过高,可以适当降低发送频率,避免消息堆积。

  4. 增加消息缓冲区大小:增加消息缓冲区的大小可以暂存更多的消息,减少消息丢失的风险。

  5. 优化Topic配置:根据实际需求,调整Topic的分区数量、复制因子等配置,提高Topic的性能。

  6. 使用流处理框架:如果需要对大量消息进行复杂的处理,可以考虑使用流处理框架(如 Kafka Streams、Apache Flink 等)来处理消息。

  7. 监控和告警:实时监控Topic的消息堆积情况,设置合适的告警阈值,及时发现并处理消息堆积问题。

kafka·topic的消息并发发送性能低

  1. 调整消息发送频率:如果发送消息的频率过高,可能会导致性能下降。尝试降低消息发送的频率,给系统一些时间来处理和发送消息。

  2. 优化消息体大小:较大的消息体可能会导致性能下降。尽量减少消息体的大小,只发送必要的数据。

  3. 增加硬件资源:如果系统资源(如 CPU、内存、网络带宽等)不足,可能会影响消息并发发送的性能。考虑升级硬件或增加资源来提升性能。

  4. 使用批量发送:将多个消息批量发送可以提高效率。一些消息中间件提供了批量发送的功能,可以一次性发送多个消息,减少网络传输的次数。

  5. 优化消息生产者:确保你的消息生产者代码高效且没有性能瓶颈。优化代码逻辑、避免不必要的计算和数据库操作等,可以提高消息发送的性能。

  6. 调整 Topic 的配置:根据你使用的具体消息中间件,可能有一些配置选项可以调整以提高性能。例如,增加 Topic 的分区数量、调整缓冲区大小等。

  7. 使用高性能的消息中间件:如果你使用的消息中间件本身性能较低,可以考虑评估其他高性能的消息中间件,以满足你的需求。

  8. 监控和性能调优:使用性能监控工具来监测消息发送的性能指标,如吞吐量、延迟等。根据监控数据进行性能调优,找出潜在的瓶颈并进行优化。

ELK组件

ElasticSearch:对日志数据进行分片、存储,并创建索引,方便全文检索

Logstash: 采集日志数据,通过插件模块对数据进行过滤、格式化处理,再输出给ElasticSearch

Kibana:接入ElasticSearch的数据源,将日志数据进行图形化展示,方便用户通过浏览器查看、统计、分析日志

ELK工作原理

(1)在所有需要收集日志的服务器上部署Logstash;或者先将日志进行集中化管理在日志服务器上,在日志服务器上部署 Logstash。

(2)Logstash 收集日志,将日志格式化并输出到 Elasticsearch 群集中。

(3)Elasticsearch 对格式化后的数据进行索引和存储。

(4)Kibana 从 ES 群集中查询数据生成图表,并进行前端数据的展示。

ElasticSearch集群化部署

节点分三种类型:master/data/client

数量>3

服务发现:设置相同的cluster.name并使用Zen Discovery模块通过单播(ping)实现集群中节点的服务发现

ElasticSearch优化

1、优化 ES 索引设置

(1)优化 fsync

频繁地执行 fsync 操作, 可能会产生阻塞导致部分操作耗时较久. 如果允许部分数据丢失, 可设置异步刷新 translog 来提高效率,还有降低 flush 的阀值

(2)优化 refresh

加大时长可以降低系统开销。对于日志搜索来说,实时性要求不是那么高,设置为 5 秒或者 10s;对于 SkyWalking,实时性要求更低一些,我们可以设置为 30s

(3)优化 merge

index.merge.scheduler.max_thread_count 控制并发的 merge 线程数,如果存储是并发性能较好的 SSD,可以用系统默认的 max(1, min(4, availableProcessors / 2)),当节点配置的 cpu 核数较高时,merge 占用的资源可能会偏高,影响集群的性能,普通磁盘的话设为1,发生磁盘 IO 堵塞。设置 max_thread_count 后,会有 max_thread_count + 2 个线程同时进行磁盘操作,也就是设置为 1 允许 3 个线程

2、优化线程池配置

(1)线程数改为 17,也就是 cpu 总核数加 1

(2)队列容量加大。队列在此时的作用是消峰。不过队列容量加大本身不会提升处理速度,只是起到缓冲作用。此外,队列容量也不能太大,否则积压很多任务时会占用过多堆内存。

3、锁定内存,不让 JVM 使用 Swap

(1)Linux 系统中的关闭 Swap (临时有效)

(2)Linux 系统中的尽可能减少 Swap 的使用(永久有效)

(3)启用 bootstrap.memory_lock

4、减少分片数、副本数

Logstash的缺点和优化

缺点:

logstash占用性能大,尤其是对内存需求大

优化:

增加内存

Filebeat替代Logstash采集日志数据

Fluentd替代Logstash采集日志数据和过滤转换等功能,常用于K8S容器环境

Kafka/Redis作为MQ消息队列,实现流量削峰、缓冲

ElasticSearch索引管理

1.用curl命令管理

创建索引
curl -X PUT[|POST] http://IP:9200/<索引名>[/<类型>/<文档ID>?pretty&pretty] \
[-H 'content-Type: application/json' -d '{"键名1":"键值","键名2":"键值"}']

删除索引
curl -X DELETE http://IP:9200/<索引名>[,<索引名2>,....]

查看索引配置
curl -X GET http://IP:9200/<索引名>/_settings

修改索引配置
curl -X PUT http://IP:9200/<索引名>/_settings \
-H 'content-Type: application/json' -d '{"键名":"键值"}'

创建索引别名
curl -X POST http://IP:9200/_aliases \
-H 'content-Type: application/json' -d '{"actions":[{"add":{"index":"索引名","alias":"索引别名"}}]}'

删除索引别名
curl -X POST http://IP:9200/_aliases \
-H 'content-Type: application/json' -d '{"actions":[{"remove":{"index":"索引名","alias":"索引别名"}}]}'

2.在Kibana的索引管理中进行管理

Redis 为什么那么快?

(1)redis是基于内存运行的,数据读写都是在内存中完成的

(2)数据读写采用单线程模式,避免了多线程切换带来的CPU性能消耗,同时也不要考虑各种锁的问题

(3)采用IO多路复用模型,可以使线程处理更多的网络连接请求,提高并发能力

redis优化

(1)设置 config set activedefrag yes 开启内存碎片自动清理,或者定时执行 memory purge 清理内存碎片

(2)尽可能使用 hash 数据类型存储数据。因为 hash 类型的一个 key 可包含多个字段,该类型的数据占用空间较小

(3)建议给 key 设置过期时间

(4)精简 key 的键名和键值,控制 key 占用空间的大小,避免 bigkey 的产生(redis-cli --bigkeys 可用于查找bigKey)

(5)修改配置 maxmemory 指定redis可占用的最大内存大小
   修改配置 maxmemory-policy 指定内存数据淘汰策略(key的回收策略),实现保证内存使用率不超过最大内存
   修改配置 maxmemory-samples 指定内存数据淘汰策略的样本数量,一般为3~7,值越大样本越精确
   修改配置 maxclients 指定最大客户端连接数
   修改配置 tcp-backlog 指定最大连接排队数
   修改配置 timeout 指定连接超时时间
   修改配置 lazyfree-lazy-expire yes  设置惰性删除,将删除过期key的操作放在后台中去执行,避免阻塞主线程
   修改配置 no-appendfsync-on-rewrite yes  设置AOF文件重写期间,AOF后台子进程不进行刷盘操作,避免AOF重写和fsync竞争磁盘IO资源,导致redis延迟增加

(6)设置AOF持久化和主从复制来备份数据,采用哨兵或集群模式实现redis集群的高可用

(7)建议设置 config set requirepass 或 修改配置 requirepass 来设置 redis 密码

Ceph的存储过程

(1)文件默认会按照4M大小进行分片成一个或多个数据对象(object)

(2)每个数据对象都有一个oid(由文件ID(ino)和分片编号(ono)组成),通过对oid使用HASH算法得到一个16进制的特征码,再除以Pool中的PG总数取余,获取到数据对象的pgid(整体由poolid+pgid组成)

(3)通过对pgid使用CRUSH算法得到PG对应的OSD的ID,如果是多副本,则是主从OSD的ID(注:PG与OSD的对应关系是在创建存储池Pool的时候就确定好的)

(4)将数据对象存储到对应的OSD里

Ceph架构(自上往下)

客户端(主机/虚拟机/容器/应用程序APP):在Ceph中进行数据读写的终端。

LibRADOS对象访问接口:提供访问存储接口给客户端使用。Ceph默认提供三个接口:RBD块存储接口、RGW对象存储接口、CephFS文件存储接口。还支持用户使用java、python、C、C++等编程语言二次开发自定义访问接口。

RADOS基础存储系统(统一存储池):提供存储能力的。Ceph中一切都是以对象(object)形式存储的。RADOS就是负责存储这些对象的,并保证数据的一致性和可靠性。

nginx优化

应用程序配置文件优化:
性能优化:
IO多路复用               use epoll;
设置工作进程数           worker_processes  与CPU数量相同或auto;
工作进程静态绑核         worker_cpu_affinity
设置并发                 worker_connections       worker_rlimit_nofile
连接保持超时             keepalive_timeout  服务器超时时间 [客户端超时时间];
网页压缩                 gzip on;
页面缓存时间             expires 时间;

安全优化:
隐藏版本号               server_tokens off;       修改源代码
防盗链                   rewrite 
设置运行用户/组          user  用户名 组名;
限制单个ip的访问频率     limit_req
限制单个ip的连接数       limit_conn

日志分割                 脚本 + crontab


系统内核优化:
/etc/sysctl.conf  内核参数配置文件
net.ipv4.tcp_syncookies = 1                  开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击
net.ipv4.tcp_tw_reuse = 1                    开启重用,允许将TIME-WAIT sockets重新用于新的TCP连接
net.ipv4.tcp_tw_recycle = 1                  开启TCP连接中TIME-WAIT sockets的快速回收
net.ipv4.tcp_fin_timeout = 30                修改系默认的 TIMEOUT 时间(MSL值)
net.ipv4.tcp_max_tw_buckets = 5000           系统同时保持TIME-WAIT的最大数量
net.ipv4.ip_local_port_range = 1024 65535    外向连接的端口范围
net.ipv4.tcp_max_syn_backlog = 8192          系统能接受的tcp半连接的最大队列数
net.core.somaxconn = 10000                   每一个端口最大的 Listen 监听队列的长度
net.ipv4.tcp_keepalive_time = 1200           发送keepalive探测包消息的频率

/etc/security/limits.conf   内核限制文件
*     soft     noproc            65535      打开的进程数
*     hard     noproc            65535
*     soft     nofile            65535      打开的文件数
*     hard     nofile            65535
*     soft     memlock         unlimited     不做内存锁定
*     hard     memlock         unlimited


用过哪些nginx模块?
http_gzip_module              网页压缩模块
http_stub_status_module       状态统计模块
http_auth_basic_module        网页用户认证模块
http_fastcgi_module           fastcgi转发php-fpm的模块
http_rewrite_module           URL重写模块
http_ssl_module               https安全加密模块
http_limit_conn_module        限制最大连接数模块
http_limit_req_module         限制最大访问频率模块
http_proxy_module             请求转发模块
http_image_filter_module      图片处理模块
http_upstream_*_module        负载均衡服务器列表模块
stream_*_module               四层代理转发模块

Zabbix 组件

zabbix server(端口10051):zabbix服务端进程,用于配置和管理zabbix应用程序,也是监控系统的告警中心(需要配置监控项告警触发阈值和发送告警)

zabbix database:持久化存储配置信息和监控指标数据(支持mysql oracle gpdb tsdb等)

zabbix web:用于zabbix服务端配置界面和监控数据的UI界面展示(支持LAMP/LNMP)

zabbix agent(端口10050):部署在被监控的主机上,采集监控指标数据,并发送给zabbix server(数据采集支持主动模式和被动模式)
              主动模式:zabbix agent 主动向 zabbix server 请求监控项列表,并主动将监控项需要的数据发送给 zabbix server
              被动模式:zabbix agent 被动接收 zabbix server 请求的监控项列表,zabbix agent 发送监控项需要的数据发送给 zabbix server

zabbix proxy:zabbix代理端进程,部署在zabbix server与zabbix agent之间,代替zabbix server接收zabbix agent发送的监控数据并存储在本地,汇总后再转发给 zabbix server,从而可以分担zabbix server的集中式负载压力

zabbix java gateway:用于获取从通过JMX在JAVA应用暴露的端口采集监控数据

SNMP协议:用来监控不能安装zabbix agent,但支持SNMP协议的的网络设备

Zabbix 工作原理

zabbix agent 会定期采集被监控主机的指标数据并发送给 zabbix server,zabbix server 接收数据后会存储到 zabbix database 里,管理员可基于 zabbix web 即可在浏览器查看到监控数据的图像。
 

tomcat优化

tomcat 的优化:
1)配置文件优化
修改 server.xml 文件
maxThreads(最大线程数/并发)  processorCache(进程缓冲)  acceptCount(等待队列数)  enableLookups(关闭DNS反向解析)  URIEncoding(网页字符集编码UTF-8) maxKeepAliveRequests(长连接最大请求数)  connectionTimeout(连接超时时间)  compression(开启页面压缩)

2)系统内核优化
/etc/security/limits.conf     nofile  nproc  memlock
/etc/sysctl.conf   net.ipv4.tcp_tw_reuse=1   net.ipv4.tcp_tw_recycle=1   net.ipv4.tcp_fin_timeout=30  
                   net.ipv4.tcp_max_tw_buckets=5000    net.ipv4.ip_local_port_range=1024 65535 

3)JVM优化
在 catalina.sh 中设置 JAVA_OPTS 参数
JAVA_OPTS="$JAVA_OPTS -server -Xms2048m -Xmx2048m -XX:PermSize=1024m -XX:MaxPermSize=1024m -Xmn768m"

-server  表示启用JDK的Server模式,实现在多核服务器性能更佳
-Xms2048m -Xmx2048m  设置JVM堆内存初始值和最大最一样大,一般设置为物理内存的 1/2
-XX:PermSize=1024m -XX:MaxPermSize=1024m   设置永久代(非堆内存)初始值和最大最一样大,一般设置为物理内存的 1/4
初始值和最大最设置一样大的原因:可以减少GC次数和内存伸缩带来的频繁内存申请,从而减少一定的系统开销。
-Xmn 设置JVM堆内存新生代的大小,一般设置为堆内存的 3/8

-XX:ParallelGCThreads=2   设置并行GC(垃圾回收)线程数,提高垃圾回收效率
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/tomcat/temp/oom.hprof  设置进程发生OOM异常退出会进行DUMP备份
-XX:+DisableExplicitGC  禁止调用System.gc()方法,防止误调用系统gc方法导致系统的JVM堆内存大起大落而使系统响应效率严重降低

LVS、Nginx、HAProxy做负载均衡各自优缺点

Nginx的优点:
●工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构。Nginx正则规则比HAProxy更为强大和灵活。
●Nginx对网络稳定性的依赖非常小,理论上能ping通就就能进行负载功能,LVS对网络稳定性依赖比较大,稳定要求相对更高。
●Nginx安装和配置、测试比较简单、方便,有清晰的日志用于排查和管理,LVS的配置、测试就要花比较长的时间了。
●可以承担高负载压力且稳定,一般能支撑几万次的并发量,负载度比LVS相对小些。
●Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等。
●Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。
●Nginx作为Web正向加速缓存越来越成熟了,速度比传统的Squid服务器更快,很多场景下都将其作为向代理加速器。
●Nginx作为静态网页和图片服务器,这方面的性能非常优秀,同时第三方模块也很多。

Nginx的缺点:
●Nginx仅能支持http、https和Email协议,这样就在适用范围上面小些。
●对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测。
●不支持Session的直接保持,需要通过ip_hash和cookie的引导来解决。

LVS的优点:
●抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生。因此负载均衡软件里的性能最强的,对内存和cpu资源消耗比较低。
●LVS工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案。
●无流量,LVS只分发请求,而流量并不从它本身出去,这点保证了均衡器IO的性能不会收到大流量的影响。
●应用范围较广,因为LVS工作在4层,所以它几乎可对所有应用做负载均衡,包括http、数据库等。

LVS的缺点:
●软件本身不支持正则表达式处理,不能做动静分离。相对来说,Nginx/HAProxy+Keepalived则具有明显的优势。
●如果是网站应用比较庞大的话,LVS/DR+Keepalived实施起来就比较复杂了。相对来说,Nginx/HAProxy+Keepalived就简单多了。

HAProxy的优点:
●HAProxy也是支持虚拟主机的。
●HAProxy支持8种负载均衡策略。
●HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导,同时支持通过获取指定的url来检测后端服务器的状态。
●HAProxy跟LVS类似,本身就只是一款负载均衡软件,单纯从效率上来讲HAProxy会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx的。
●HAProxy支持TCP协议的负载均衡转发。
 

LVS工作模式

(1)NAT 地址转换
调度器会作为所有节点服务器的默认网关,也是客户端的访问入口和节点服务器返回响应消息的出口,所以调度器会承载双向流量的负载压力,可能会为整个群集的性能瓶颈。由于节点服务器都会处于内网环境,使用私网IP,所以具有一点的安全行。

(2)TUN IP隧道   IP Tunnel  
调度器仅作为客户端的访问入口,节点服务器的响应消息是直接返回客户端的,不需要经过调度器。但是由于节点服务器需要部署在不同的公网环境,所以要有独立的公网IP,而且调度器与节点服务器是通过专用的IP隧道实现相互通信,因此IP隧道模式的成本较高、安全性较低,且数据IP隧道传输的过程中需要额外的封装和解封装,性能也会受到一定的影响。

(3)DR 直接路由  Direct Routing
调度器仅作为客户端的访问入口,节点服务器的响应消息是直接返回客户端的,不需要经过调度器。(与NAT模式的区别)
节点服务器与调度器是部署在同一个物理网络里,因此不需要建议专用的IP隧道。(与IP隧道模式的区别)
DR模式是企业首选的LVS模式。

简述LVS三种工作模式,简述他们的区别

NAT:通过网络地址转换实现的虚拟服务器,大并发访问时,调度器的性能成为瓶颈
DR:使用路由技术实现虚拟服务器,节点服务器需要配置VIP,注意MAC地址广播
TUN:通过隧道方式实现虚拟服务器。

LVS工作的优缺点

1、NAT模式(VS-NAT)

原理:首先负载均衡器接收到客户的请求数据包时,根据调度算法决定将请求发送给哪个后端的真实服务器(RS)。然后负载均衡器就把客户端发送的请求数据包的目标IP地址及端口改成后端真实服务器的IP地址(RIP)。真实服务器响应完请求后,查看默认路由,把响应后的数据包发送给负载均衡器,负载均衡器在接收到响应包后,把包的源地址改成虚拟地址(VIP)然后发送回给客户端。

优点:集群中的服务器可以使用任何支持TCP/IP的操作系统,只要负载均衡器有一个合法的IP地址。

缺点:扩展性有限,当服务器节点增长过多时,由于所有的请求和应答都需要经过负载均衡器,因此负载均衡器将成为整个系统的瓶颈。
2、直接路由模式(VS-DR)

原理:首先负载均衡器接收到客户的请求数据包时,根据调度算法决定将请求发送给哪个后端的真实服务器(RS)。然后负载均衡器就把客户端发送的请求数据包的目标MAC地址改成后端真实服务器的MAC地址(R-MAC)。真实服务器响应完请求后,查看默认路由,把响应后的数据包直接发送给客户端,不需要经过负载均衡器。

优点:负载均衡器只负责将请求包分发给后端节点服务器,而RS将应答包直接发给用户。所以,减少了负载均衡器的大量数据流动,负载均衡器不再是系统的瓶颈,也能处理很巨大的请求量。

缺点:需要负载均衡器与真实服务器RS都有一块网卡连接到同一物理网段上,必须在同一个局域网环境。
3、IP隧道模式(VS-TUN)

原理:首先负载均衡器接收到客户的请求数据包时,根据调度算法决定将请求发送给哪个后端的真实服务器(RS)。然后负载均衡器就把客户端发送的请求报文封装一层IP隧道(T-IP)转发到真实服务器(RS)。真实服务器响应完请求后,查看默认路由,把响应后的数据包直接发送给客户端,不需要经过负载均衡器。

优点:负载均衡器只负责将请求包分发给后端节点服务器,而RS将应答包直接发给用户。所以,减少了负载均衡器的大量数据流动,负载均衡器不再是系统的瓶颈,也能处理很巨大的请求量。

缺点:隧道模式的RS节点需要合法IP,这种方式需要所有的服务器支持“IP Tunneling”。

列举你知道的LVS调度算法

轮询(Round Robin);
加权轮询(Weighted Round Robin);
最少连接(Least Connections);
加权最少连接(Weighted Least Connections);
源地址哈希值(source hash)

脑裂

现象:主服务器和备服务器同时拥有VIP
原因:因为主服务器和备服务器之间的通信链路中断,导致备服务器无法收到主服务器发送的VRRP通告消息,备服务器误认为主服务器故障了并通过IP命令生成VIP
解决:关闭主服务器或备服务器其中一个的keepalived服务
预防:

(1)主服务器和备服务器之间添加双链路通信

(2)在主服务器上添加脚本进行判断与备服务器通信链路是否中断,如果确实是链路中断则自行关闭keepalived服务

(3)利用第三方应用或监控系统检测是否发送脑裂故障,如果发送脑裂故障则通过第三方应用或监控系统来关闭主服务器或备服务器上的keepalived服务

nginx反向代理(4层和7层)

四层反向代理:基于 IP + PORT 实现的代理转发(根据IP和PORT来转发请求),通常用于做客户端的访问入口和负载均衡器等应用场景。
配置:
1)编译安装需要 ./configure --with-stream 添加四层代理模块
2)在 http 同层级,一般在 http 配置块上面添加 stream 配置块,在里面定义服务器池、监听端口和转发配置
stream {
    upstream backend {
        server IP1:PORT1 weight=1;
        ....
        [调度策略];
    }

    server {
        listen PROT;
        proxy_pass backend;       #注:四层代理不需要添加协议
    }
}

http {....}

七层反向代理:基于 http、https、mail 等七层应用协议的代理转发(根据用户访问请求的URL路径来转发请求),通常用于动静分离等应用场景。
配置:
1)在 http 配置块中设置 upstream 定义 后端/上游服务器池的名称和节点参数
http {
    ....
    upstream backend {
        server IP1:PORT1 weight=1;
        ....
        [调度策略];
    }

2)在 server 配置块中用 location 匹配用户访问请求的URL路径,使用 proxy_pass 基于协议转发请求
    server {
        location ~ .*\./jsp {
            proxy_pass http://backend;
        
            proxy_set_header HOST $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forworded-For $proxy_add_x_forwarded_for;
        }
    }
}

Keepalived通过什么判断哪台主机为主服务器,通过什么方式配置浮动IP

Keepalived首先做初始化先检查state状态,master为主服务器,backup为备服务器。
然后再对比所有服务器的priority,谁的优先级高谁是最终的主服务器。
优先级高的服务器会通过ip命令为自己的电脑配置一个提前定义好的浮动IP地址。

keepalived的抢占与非抢占模式

抢占模式即MASTER从故障中恢复后,会将VIP从BACKUP节点中抢占过来。非抢占模式即MASTER恢复后不抢占BACKUP升级为MASTER后的VIP
非抢占式俩节点state必须为bakcup,且必须配置nopreempt。
注意:这样配置后,我们要注意启动服务的顺序,优先启动的获取master权限,与优先级没有关系了。

ctime,atime,mtime

ctime(status time):
当修改文件的权限或者属性的时候,就会更新这个时间,ctime并不是create time,更像是change time,
只有当更新文件的属性或者权限的时候才会更新这个时间,但是更改内容的话是不会更新这个时间。

atime(accesstime):
当使用这个文件的时候就会更新这个时间。

mtime(modification time):
当修改文件的内容数据的时候,就会更新这个时间,而更改权限或者属性,mtime不会改变,这就是和ctime的区别。

rewrite 和 location

从功能看 rewrite 和 location 似乎有点像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,还可以proxy_pass 到其他机器。

rewrite 对访问的域名或者域名内的URL路径地址重写
location 对访问的路径做访问控制或者代理转发

redis的三大缓存问题

缓存雪崩:redis中大量缓存key集体过期
缓存穿透:大量请求访问redis和MySQL都不存在的资源
缓存击穿:redis中一个热点key过期,此时又有大量用户访问这个热点key(redis-cli --hotkeys 可用于查找热Key)


缓存雪崩的解决方案:
使用随机数设置key的过期时间,防止集体过期
设置缓存标记,如果缓存过期,则自动更新缓存
数据库使用排他锁,实现加锁等待


缓存穿透的解决方案:
对空值也进行缓存
使用布隆过滤器进行判断拦截一定不存在的无效请求
使用脚本实时监控,进行黑名单限制


缓存击穿的解决方案:
预先对热点数据进行缓存预热
监控数据,实时调整过期时长
数据库使用排他锁,实现加锁等待

如何保证 MySQL 和 redis 的数据一致性?

读取数据时,先从redis读取数据,如果redis中没有,再从MySQL中读取,并将读取到的数据同步到redis缓存中。
更新数据时,先更新MySQL数据库,再更新redis缓存
删除数据时,先删除redis缓存,再删除MySQL数据库
对于一些关键数据,可以使用MySQL的触发器来实现同步更新redis缓存。也可以使用定时任务,定时自动进行缓存预热,来定期同步MySQL和redis的数据。

redis的2种持久化方式

RDB持久化:定时把redis内存中的数据进行快照并压缩保存到硬盘里

手动触发(bgsave命令)     自动触发(满足save指令配置的条件,主从全量同步,执行shutdown命令时)

文件名:dump.rdb

优缺点:RDB持久化保存的文件占用空间小,网络传输块,恢复速度也比AOF更快,性能影响比AOF更小;实时性不如AOF,兼容性较差,持久化期间在fork子进程时会阻塞redis父进程。

AOF持久化:以追加的方式将redis写操作的命令记录到aof文件中

执行流程:命令追加(写命令追加到aof_buf缓冲区)

文件写入和同步(文件名:appendonly.aof,同步策略:appendfsync everysec|always|no)

文件重写(减少aof文件占用空间的大小和加快恢复速度,执行bgrewriteaof命令触发)

优缺点:实时性比RDB更好,支持秒级持久化,兼容性较好,持久化保存的文件占用磁盘空间更大,恢复速度更慢,性能影响更大,AOF文件重写期间在fork子进程时会阻塞redis父进程

MyISAM 与 InnoDB 的区别

MyISAM:不支持事务、外键约束,只支持表级锁定,适合单独的查询和插入的操作,读写会相互阻塞,支持全文索引,硬件资源占用较小,数据文件和索引文件是分开存储的(存储成三个文件:表结构文件.frm、数据文件.MYD、索引文件.MYI)
使用场景:适用于不需要事务支持,单独的查询或插入数据的业务场景

InnoDB:支持事务、外键约束,支持行级锁定(在全表扫描时仍然会表级锁定),读写并发能力较好,支持全文索引(5.5版本之后),缓存能力较好可以减少磁盘IO的压力,数据文件也是索引文件(存储成两个文件:表结构文件.frm、数据文件.ibd)
使用场景:适用于需要事务的支持,一致性要求较高,数据会频繁更新,读写并发高的业务场景

如何避免死锁

(1)设置事务的锁等待超时时间 innodb_lock_wait_timeout

(2)设置开启死锁检测 innodb_deadlock_detect

(3)为表添加合理的索引,减少表锁发生的概率

(4)如果业务允许,可以降低隔离级别,比如采用 提交读 隔离级别

(5)建议开发人员尽量使用更合理的业务逻辑,多表操作时以固定顺序访问表,尽量避免同时锁定多个资源

(6)建议开发人员尽量保持事务简短,减少对资源的占用时间和占用范围

(7)建议开发人员在读多写少的场景下适用乐观锁机制

你可能感兴趣的:(运维)