title: 面试汇总 #标题tags: 面试 #标签
date: 2020-01-22
categories: linux大杂烩 # 分类

总结面试遇到的问题。

反向代理

nginx优化做过哪些?

答:可以从nginx服务和系统内核两个方面着手优化。

nginx服务本身的优化如下:

  • 开启stub-status状态统计页;
  • gzip、br、defalte压缩功能;
  • 配置静态缓存,并通过ngx_cache_purge模块来手动清理缓存;
  • 通过worker_processes配置项调整nginx运行工作进程个数,该值一般为cpu的核心数(最多设置为“8”,8个以上的话性能就不会再提升了,而且稳定性变得更低)。
  • 通过worker_cpu_affinity配置项设置cpu亲和力,上家公司设置的值是auto。
  • 通过worker_rlimit_nofile配置项设置nginx最多可以打开的文件数。
  • 通过配置worker_connections来指定单个worker进程允许客户端的最大连接,worker_processes X work_connection = 最大并发量。
  • 配置防盗链 系统内核方面的优化如下:
  • 主要针对time-wait进行优化,比如开启它的快速回收、允许time-wait去处理新的请求。

lvs的有哪几种工作模式,工作原理是什么?

答:TUN、DR、NAT。

具体工作原理如下:

  • NAT模式:类似于防火墙的私有网络结构,负载调度器作为所有服务器节点的网关,即作为客户机的访问入口,也是各节点回应客户机的访问出口。服务器节点使用私有IP地址,与负载调度器位于同一个物理网络,安全性要优于其他两种方式,但负载调度器的压力较大。
  • TUN模式:采用开放式的网络结构,负载调度器仅作为客户机的访问入口,各节点通过各自的Internet连接直接回应客户机,而不再经过负载调度器,服务器节点分散在互联网中的不同位置,具有独立的公网IP地址,通过专用IP隧道与负载调度器相互通信。
  • DR模式:采用半开放的网络结构,与TUN模式的结构类似,但各节点不是分散在各地的,而是与调度器位于同一个物理网络,负载调度器与各节点服务器通过本地网络连接,不需要建立专用的IP隧道。

lvs的调度算法:rr(轮询)、wrr(加权轮询)、lc(最少连接)、wlc(加权最少连接)。

MySQL

MySQL主从复制的原理?

答:master开启bin-long日志记录,增删改的操作都会记录到二进制日志,slave开启两个线程,sql-running和IO-running,IO-running去同步master的bin-long日志,然后sql-running将同步过来的二进制日志转换为sql语句,写入到salve本身的数据库中。这就是一个完整的主从复制原理。

MySQL的存储引擎有哪些?

答:通过show engines指令可以查看到MySQL支持的引擎,在mysql 5.7.24中支持的存储引擎有9个,分别是:innodb、csv、myisam、blackhole、PERFORMANCE_SCHEMA、MRG_MYISAM、ARCHIVE、MEMORY、FEDERATED。

可以通过指令show variables like "default_storage_engine";指令来查看数据库默认的存储引擎。

mysql 5.5以后,innodb作为默认的存储引擎。

Innodb存储引擎

Innodb支持事务(ACID:原子性、一致性、隔离性、持久性),支持行锁定和外键。

Innodb作为默认的存储引擎,主要特性如下:

  • 支持事务;
  • 灾难恢复性好;
  • 支持热备份;
  • 为处理巨大数据量的最大性能设计;
  • 实现了缓冲管理,不仅能缓冲索引也能缓冲数据,并且会自动创建散列索引以加快数据的获取;
  • 支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,Innodb会为每一行生成一个6B的ROWID,并以此作为主键。
  • 被用在众多需要高性能的大性数据库站点上。

myisam存储引擎

myisam拥有较高的插入、查询速度,但不支持事务,在mysql 5.5之前,myisam是默认的存储引擎。

myisam主要特性如下:

  • 不支持事务。
  • 使用表级锁,并发性差。
  • 主机宕机后,myisam表容易损坏,灾难恢复性不佳。
  • 可以配置锁,实现操作系统下的复制备份、迁移。
  • 只缓存索引,数据的缓存是利用操作系统缓冲区来实现的,可能引发过多的系统调用且效率不佳。
  • 数据紧凑存储,因此可获得更小的索引和更快的全表扫描性能。
  • 可以把数据文件和索引文件放在不同目录。

使用 MyISAM 引擎创建数据库,将产生3个文件。文件的名字以表的名字开始,扩展名指出文件类型:frm 文件存储表定义,数据文件的扩展名为 .MYD(MYData),索引文件的扩展名是 .MYI(MYIndex)。

memory存储引擎

memory存储引擎将表中的数据存储在内存中,为查询和引用其他表数据提供快速访问。

memory主要特性如下:

  • 使用表级锁,虽然内存访问块,但如果频繁的读写,表级锁就会成为瓶颈。
  • 只支持固定大小的行,varchar类型的字段会存储为固定长度的char类型,浪费空间。
  • 不支持text、bolb字段,当有些查询需要使用到临时表(使用的也是memory存储引擎)时,如果表中有text、blob字段,那么会转换为基于磁盘的myisam表,严重降低性能。
  • 服务器重启后数据会丢失,复制维护时需要小心。

如何选择MySQL的存储引擎

功能 InnoDB MyISAM Memory
存储限制 64TB 256TB RAM
支持事务 Yes No No
支持全文索引 No Yes No
支持数索引 Yes Yes Yes
支持哈希索引 No No Yes
支持数据缓存 Yes No N/A
支持外键 Yes No No
  • 如果要提交、回滚和崩溃恢复能力的事务安全能力,并要求实现并发控制,innodb是个很好的选择。
  • 如果数据表主要用来插入和查询记录,则myisam引擎能提供较高的处理效率。
  • 如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以将数据保存在内存中的memory引擎,mysql中使用memory引擎作为临时表,存放查询的中间结果。
  • 如果只有insert和select操作,可以选择archive引擎,archive存储引擎支持高并发的插入操作,但是本身并不是事务安全的,archive引擎非常适合存储归档数据,如记录日志信息可以使用archive引擎。

使用哪种引擎要根据需求来选择,一个数据库中多个表可以使用不同存储引擎满足各种性能和实际需求,使用合适的存储引擎,将会提高整个数据库的性能。

MySQL支持哪几种索引

可以从三个角度来看。

从数据结构角度来看
  • B+树索引,
  • hash索引:

    • 仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询。
    • 其检索效率非常高,索引的检索可以一次定位,不像B-Tree索引需要从根节点到枝节点,最后才能访问到页节点,这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。
    • 只有memory存储引擎支持hash索引
  • fulltext索引(myisam和innodb存储引擎都支持)
  • R-tree索引(用于对GIS数据类型创建spatial索引)

从物理存储角度
  • 聚集索引(clustered index)
  • 非聚集索引(non-clustered index)

从逻辑角度
  • 主键索引:主键索引是一种特殊的唯一索引,不允许有空值;
  • 普通索引或者单列索引;
  • 多列索引(复合索引):指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用,使用复合索引时遵循最左前缀集合;
  • 唯一索引或者非唯一索引;
  • 空间索引:空间索引是对空间数据类型的字段建立的索引,mysql中的空间数据类型有4中,分别是GEOMETRY、POINT、LINESTRING、POLYGON。MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建

关于更多索引相关的文档请移步:MySQL索引类型详解

数据库有哪些语言?

答:DDL(数据定义语言):create、alter、drop、truncate、comment、rename。
DML(数据操纵语言):select、insert、update、delete、merge、call、explain plan、lock table
DCL(数据控制语言):grant、revoke
TCL(事务控制语言):savepoint、rollback、set transaction。

什么是主键?

主键是一列或一组列,可唯一标示表中的每一行,通常,为此目的创建一个id列。

什么是条款

sql子句是sql语句中定义明确的部分,通常用于根据预定义条件过滤结果,但并非总是如此,例如,order by是一个子句,但不过滤结果。

五个主要子句是top、where、order by、group by和having。

where子句和having子句有什么区别?

where和having都用于过滤我们设置的条件,where子句用于在分组之前过滤行(在group by子句之前),而having子句用于在分组之后过滤行。

有哪些不同类型的链接,并分别说明它们?

面试汇总 - 图1

有以下四种不同类型的联接:

  • 内部联接:返回两个表中具有匹配值的记录;
  • 左联接:返回左表中的所有记录以及右表中的匹配记录;
  • 右联接:从右表返回所有记录,并从左表返回匹配的记录;
  • 完全联接:当左表或右表存在匹配项时,返回所有记录。

两者之间的联系:
视图是基本表上建立的表,它的结构和内容都来自于基本表,它依赖基本表存在而存在,一个视图可以对应一个基本表,也可以对应多个基本表,视图是基本的抽象和逻辑意义上建立的关系。

什么是子查询?

子查询是另一个sql查询中的查询,用于返回将在主查询中用作进一步限制要检索的而数据的条件和数据。

有以下两种类型的子查询:

  • 关联子查询:关联子查询不能独立于外部查询进行评估,因为子查询使用父语句的值。
  • 不相关的子查询,不相关的子查询可被视为独立查询,并且子查询的输出将替换为主查询中。

MySQL单库最多可以有多少个表?单表最多可以有多少个字段?多少个索引?

在msyql中,单库中最多可以创建20亿个表,一个表允许定义1024列,每行的最大长度为8092字节。单表最多可以有16个索引。

union和join有什么区别

两者都是用于将来自一个或多个表的数据合并为一个结果,区别在于join语句将不同表的列合并为一个结果,而union语句将不同表的行为合并为一个结果。

delete和truncate语句有什么区别?

delete用于从表中删除一个或多个行,可以在使用delete语句后回滚数据。
truncate用于删除表中的所有行,并且执行后不能回滚数据。

什么是视图?

视图也是一个表,它是另一个表或多个表上查询的存储结果集,用户可以像其他表一样从中查询。

视图和表的区别?

  • 视图是已经编译好的SQL语句,是基于SQL语句的结果集的可视化的表,而表不是;
  • 视图没有实际的物理记录,而表有;
  • 表是内容,视图是窗口;
  • 表和视图虽然都占用物理空间,但是视图只是逻辑概念存在,而表可以及时对数据进行修改,但是视图只能用创建语句来修改 ;
  • 视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL 语句的集合。从安全角度来说,视图可以防止用户接触数据表,因而不知道表结构 ;
  • 表属于全局模式中的表,是实表。而视图属于局部模式的表,是虚表;
  • 视图的建立和删除只影响视图本身,而不影响对应表的基本表。

memcached和redis

redis的持久化方式有哪些?它们有什么区别?

答:RDB和AOF。

  • RDB:原理是将Redis在内存中的数据库定时记录dump到磁盘上的RDB持久化。
  • AOF:将Redis的操作日志以追加的方式写入文件。

区别如下: RDB:

  • 只包含一个文件,有利于文件备份;
  • 灾难恢复比aof持久化要快;
  • 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
    相比较AOF机制,如果数据集过大,RDB的启动效率会更高。
  • 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集比较大时,可能会导致整个服务停止几百毫秒,甚至是1秒钟。

AOF:

  • 可以保证数据的高可用性;
  • 写入过程中及时出现宕机现象,也不会破坏日志文件中已经存在的内容,如果在写入过程中宕机,重启Redis后可以通过redis-check-aof工具来解决;
  • 如果日志过大,Redis可以自动启用rewrite机制,生成新的文件存储aof日志;
  • 该机制可以带来更高的数据安全性,及数据持久性。Redis中提供了三种同步策略,即每秒同步、每修改同步和不同步。
  • 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB在恢复大数据集时的速度比AOF的恢复速度要快;
  • 根据同步策略的不同,AOF在运行效率上往往会慢于RDM,总之,每秒同步策略的效率是比较高的。

如果RDB和AOF同时存在,则优先选择AOF方式。

memcache和redis有什么区别?

答:

基本上有以下三点:

  • redis支持更丰富的数据类型,如list、set、zset、hash等,而memcached仅支持key-value。
  • redis支持数据持久化,memcached不支持。
  • memcache是多线程非阻塞IO复用的网络模型,分为监听主线程和worker子线程;redis使用单线程。

k8s

k8s中的pod有几种状态?

答:Pending、Running、Succeeded、Failed、Unknown、evicted、PodScheduled、initialized、ready、Unschedulable、Terminating。

  • Pending:创建pod的请求已经被k8s接受,但是容器并没有启动成功,可能处于:写数据到etcd,调度、pull镜像,启动容器这四个阶段中的任何一个阶段,pending伴随的事件通常会有:ADDED、Modified这两个事件。
  • Running:pod已经绑定到node节点,并且所有的容器已经启动成功,或者至少有一个容器在运行,或者在重启中。
  • succeeded:pod中的所有的容器已经正常的自动退出,并且k8s永远不会自动启动这些容器,一般会是在部署job的时候会出现。
  • failed:pod中的所有容器已经终止,并且至少有一个容器已经终止失败(状态码非0退出或被系统停止)。
  • Unknown:由于某种原因,API无法获取pod的状态,通常是由于与pod的主机通信错误。
  • eviction:驱赶的意思,当节点出现异常,k8s会有对应的驱逐机制驱逐该节点上的pod,多见于资源不足时导致的驱赶。
  • PodScheduled:pod正处于调度中,刚开始调度的时候,host IP还没绑定上,持续调度后,有合适的节点就会绑定hostip,然后更新etcd数据。
  • initialized:pod中的所有初始化容器已经启动完毕。
  • Ready:pod中的容器可以提供服务了。
  • Unschedulable:pod不能被调度,没有合适的节点。
  • Terminating:pod被删除,处于优雅退出阶段。

zabbix

关于zabbix的自动发现和自动注册分别是什么?如何选择?

自动发现

由服务端发起,zabbix server开启发现进程,定时扫描局域网中IP服务器、设备。

但是需要提前指定要扫描的IP范围段,并且自动发现会给zabbix server造成很大的负载,要扫描的字段越多,负载越大。因此不太建议使用自动发现。

自动注册

由客户端主动发起,客户端必须安装并启动agentd,否则无法被自动注册添加至主机列表。大多数工作由agent端来完成,所以zabbix server的负载会低很多,并且无需提前设置agentd的IP范围,在阿里云上非常适合使用此模式。

zabbix的主动模式与被动模式

默认情况下,zabbix server会直接去每个agent上抓取数据,这对于zabbix agent来说,是被动模式,也是默认的一种获取数据的方式,但是,当zabbix server监控主机数量过多的时候,由zabbix server端去抓取agent上的数据,zabbix server会出现严重的性能问题,主要表现如下:

  • web操作很卡,容易出现502错误;
  • 监控图形中图层断裂;
  • 监控告警不及时;

所以下面主要从两个方面进行优化,分别是:

  • 通过部署多个zabbix proxy模式做分布式监控(需要增加服务器节点,主机量不是特别大的话,不建议这么做)
  • 调整zabbix-agentd为主动模式(把压力给到各个被监控节点上,以减轻zabbix server的压力)

zabbix agentd主动模式的含义是agentd端主动汇报自己收集到的数据给zabbix server,这样,zabbix server就会空闲很多。

下面写一下如何调整zabbix agentd为主动模式

zabbix_agent端配置

修改zabbix_agentd.conf配置文件,主要是如下三个参数:

  1. ServerActive=192.168.20.8 # 指定agentd收集的数据发送到哪里
  2. Hostname=node01 # hostname必须要和zabbix web端添加主机时的主机名对应,这样 zabbix server端接受数据后才能找到对应关系。
  3. StartAgents=1 # 该值默认为3,要关闭被动模式的话,直接修改为0即可
  4. # 关闭被动模式后,agent端的10050端口也关闭了,这里为了兼容被动模式,没有把startagents设为0
  5. # 如果一开始就是使用主动模式的话,建议把startagents设为0,关闭被动模式。

zabbix server端配置
StartPollers=5     # 把这个zabbix server主动收集数据进程减少一些
StartTrappers=200      # 把这个负责处理agentd推送过来的数据的进程开大一些。