面试准备50问
面试官您好,我是xxxx,大概3分钟的
想学容器化的东西,自学了一些东西,然后想有个发展。
平台的问题,因为像我之前几个怎么说,接不接触不到,就是一些先进的技术。而且这个对个人发展来说,就是一直弄那点服务器,但是对个人锻炼不是很好,需要你就是有更好的一个晋升空间。
想学容器化的东西,自学了一些东西,然后想有个发展。接不接触不到先进的技术。而且这个对个人发展来说,就是一直弄那点服务器,但是对个人锻炼不是很好,需要你就是有更好的一个晋升空间。
我们最近一个项目的架构,70 台左右。半容器化的结构,前面是用的那个中间件和 web 服务,用的是那个容器,后面MySQL 数据库物理机。然后 f5 做的负载均衡,后面接的ingress-nginx做的7层代理动静分离这些业务分离,然后中间件主要是 Redis amiba。然后底层就这些。还有那个一些其他的包括 prometheus和EFK。
efk 因为这个 brand D 这个相对相对那个 love start 那个,因为之前是 Java 编写的,比较占资源,这个是每个机器上都要装,所以 front D 这个是使用够远,编写它比较小。节省资源
扩容主要是配合着来。因为我们这边节假日扩容说如果用 hpa 的话,它可能扩容的速度会比较慢,有时候是跟不上。所以hpa 进行微调,而且事先先进行手动扩容,然后等到 hpa 上去的时候再进行。就是根据使用的访问量,它消耗的作用量在进行扩容,就要人监控了。括的是副本数是吧
节点不扩的节点充足的,对资源是充足的。
多个集群。所有服务器 70 多个;半容器化,前面是容器化,后面数据库是物理机的。
无状态和中间件的服务容器上面,有状态的都放物理机是吧。
中间件也是放在那里面,因为中间件总是会出现故障。如果是容器化部署的话,它可能就是有一个治愈性,它如果出现故障会治愈。所以说我们中间件也是选择放在你那上面的。
然后这边架构其实不大,大概 70 台左右,采用的半容器化这个结构。前面那个 web 界面还有这个中间件是采用的容器化部署,后面的 MySQL 数据库是采用的就是物理机。这里面如果是再细一点,就是采用 F5 做的是二层代理,做的二层代理,然后Ingress-Nginx进行七层代理,代理到后端不同的 service 集群里面做了一个动静分离,还有一个业务的分离。然后再通过这个中间件Redis 和 amama 做的读写分离。 MySQL 数据库有这种不光是一种有主主多活,还有读写分离这种。然后监控的这方面采用Promethus日志监控采用的是EFK。
镜像仓库是一部分,如果那边业务升级了,我们这边是通过这个对镜像进行封装。封装之后开发那边进行测试。测试之后我们这边是进行一个上线操作,就是先进行金丝雀部署,然后运行一段时间之后没有关没有没有问题了。之后就是滚动更新,通过25% 50% 这种进行逐步更新。另一个就是我们集群如果也是需要经常进行的一些调整,比如说哪个业务模块访问量增加,需要给他进行一个扩容缩操作啊还有一些客户这面要求的,根据客户需求来判断,就是以及访问量级来判断哪些些集群需要扩容。说啊还有一些日常处理吧,告警处理。
根据客户那些需求进行一些版本滚动升级以及日又比如说我们这边节假日访问量提高,做好事前预案处理,然后根据他们需求进行这个集群扩容操缩作,然后进行资源挖潜以及一些日常故障的处理。
有一个业务模块,资源占用率在逐步升高。设的是一个 hpa 自动扩容缩操作,当它扩容到顶点之后,它就会报警。根据经验来判断,它这个因为访容量增加,导致它这个业务模块就是资源使用率升高。做了扩容操作,两个小时左右再一次报警。然后又进行了一次扩容操作。然后第三次报警的时候,我才发现可能是不太正常。然后之后我是查询了一个访问量日志访问量,内存使用的趋势图。然后对你这个占用那个内存的这个 POD 来进行一个监控,发现那个有一个报警,就是那个 oome 然后最后经过排查确定是那个内存溢出的一个问题。然后因为当时比较晚,也就是给那几个开发人员打电话,有的也打不通。最后找到一个开发人员,我是跟他沟通是想让他如果能尽快定位问题,我这边也如果他这边说把个代码相关操作给我发过来,我这边可以进行一个更新,但是他说这边是定位不到问题,最后没有办法,进行了一个版本回滚操作。回滚之后其实我们这个业务模块就恢复回复到之前的样子了。然后最后之后这个事情是之后解决的。
因为这个问题是经常比较常遇到的,我们这边访问量上涨,然后没有跑量上涨进行扩容。有事先预案,另一个根据经验判断,当时是一个错误的操作,完全因为事情也比较多,当时错误的操作进行扩容,导致这个问题处理没有及时处理掉。
预案。就是我们每一次放假之前都是会首先一个对我们这个之前的历史记录进行一个分析,然后分析哪个集群还行,需要的资源会更多一些,然后资源调优。另一个如果说我这个集群如果挂掉了,因为访问量继争挂掉了,我应该怎样去切流,重启这些操作,怎样去保持这个服务可用性。
实际演练这个会的。
你这个步骤不是很完整,就是一个大致的方案。
主要看我们这边工作经验了吧。这个其实这个因为主要主要是什么呢?因为我们这边其实资源是充足的,所以我们虽然做预案,但是可能说平时出现那种紧急故障,大型大规模的故障比较少,所以说对方面确实是有一些薄弱。
主要是后端,微服务集群是svc ,他通过服务发现到CoreDNS 进行服务发现可以和其他的服务进行这个进行连接。具体架构就是Nginx做七层代理。而后面代理的不同的就是页面,像这些挂号、订票酒店预订这些不同的服务集群之间通过 SVC 就是那个 DNS 进行这个服务发现,然后可以进行一个连通。
Pod状态
PRSFU:Pending、Running、Succeeded、Failed、Unknown
Pending:
API Server已经创建该Pod,且Pod内还有一个或多个容器的镜像没有创建,
包括正在下载镜像的过程。
Running:
Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动状态
或正在重启状态。
Succeeded:
Pod内所有容器均成功执行退出,且不重启。
Failed:
Pod内所有容器均已退出,但至少有一个容器退出为失败状态。
Unknown:
由于某种原因无法获取该Pod状态,可能由于网络通信不畅导致。
Running
该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
Pending
Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。创建pod的请求已经被k8s接受,但是容器并没有启动成功,可能处在:写数据到etcd,调度,pull镜像,启动容器这四个阶段中的任何一个阶段,pending伴随的事件通常会有:ADDED, Modified这两个事件的产生
Succeeded
Pod中的所有的容器已经正常的自行退出,并且k8s永远不会自动重启这些容器,一般会是在部署job的时候会出现。
Failed
Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
Unknown 出于某种原因,无法获得Pod的状态,通常是由于与Pod主机通信时出错。
docker运行状态 CRPSD
Created:容器已经被创建,容器所需的相关资源已经准备就绪,但容器中的程序还未处于运行状态。
Running:容器正在运行,也就是容器中的应用正在运行。
Paused:容器已暂停,表示容器中的所有程序都处于暂停(不是停止)状态。
Stopped:容器处于停止状态,占用的资源和沙盒环境都依然存在,只是容器中的应用程序均已停止。
Deleted:容器已删除,相关占用的资源及存储在 Docker 中的管理信息也都已释放和移除
docker容器无法启动,排查思路:定查日进进
1、定位:查看容器列表,查找容器(docker ps -a)
2、查看出现问题的容器或节点(docker inspect 容器名)
3、查看对应容器的日志(docker logs)
4、查看容器的进程(docker top 容器名)
5、进入容器内部查看问题(docker exec -it 容器名)
docker原理
Docker 利用 LXC 技术通过 GOLANG 开发的管理引擎,项目开源托管在 github 之上。
当然 Docker 利用了当前系统的很多底层概念,比如
通过 overlay 实现了 UFS,
通过 Bridge 实现容器间的数据通信,
通过 netfilter 实现了容器对外,以及外部访问容器的功能,
通过 chroot 进行容器内部的伪根,
通过 cgroup 实现了容器的资源限制
Kubernetes中创建一个Pod涉及多个组件之间联动,主要流程:
1、提交Pod的配置信息(可以是yaml文件定义的信息)到kube-apiserver。
2、收到指令后,通知给controller-manager创建资源对象。
3、通过api-server将pod的配置信息存储到ETCD数据中心。
4、Kube-scheduler检测到pod信息会开始调度预选,会先过滤掉不符合Pod资源配置要求的节点,然后开始调度调优,主要是挑选出更适合运行pod的节点,然后将pod的资源配置单发送到node节点上的kubelet组件上。
访问方式
pod
1)pod内部的不同容器间的访问:lo回环接口
2)不同pod间的访问
如果pod位于同一个物理节点:处于同一个广播域,通过docker0网桥转发即可
如果pod位于不同物理节点:基于Flannel提供网络,UDP数据报文二次封装
docker
1)访问自身:启动回环接口
2)外部网络访问容器:DNAT
3)容访问外部网络:SNAT
4)容器与容器间访问:网桥
Kubernetes是一个全新的基于容器技术的分布式系统支撑平台。是Google开源的容器集群管理系统(谷歌内部:Borg)。在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。并且具有完备的集群管理能力,多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、內建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制以及多粒度的资源配额管理能力。
Pod流程
Kubernetes中创建一个Pod涉及多个组件之间联动,主要流程如下:
1、客户端提交Pod的配置信息(可以是yaml文件定义的信息)到kube-apiserver。
2、Apiserver收到指令后,通知给controller-manager创建一个资源对象。
3、Controller-manager通过api-server将pod的配置信息存储到ETCD数据中心。
4、Kube-scheduler检测到pod信息会开始调度预选,会先过滤掉不符合Pod资源配置要求的节点,然后开始调度调优,主要是挑选出更适合运行pod的节点,然后将pod的资源配置单发送到node节点上的kubelet组件上。
Kubernetes和Docker的关系
Docker 提供容器的生命周期管理和Docker 镜像构建运行时容器。它的主要优点是将软件/应用程序运行所需的设置和依赖项打包到一个容器中,从而实现了可移植性等优点。Kubernetes 用于关联和编排在多个主机上运行的容器。
CPU 是什么型号,通过 lscpu 看它上面主要有频率赫制对吧。然后还有那个 node 节点 socket socket 上有 create 上有线程,一般就几线程,就是几个vcpu
w、uptime、top和htop
CPU 就绪状态和不可中断状态。io密集型的进程导致它的 CPU 负载高。可以通过看看它那个网络 IO 磁盘 IO 的, iowait命令看哪个进程它这个 IO 就比较高,是什么原因导致的?访问量激增,数据有问题,就是数据比较大?磁或者是磁盘那个读写速度慢。比如说这个磁盘比如说坏掉了,磁盘和正常的速度不一样,可以看通过看那个磁盘日志来去确定是不是这个磁盘出现了故障。
AlertManager告警管理器通过钉钉告警,请那个主键 webhook hook。
一般都七十、七十五告警阈值
根据业务定这个阈值
如果是那个比较重要的业务,而且访量比较高的业务,都会定低一点,就是重要的业务,定值主要还是根据他们一个经验值。
访问不了,主要就看哪个业务,在哪个集群,集群有没有问题, POD 进程起没起来?防火墙规则就等等。看那 kuer proxy kubelete 有没有问题?要根据这个根据实际情况去?分析定位
没有人动它。那个你说的防漏墙规则审池哪个防火墙。我说的但是这个比较少见,谁会去调这个防火墙。
kube-proxy 有过有过有有遇到过,这个容器挂掉了。挂掉了。自动重启的。
通过脚本用for循环,while循环比较好,cat一个文件,然后管道符给while 赋值给一个变量,然后底下对这个变量进行累加操作,然后求出一个值。
日志cat,然后grep截相应的字段筛选、sort排序、unique 统计它的次数,然后进行相关操作。比如说把它添加到 TCP wapper 里。
提供一个web界面,给用户提供访问码,提供一个外部界面的一个展示。是吧。然后你们的你说的你说那个 SVC 就微服务,它主要就是以一个 web 界面的一个展示为主。是吧展示。然后那就是平台的一个月入直接会达到大刀上面,然后就可以看见了。是这个意思吧。是。然后还有一些做那些订票的一些操作,可以通过这个 web连通后端数据库,通过 amama 做的读写分离, readis 做缓存。然后直接到数据库中间件的搭配
流程主要是开发,先把这个开发的就是升级包这边开发结束之后由进行测试。测试之后我们这边对它做一个镜像的就是升级封装。封装之后通过这个智能清单如果是上线的话,就是先测试,然后再上线,先进行那个灰度发布,金饰却部署,然后观察一段没有问题之后,我这边是逐渐切流加 25 50 100 逐步切流观察。
一个灰度发布的滚动更新上线,是由运维来做的。对,我这边做的
主要分为十大块,他第一个就是 API version 写的是那个调用的 API 接口版本号。然后第下面就是那个 kindle 写的是你这个资源对象的种类。还有没事对的,写元数据里面有 name speech 还有 name label 是还有像一些 no T 审就注释还有这个还有一个主要的是 spect 期望。如果你写的一个是 deployment 资源清单的话,期望里面会有这个副本数量。然后容器运行的容器包括音译音音译挂载目录这些。如果是 SV 系的话,你就可以选择那个号的类型,不是那个 IP 类型,包括这个 external I tunnel name plus IP node port 还有还有一个啥那个 LB 然后还有一些资源特殊的像 config map 这种也有的。
那这个调优主要是他那个连接时长,这这个我调整过,因为之前是服务器,后面有这个大量的 time 位上看那个进程状态。所以说我把这个连接时长调长一些,因为它这个短连接导致它那个出现大量的状态。三肢握手之四肢挥手之后有个 2 msl 这个状态值这个比较长。然后为了减少这个 time 位的时间,因为它占用端口,调过这个。
Redis 原理,我这个 Redis 主要一个是内关系型数据库,它是内存式数据库,它插取最主要的作用就是做缓存给后端的数据库做缓存。当我们插取 Redis 通过 Redis 一般是程序开发的,通过这个 Redis 查取一个数据的时候,如果我这个 Redis 中有这个数据,我就把这个数据返回给这个查询方。如果我没有这个数据,则向这个后端数据库进行查询。查询之后把这个数据写到内存中,再返回给那个数据查询。然后除此之外,它还有一个的过期时间。
B tree plus,
B +tree底层有一个链路、链表、链接可以通过,比如查这个字段儿跨字段,跨叶子节点,它可以通过这个链接方便查取到。
使用二叉树,它会有一个左倾或者是左倾右倾的问题。B加树是比较好的一种说法。我这个对这边了解确实不是很多
delete 与 truncate 应用区别:
1、删除整表和所有数据,delete不释放表所占用的空间
2、如果用户确定是 删除 整表的所有数据,那么使用 truncate table 速度更快
delete from table_name
delete from table_name;
删除信息:TRUNCATE
truncate table table_name
truncate table table_name;
主配置文件:/etc/my.cnf
数据目录:/var/lib/mysql
默认端口:3306
增:增加库:create database 库名;
create database 库名;
增加表:create table 表名 (x1 int(3));
create table table 表名(x1 int(3));
主键约束:
primary key(id);
primary key (id);
从表二数据添加到表一:
insert into 表一(x1)select x1 from 表二
insert into 表一 (x1) select x1 from 表二
给所有字段插入数据
insert into 表名 values(值1,值2.....)
insert into 表名 values(值1,值2…);
给必须字段插入数据
insert into 表名(字段1,字段2) values(值1,值2);
insert into 表名(字段1,字段2) values(值1,值2);
删:删除数据库:
drop database 库名;
drop database 库名;
删除表:
drop table 表名;
drop table 表名;
删除表中字段等于数值的记录(根据主键约束去删除数据)
delete from 表 where 字段=数值;
delete from 表 where 字段=数值;
改:修改某一字段中的某一数据
update 表名 set 字段1=数值1 where 字段2=数值2
update 表名 set 字段1=数值1 where 字段2=数值2;
修改某一字段
update 表名 set 字段1=数值1
update 表名 set 字段1=数值1
修改某一字段中的部分数据
update 表名 set 字段1=数值1 where 字段2 between 1 and 5;
update 表名 set 字段1=数值1 where 字段2 between 1 and 5;
修改表名
alter table 表1名 rename 表2名;
alter table 表1名 rename 表2名;
修改表字段结构
alter table 表1名 rename 表2名;
alter table 表1名 rename 表2名;
修改表字段结构
alter table 表 modify 字段;
alter table 表 modify 字段;
修改表字段名
alter table 表名 change 原字段名 新字段名;
alter table 表名 change 原字段名 新字段名;
表添加字段
alter table 表名 add 字段;
alter table 表名 add 字段;
表删除字段
alter table 表名 drop 字段;
alter table 表名 drop 字段;
查:查看数据库
show databases;
show databases;
查看数据表
show tables;
show tables;
查看表结构
describe 表名;
describe 表名;
查看表的内容
select * from username;
select * from username;
查看所有查看部分
select id from username;
select name from username;
select id,name from username;
select id from username;
select name from username;
select id,name from username;
给所有字段插入数据
语法:insert into 表名 values(值1,值2…);
insert into 表名 values(值1,值2....);
mysql> insert into domain_manager values(‘jimmy’,‘hongfu.com’,‘2021-7-7’,1);
#给必须字段插入数据
insert into 表名(字段1,字段2) values(值1,值2);
语法:insert into 表名(字段1,字段2) values(值1,值2);
mysql> insert into domain_manager(username,domain,active) values(‘tom’,‘jiayou.com’,1);
insert into domain_manager(username,domain,active) values('tom','jiayou.com',1);
修改所有记录
update domain_manager set active=0;
mysql> update domain_manager set active=0;
修改指定记录
update 表名 set 字段名=值 where 指定字段=指定值;
语法:update 表名 set 字段名=值 where 指定字段=指定值;
mysql> update domain_manager set active=1 where username=‘tom’;
update domain_manager set active=1 where username='tom';
删除所有记录
delete from 表名;
语法:delete from 表名;
mysql> delete from domain_manager;
删除指定记录
delete from 表名 where 指定字段=指定值;
语法:delete from 表名 where 指定字段=指定值;
delete from 表名 where
mysql> delete from domain_manager where username=‘tom’;
delete from domain_manager where username='tom';
多表级联
用共有的字段连接两张表,inner join两边都有记录、left join以主表记录为准、right join以副表记录为准
select * from 主表名 inner|left|right join 副表名 on 主表.字段=副表.字段;
语法:select *
from 主表名 inner|left|right join 副表名 on 主表.字段=副表.字段;
mysql> select *
from xinxi inner join paihangbang on xinxi.name=paihangbang.name;
mysql> select *
from xinxi left join paihangbang on xinxi.name=paihangbang.name;
mysql> select *
from xinxi right join paihangbang on xinxi.name=paihangbang.name;
select * from xinxi inner join paihangbang on xinxi.name=paihangbang.name;
select * from xinxi left join paihangbang on xinxi.name=paihangbang.name;
select * from xinxi right join paihangbang on xinxi.name=paihangbang.name;
排序;
1、单列排序
select * from test ORDER BY data_time;
SELECT *
FROM test1 ORDER BY date_time;
默认升序,降序后面接"DESC"即可。
2、多列排序
select * from test order by status,date_time desc;
SELECT *
FROM test1 ORDER BY status
, date_time DESC;
首先按status
字段排序,若status
相等,则按data_time排序。
3、自定义排序
select * from test order by field(status,3,2,4,1,5), date_time desc;
SELECT * FROM test ORDER BY FIELD(status
, 3, 2, 4, 1, 5), date_time DESC;
使用"FIELD()"函数,可指定顺序。
4、其他条件排序
先按大于等于当前时间升序,再按小于当前时间降序,支持分页。
select * from test order by date_time < now(),if(date_time<now(),0,date_time),date_time DESC;
SELECT * FROM test ORDER BY date_time < NOW(), IF(date_time < NOW(), 0, date_time), date_time DESC;
28.解释一下数据库的主从复制的原理(或者会问:怎么做的数据库的数据同步)
从服务器会向主服务器提交主机偏移位
从服务器的io线程会主动连接主服务器的io线程
主服务器会通过io线程将bin-log日志推送给从服务器,然后进入休眠状态
从服务器的io线程会唤醒sql线程,将bin-log日志转化为存储日志,进行数据同步,线程会进入休眠状态,等待下一次同步
29.数据库主从不同步的原因
网络延迟:数据库主从同步是基于binlog日志的异步复制,而binlog日志是通过网络进
行传输的,网络延迟大时,可能会造成主从不同步
主从数据库负载不一致:主从同步时,主数据库需要一个io线程,而从服务器需要一个
io线程和一个sql线程,当一台服务器负载过大时,会导致提供给线程的资源不足,主
从同步就无法完成
MySQL异常宕机
主从数据库设置的 max_allowed_packet 不一致,当主库执行一个较大的sql语句,从库
无法成功执行,导致数据不同步
可能在数据同步过程中发生了bug
MySQL主从数据库的版本不一致,如果主数据库的版本较高、从数据库版本较低,也会
导致同步不成功
30.解释一下数据库的读写分离
如果被这么问到,不仅要解释什么是读写分离,还要说出数据库主从复制的原理,切
忌只说读写分离,回答一定要完整
读写分离就是,主服务器负责写入数据,后台的一台或多台从服务器提供读操作
当主数据库写入数据时,从服务器会将数据同步过去
解释主从同步的原理
31.如果数据库主库宕机了,怎么切换到从库,如果有多个从库,其余的从库如何处理
登录所有的从库,执行show slave status\G;查看Pos信息,选择Pos值最大的从库作为
主库,执行stop slave命令
修改my.conf配置文件,开启bin-log日志,然后重启数据库,登录数据库执行restart
master,修改对应服务器IP信息
登录其他从库,执行change master,查看状态
优化mysql数据库性能的十个参数
(1)、max_connections:
允许的同时客户的数量。增加该值增加 mysqld 要求的文件描述符的数量。这个数字应该增加,否则,你将经常看到 too many connections 错误。 默认数值是100,我把它改为1024 。
(2)、record_buffer:
每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是131072(128k),我把它改为16773120 (16m)
(3)、key_buffer_size:
索引块是缓冲的并且被所有的线程共享。key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大,系统将开始换页并且真的变慢了。默认数值是8388600(8m),我的mysql主机有2gb内存,所以我把它改为 402649088(400mb)。
4)、back_log:
要求 mysql 能有的连接数量。当主要mysql线程在一个很短时间内得到非常多的连接请求,这就起作用,然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
back_log 值指出在mysql暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接,你需要增加它,换句话说,这值对到来的tcp/ip连接的侦听队列的大小。你的操作系统在这个队列大小上有它自己的限制。试图设定back_log高于你的操作系统的限制将是无效的。
当你观察你的主机进程列表,发现大量 264084 | unauthenticated user | xxx.xxx.xxx.xxx | null | connect | null | login | null 的待连接进程时,就要加大 back_log 的值了。默认数值是50,我把它改为500。
(5)、interactive_timeout:
服务器在关闭它前在一个交互连接上等待行动的秒数。一个交互的客户被定义为对 mysql_real_connect()使用 client_interactive 选项的客户。 默认数值是28800,我把它改为7200。
(6)、sort_buffer:
每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速order by或group by操作。默认数值是2097144(2m),我把它改为 16777208 (16m)。
(7)、table_cache:
为所有线程打开表的数量。增加该值能增加mysqld要求的文件描述符的数量。mysql对每个唯一打开的表需要2个文件描述符。默认数值是64,我把它改为512。
(8)、thread_cache_size:
可以复用的保存在中的线程的数量。如果有,新的线程从缓存中取得,当断开连接的时候如果有空间,客户的线置在缓存中。如果有很多新的线程,为了提高性能可以这个变量值。通过比较 connections 和 threads_created 状态的变量,可以看到这个变量的作用。我把它设置为 80。
(9)mysql的搜索功能
用mysql进行搜索,目的是能不分大小写,又能用中文进行搜索
只需起动mysqld时指定 --default-character-set=gb2312
(10)、wait_timeout:
服务器在关闭它之前在一个连接上等待行动的秒数。 默认数值是28800,我把它改为7200。
连接数 = ((核心数 * 2) + 有效磁盘数)
注:参数的调整可以通过修改 /etc/my.cnf 文件并重启 mysql 实现。这是一个比较谨慎的工作,上面的结果也仅仅是我的一些看法,你可以根据你自己主机的硬件情况(特别是内存大小)进一步修改。
RPC远程过程调用,就是通过远程调用的一种方式。NFS 服务RPC 端口映射。
NFS远程过程调用,RPC 先启动启动,NFS 注册端口通过 RPC 暴露端口,然后客户端也是要启用 RPC ,然后客户端当需要挂载的时候通过 RPC 就是客户端这边的 RPC 去沟通,服务器端 RPC 进行协商端口,把这个端口返回到客户端,然后再通过这个端口去进行挂载NFS 。
数据交互,怎么接收和解析这个请求
1.0 2.0 https
一、服务是否开启。二、 nmap 命令去扫描端口,看这个端口是否开启。如果端口开启了,可能是telnet连接一下,看是否有问题。进行排查:进程启动失败,或者端口开放失败,或者是通过那个防火墙 IP table 把这个端口禁用了,或者是 TCPwapper 也可以禁用它这个或者是访问控制列表,通过权限。大概就这些方面进行排查。
404 找不到网页,
一、权限问题,读取不到网页;
二、页面里面链接写错了;
三、后端挂载出现问题。
做缓存加速数据读取。
缓存MySQL 就是从 MySQL 中读取的数据,然后缓存到 Redis 中。然后客户端访问的时候查 Redis 有没有数据。如果没有数据,它会到 MySQL 读取数据,然后把 MySQL 数据写入 Redis 中,如果有数据,就直接从 Redis 进行读取数据。
缓存会淘汰,有一个过期时间,可以设置,这个具体的不在我这做。
几百的 QPS 为什么还会用redis。当时就这么设计的,因为这个也不是我设计的,可能是这面儿技术项目上问题。
有一次更新Nginx,更新之后页面儿配置更新之后实际上没有变动,然后排查原因,因为新手想通过重重启进程,结果重启进程也不行,结果最后发现是那个配置文件写错了。 应该是杠 T 检测一下。
中间件,ameba进行读写分离的,有时候这个方向会出现瓶颈,当时做的操作就是扩容。
资源是比较充足的,如果说是故障,主要的就是这边可能是有时候开发那边提交代码可能是有一些问题,比如升级的模块,它可能会有一些内存抖动、内存溢出这些问题。然后我们这边是进行监控,如果出现问题要及时反馈这个方向。
如果我们这边确定问题了,把这个如果是新更新的模块,我们肯定是根据先去跟他们开个会,紧急会议。如果是能快速定位到问题,那就尽快解决,重新进行升级。如果不能的话,就是进行版本回滚这个操作,然后再等他们慢慢解决。回滚是怎么回滚呢?你大概具体是实际的操作,回滚也比较简单。一个项目一个目录,然后目录不同版本就不同目录里面 kubectl apply 杠 F 指定上一个版本就可以了。
PV 和 PVC手工创建那个 PV 券,没有用自动分配的,因为也是比较小。通过 PV卷然后 PVC 绑定到里面。
clusterFS 不是我布的,不过了解,经常会出现它那个节点上损坏,就是磁盘损坏这个有问题。但是我们那面是热插拔的。磁盘热插拔,这个不是我负责,但是我知道它经常会有一些问题,然后磁盘热插拔换个磁盘就可以了,它也有那种故障转移的功能。
IO 问题,磁盘坏了它也会导致 IO 负载高。访问量大也会导致 IO IO 负载高。IO负载就是就绪状态和不可中断,中断状态的进程处理了。
AlertManager告警管理器通过钉钉告警,请那个主键 webhook hook。一般都七十、七十五。
业务,如果是那个比较重要的业务,而且访量比较高的业务,都会定低一点,就是重要的业务,定值主要还是根据他们一个经验值。
访问不了,主要就看哪个业务,在哪个集群,集群有没有问题, POD 进程起没起来?防火墙规则就等等。看那 kuer proxy kubelete 有没有问题?要根据这个根据实际情况去?分析定位。
sealos 非常简单。高可用的其实非常简单。然后其他的一些工具我也接触到,像 kubeadm 什么 minikube、二进制。 sealos这个是做高可用的,它主要基于kubeadm安装,通过kubernets的SVC调用apiserver,后端还有 ETCD 是自动组成一个集群,然后这controller-manager三个在一个节点上,它是通过 API 访问,以 SVC 用自己的 SVC 去代理自己。那个想法很巧妙。
属于一键安装,然后扩容。扩缩容也就是添加节点。就是要跟你说一下 seal OS join – master --node 要做加节点。因为我们都是我接触过 rk 还有库格电影,还有二进制的,还有库布 ASA 奥贝特,这些东西我都接着。你说这个我是头一次听过二进制。我发过失败的。刚刚开始值班。二进制的麻烦,很麻烦。
这证书更新证书我们自签的。他那个 99 年。也不会遇到这个事情。那你们多集群管理是用什么管理啊?
ansible集群的名 -m 模块名 -a 执行对象,在/etc/ansible/hosts配置文件添加主机组,也会生成一个默认全部的主机组all,包含配置文件内的所有主机,一共有2080个模块,常用的模块command模块、script模块、shell模块、copy模块和cron模块。
查看所有名称空间:
kubectl get ns
kubectl get pod --all-namespaces
kubectl get ns
kubectl get pod --all-namespaces
查看kube-system名称空间下所有node信息:
kubectl get node -n kube-system
kubectl get node -n kube-system
查看kubernetes集群信息:
kubectl cluster-info
kubectl cluster-info
给指定节点指定SSD标签:
kubectl label node 节点名称 disktype=SSD
kubectl label node 节点名称 disktype=SSD
给pod指定标签:
kubectl label pod pod名称 类型=标签名
kubectl label pod pod名称 类型=标签名
删除指定节点标签:
kubectl label node 节点名称 标签名-
kubectl label node 节点名称 标签名-
查看日志(前台输出信息):
kuubectl logs 指定资源对象 容器名称
kubectl logs 指定资源对象 容器名称
跟踪查看具体容器的日志:
kubectl log -f 指定pod -c 容器名称
kubectl log -f 指定pod -c 容器名称
查看pod具体信息:
kubectl get pod -o wide
kubectl get pod -o wide
登录到容器内:
kubectl exec -it 容器名称 --/bin/sh
kubectl exec -it 容器名称 – /bin/sh
查看指定资源对象:
kubectl get 资源对象
kubectl get 资源对象
查看资源对象详细信息:
kubectl get 资源对象 容器名称 -o yaml
kubectl get 资源对象 容器名称 -o yaml
查看pod内标签:
kubectl get pod --show-labels
kubectl get pod --show-labels
查看所有接入口和组(操作路径):
kubectl api-versions
kubectl api-versions
查询pods内kube-system信息:
kubectl get pods -n kube-system
kubectl get pods -n kube-system
创建资源对象:
kubectl create -f 资源清单名称
kubectl create 资源对象 自定义容器名 --image=使用镜像
kubectl create -f 资源清单名称
kubectl create 资源对象 自定义容器名 --image=使用镜像
删除资源对象:
kubectl delete 资源对象
kubectl delete 资源对象
查看对象解释:
kubectl explain 资源对象
kubectl explain 资源对象
查看指定对象详细描述信息:
kubectl describe 资源对象
kubectl describe 资源对象
进入pod内部:
kubectl exec -it pod名称 -c 容器名称 --/bin/sh
kubectl exec -it pod名称 -c 容器名称 --/bin/sh
检测node、pod资源使用情况:
kubectl top node/pod
kubectl top node/pod
临时修改资源:
kubectl edit 资源类型 资源池中资源
kubectl edit 资源类型 资源池中资源
查看并监控资源对象:
kubectl get 资源对象 -w
kubectl get 资源对象 -w
手动扩容缩Pod:
kubectl scale deployment pod名称 --replicas=扩容缩数
kubectl scale deployment pod名称 --replicas=扩容缩数
HPA自动扩容缩:
kubectl autoscale deployment 控制器名称 --cpu-percent=使用限制 --max=值 --min=值
kubectl autoscale deployment 控制器名称 --cpu-percent=使用限制 --max=值 --min=值
查看组件状态:
kubectl get cs
Kubectl get cs
查看k8s集群的所有信息:
kubectl get 对象类型 --all-namespaces
kubectl get 对象类型 --all-namespaces
假设有一个名称为nginx-deployment,目前pod数目为4,当cpu利用率达到70%时扩容到6个pod?
自动伸缩需要部署HPA(Heapster和metrics-server)
kubectl autoscale deployment nginx-deployment --cpu-percent=70 --max=6
kubectl autoscale deployment nginx-deployment --cpu-percent=70 --max=6
启动交互式容器:
docker run -it --name=容器名称 镜像名称:版本号 /bin/bash
docker run -it --name=容器名称 镜像名称:版本号 /bin/bash
启动守护式容器:
docker run -di --name=容器名称 镜像名称:版本号 /bin/bash
docker run -di --name=容器名称 镜像名称:版本号 /bin/bash
列出当前所有运行的容器:
docker ps -a
docker ps -a
启动、停止、重启容器:
docker start/stop/restart 容器名称
docker start/stop/restart 容器名称
强制停止容器:
docker kill 容器名称
docekr kill 容器名称
查看docker版本信息:
docker info
docker info
docker镜像仓库查询:
docker search 镜像名称
docker search 镜像名称
镜像下载:
docker pull
docker pull 镜像名称
查看已经下载镜像:
docker images
docker images
镜像删除:
docker rmi -f 镜像名称
docker rmi -f 镜像名称
导出镜像文件:
docker save -o 自定义名称.tar 镜像:版本号
docker save -o 自定义名称.tar 镜像:版本号
导入镜像文件:
docker load -i 自定义名称.tar
docker load -i 自定义名称.tar
修改镜像名:
docker tag 旧名 新名
docker tag 旧名 新名
查看当前正在运行的镜像:
docker ps
docker ps
容器的创建并启动:
docker run --name 自定义名称 -c 镜像
docker run --name 自定义名称 -c 镜像
删除容器:
docker rm -f 容器名
docker rm -f 容器名
删除所有容器:
docker rm -f $(docker ps -aq)
docker rm -f $(docker ps -aq)
查看容器的详细信息(IP地址等):
docker inspect
docker inspect
查看前台输出信息(日志):
docker logs 容器名
docker logs 容器名
日志存放目录:
/var/lib/docker/container/容器ID/容器ID-json.log
/var/lib/docker/container/容器ID/容器ID-json.log
进入容器内部:
docker exec -it 容器名称 /bin/bash
docker exec -it 容器名称 /bin/bash
拷贝数据到容器内:
docker cp 源文件 容器名称:容器内目录
docker cp 源文件 容器名称:容器内目录
将文件从容器内拷贝出:
docker cp 容器名称:容器内目录 目标位置
docker cp 容器名称:容器内目录 目标位置
将当前dockerfile文件制作为镜像:
docker build -t 镜像名:版本号 . -f dockerfile文件
docker buid -t 镜像名:版本号 . -f dockerfile文件
查看所有容器所占用的系统资源:
docker stats 容器名称
docker stats 容器名称
Docker与k8s区别
Docker本身并不是容器,它是创建容器的工具,是应用容器引擎。
k8s基于容器的集群管理平台
Kubernetes
使用版本:1.15
最新稳定版本:1.18
最新版本:1.21
K8s组件:
api-server:集群资源访问入口
Etcd:分布式键值存储服务,存储整个集群状态
Kubectl:命令行管理工具
Kubelet:维护pod生命周期、voluem、网络
Kube-proxy:svc服务发现和负载均衡
Controller manager:控制器,副本创建、滚动更新、官方回滚
Scheduler:调度器,pod位于那个pod
Container runtime:管理镜像,真正负责pod运行、容器管理
K8s插件:
coreDNS:集群DNS
Dashbord:提供B/S访问体系
Ingress:七层负载
Federation:提供跨可用区集群
Promethues:监控
Pod
1、什么是Pod:
1)Pod是一组容器,有pause容器、主容器
2)pause容器:初始化网络栈,挂载存储卷
3)主容器:可以有多个,至少有一个
因为共用网络栈,注意主机名以及端口信息不能重复
pod访问方式
1)pod内部的不同容器间的访问:lo回环接口
2)不同pod间的访问
如果pod位于同一个物理节点:处于同一个广播域,通过docker0网桥转发即可
如果pod位于不同物理节点:基于Flannel提供网络,UDP数据报文二次封装
探测状态
①成功:容器通过了诊断
②失败:容器未通过诊断
③未知:诊断失败,因此不会采取任何行动
探测种类:
livenessProbe(存活探测):指示容器是否正在运行
readinessProbe(就绪探测):指示容器是否准备好服务请求
探测类型:
①ExecAction:在容器内执行指定命令。退出时返回码为 0 则认为诊断成功
②TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。端口打开,则诊断被认为是成功
③HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求。响应的状态码大于等于200 且小于 400,则诊断被认为是成功
note节点稳定,大量pod重启:镜像问题、代码逻辑问题
OOME频繁杀死容器
网络通信:
Flannel:让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,而且它还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内
etcd与Flannel之间的关系
1)存储管理Flannel可分配的IP地址段资源
2)监控ETCD中每个Pod的实际地址,并在内存中建立维护Pod节点路由表
flannel模式:UDP
VXLAN
host-gw
K8s资源
基础资源:pod
控制器:rc、rs、deployment、daemonset、statfulset、job、cron job
服务发现与负载均衡:svc、ingress
存储:configmap、volume、pv、Local Volume、Storage Class
安全:secret、service account、RBAC、Network Policy、kubernetes-network-policy-recipes、Security Context
集群级别资源:Namespace、Node、ClusterRole、ClusterRoleBinding
元数据:hpa
API扩展:应用扩展定义自定义API对象
Svc类型
1、ClusterIp:默认类型,自动分配一个仅集群内部可以访问的虚拟IP
2、NodePort:在ClusterIP基础上给每台机器上绑定一个端口(30000+),这样就可以通过NodePort来访问pod中的服务(外部访问)
3、LoadBalancer:在NodePort的基础上,借助LAAS(负载均衡即服务)创建一个外部负载均衡器,并将请求转发到NodePort
4、ExternalName:把集群内部的pod定义到集群私有域名中,将外部域名引入到集群内部私有域名,形成相对稳定的域名
ingress
原理:
ingress是k8s中的一个api对象,一般用yaml配置。作用是定义请求如何转
发到service的规则,可以理解为配置模板
ingress-controller是具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发
Store 主要负责从kubernetes APIServer收集运行时信息,感知各类资源(如 ingress、service等)的变化,并及时将更新事件消息(event)写入一个环形管道
SyncQueue 协程定期扫描 syncQueue 队列,发现有任务就执行更新操作,即借助 Store 完成最新运行数据的拉取,然后根据一定的规则产生新的 nginx 配置,(有些更新必须 reload,就本地写入新配置,执行 reload),然后执行动态更新操作,即构造 POST 数据,向本地 Nginx Lua 服务模块发送 post 请求,实现配置更新
NginxController作为中间的联系者,监听updateChannel,一旦收到配置更新事件,就向同步队列syncQueue里写入一个更新请求
如何使用
Nginx Ingress Controller 本质上就是一个 Nginx,只不过它能根据 Ingress 资源的定义动态生成 Nginx 的配置文件,然后动态 Reload
要使用 Ingress,得先部署 Ingress Controller 实体(相当于前端 Nginx),然后再创建 Ingress ,ingress中自定义规则,规则就是写明了哪个域名对应哪个service,Ingress Controller 部署好后会动态检测 Ingress 的创建情况生成相应配置,再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中
高可用类型
Sealos
每台node节点上安装nginx,nginx通过内部的负载均衡将node节点上需要访问master
etcd高可用(集群高可用)
etcd官方给的部署模式是奇数个(大于等于3)就好了,推荐部署5个节点,这就不得不提etcd的选主协议算法Raft
普罗米修斯组件
1)Prometheus:服务器端(本质为时序数据库)
2)NodeExporter:收集数据端(本质为web服务器)
3)Grafana:开源软件,用于图形展示
4)alertmanager:控制管理器,用于报警
5)PrometheusOperator:自定义对象,是一个系统监测和警报工具箱,用来存储监控数据
其他组件
1)MetricServer:kubernetes集群资源使用情况的聚合器(对接服务接口)
2)KubeStateMetrics:收集kubernetes集群内资源对象数据,制定告警规则
EFK部署
Elasticsearch:搜索引擎(搜索原理:切片)
Elasticsearch角色分类:client:访问数据(deployment控制器)
Master:检索数据,负责索引(statefulset控制器)
Data:存储数据(statefulset控制器)
Fluentd:日志收集、切片、检索并推送到Elasticsearch服务器(每个节点有且只有一个Fluentd)
Kibana:数据检索
注:Elasticsearch与Kibana版本需要一致
helm
什么是Helm:让K8s的应用管理可配置,能动态生成。通过动态生成K8s资源清单文件。然后调用Kubectl自动执行K8s资源部署
2、Helm官网:helm.sh
3、Chart:软件安装包(镜像)
4、release:chart运行后生成release(容器)
5、helm原理图
1)V2版:Helm客户端通过grpc协议访问Tiller服务器,Tiller调用api server接口实现数据上传
2)V3版:helm客户端直接调用api server接口实现数据上传
Helm需要和dashborad联合使用
helm下的文件:
.Values.*
:从value.yaml文件中读取
.Release.*
:从运行Release的元数据读取
.Template.*
.Chart.*
:从Chart.yaml文件中读取
.Files.*
.Capabilities.*
k8s排错思路
1、查看node节点状态:kubectl get node 是否为ready
是:使用kubectl describe 节点名称 查看资源使用率
否:使用kubectl get node -o wide 查看对应节点后登陆对应节点查看节点中的情况
2、查看集群组件状态是否为healthy
否:使用kubectl get node -o wide 查看对应节点后登陆对应节点查看节点中的情况
3、查看pod状态是否为running
否:使用kubectl describe pod pod名称 查看详细信息
Dokcer运行原理
Docker是一个Client-Server结构的系统,Docker守护进程(Docker daemon)运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器
什么是docker?
Docker是基于LXC技术,底层采用golang语言编写,基于http2.0协议开源在github上的管理引擎。镜像使用UFS技术做多层级构建,并可将镜像上传保存至镜像仓库,默认使用网桥进行数据间的转发,通过防火墙规则实现内部以及外部网络的访问,通过“卷”保证数据的持久化存储,使用namespeace做资源的虚拟化,使用Cgroup做资源限制
commit与dockerfile区别:
Commit:
优点:简单,所见即所得(适用于应用程序部署较为困难的)
缺点:功能性缺失(元数据级别)
重用性差(存储空间、过程)
Dcokerfile:
优点:功能性完整
重用性高(存储空间、过程):考虑重用是否错误
缺点:类似于脚本编写
如何修改Docker日志默认存储路径:
默认存储路径:/var/lib/docker/container/容器ID/容器ID-json.log
修改:vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --graph 指定日志存放路径
Docker镜像优化方法
基础镜像小,层级尽量少,去除不必要,复用镜像层,分阶段构建
镜像下载
IfNotPresent(镜像下载策略):
Always:每次出错都重新下载镜像(默认)
Never:仅使用本地镜像
ifNotPresent:如果本地有使用本地镜像,本地没有下载镜像
Docker访问方式
1)访问自身:启动回环接口
2)外部网络访问容器:DNAT
3)容访问外部网络:SNAT
4)容器与容器间访问:网桥
Docker的网段(Docker0网桥)需要修改这个网段在哪里修改?
Docker的daemon.json文件作用
docker安装后默认没有daemon.json这个配置文件,需要进行手动创建
配置文件的默认路径:/etc/docker/daemon.json
docker版本高于1.12.6生效(不包括1.12.6版本)
设定容器DNS的地址,在容器的 /etc/resolv.conf文件中可查看
配置docker的私库地址
Docker守护进程的PID文件
镜像加速的地址,增加后在 docker info中可查看
内存资源限制
使用cgroups做资源限制
1、Docker 限制可以从 Memory、CPU、Block I/O 三个方面
2、OOME:Out Of Memory Exception
1)一旦发生OOME,任何进程都有可能被杀死
2)Docker调整了docker daemon的OOM优先级,以免被内核关闭
docker运行状态CRPSD
Created:容器已经被创建,容器所需的相关资源已经准备就绪,但容器中的程序还未处于运行状态。
Running:容器正在运行,也就是容器中的应用正在运行。
Paused:容器已暂停,表示容器中的所有程序都处于暂停(不是停止)状态。
Stopped:容器处于停止状态,占用的资源和沙盒环境都依然存在,只是容器中的应用程序均已停止。
Deleted:容器已删除,相关占用的资源及存储在 Docker 中的管理信息也都已释放和移除
docker容器无法启动,排查思路
1、定位:查看容器列表,查找容器(docker ps -a)
2、查看出现问题的容器或节点(docker inspect 容器名)
3、查看对应容器的日志(docker logs)
4、查看容器的进程(docker top 容器名)
5、进入容器内部查看问题(docker exec -it 容器名)