面试题

## nginx ### nginx和apache的区别 ``` Nginx 轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源 抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比apache 高很多, 而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而apache 在 PHP 处理慢或者前端 压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。 nginx 处理静态文件好,静态处理性能比 apache 高三倍以上 nginx 的设计高度模块化,编写模块相对简单 nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题, apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃 nginx 作为负载均衡服务器,支持 7 层负载均衡,七层负载可以有效的防止ddos攻击 nginx本身就是一个反向代理服务器,也可以左右邮件代理服务器来使用 Apache apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache apache 发展到现在,模块超多,基本想到的都可以找到,apache 更为成熟,少 bug ,nginx 的 bug 相对较多 apache 对PHP支持比较简单,nginx需要配合其他后端用 apache 在处理动态请求有优势,nginx在这方面是鸡肋,一般动态请求要apache去做,nginx适合静态和反向。 apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区 两者最核心的区别在于apache是同步多进程模型,一个连接对应一个进程,而 nginx是异步的,多个连接(万级别) 可以对应一个进程。 需要稳定用apache,需要高性能用nginx ``` ### Tomcat作为web的优缺点? ``` 缺点:tomcat 只能用做java服务器,处理静态请求的能力不如nginx和apache。高并发能力有限 优点:动态解析容器,处理动态请求,是编译JSP/Servlet的容器,轻量级 ``` ### nginx常用的命令 ``` 启动 nginx 。 停止 nginx -s stop 或 nginx -s quit 。 重载配置 ./sbin/nginx -s reload(平滑重启) 或 service nginx reload 。 重载指定配置文件 .nginx -c /usr/local/nginx/conf/nginx.conf 。 查看 nginx 版本 nginx -v 。 检查配置文件是否正确 nginx -t 。 显示帮助信息 nginx -h 。 ``` ### 什么是反向代理,什么是正向代理,以及区别? ``` 正向代理: 所谓的正向代理就是: 需要在用户端去配置的。配置完再去访问具体的服务,这叫正向代理,其实是"代理服务器"代理了"客户端",去和"目标服务器"进行交互。 正向代理的用途: 1.提高访问速度 2.隐藏客户真实IP 反向代理: 反向代理是在服务端的,不需要访问用户关心。用户访问服务器A, A服务器是代理服务器,将用户服务再转发到服务器B. 反向代理的作用: 1.缓存,将服务器的响应缓存在自己的内存中,减少服务器的压力。 2.负载均衡,将用户请求分配给多个服务器。 3.访问控制 ``` ### nginx虚拟主机有哪些? ``` 基于域名的虚拟主机 基于端口的虚拟主机 基于IP的虚拟主机 ``` ### nginx怎么实现后端服务的健康检查 ``` 方式一,利用 nginx 自带模块 ngx_http_proxy_module 和 ngx_http_upstream_module 对后端节点做健康检查。 方式二,利用 nginx_upstream_check_module 模块对后端节点做健康检查。(推荐此方法) ``` ### nginx的优化你都做过哪些? ``` 1. worker_processes 8; #nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计为8)。 2. worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000; #为每个进程分配cpu,上例中将8 个进程分配到8 个cpu,当然可以写多个,或者将一个进程分配到多个cpu。 3. worker_rlimit_nofile 65535; #这个指令是指当一个nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx 进程数相除, #但是nginx 分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。 4. use epoll 5. worker_connections 65535 #每个进程允许的最多连接数, 理论上每台nginx 服务器的最大连接数为worker_processes*worker_connections。 6. keepalive_timeout 60; 7. client_header_buffer_size 4k; #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k 8. open_file_cache max=65535 inactive=60s; 这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致, inactive 是指经过多长时间文件没被请求后删除缓存。 9. open_file_cache_valid 80s; #这个是指多长时间检查一次缓存的有效信息。 10. open_file_cache_min_uses 1; open_file_cache 指令中的inactive 参数时间内文件的最少使用次数,如果超过这个数字,文件 描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive 时间内一次没被使用,它将被移除。 ``` ### nginx的session不同步怎么办 ``` 我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该 请求通过哈希算法,自动定位到该服务器。即每个访客固定访问一个后端服务器,可以解决session的问题。 其他办法:那就是用spring_session+redis,把session放到缓存中实现session共享。 ``` ### 访问一个网站的流程 ``` 用户输入网站按回车, 查找本地缓存,如果有就打开页面,如果没有,利用DNS做域名解析,递归查询, 一级一级的向上提交查询请求,知道查询到为止,HOSTS表--> 本地DNS -->上层DNS(包括根DNS) 经过了DNS解析,知道了网站的IP地址,然后建立tcp三次握手; 建立请求后,发送请求报文,默认请求 的是index.html,传送完毕,断开连接 ``` ### 三次握手 ``` 第一次握手 1:客户端先向服务端发起一次询问建立连接的请求,并随机生成一个值作为标识 第二次握手 2:服务端向客户端先回应第一个标识,再重新发一个确认标识 第三次握手 3:客户端确认标识,建立连接,开始传输数据 ``` ### 四次挥手 ``` 四次挥手 ---> 断开连接 第一次挥手 客户端向服务端发起请求断开连接的请求 第二次挥手 服务端向客户端确认请求 第三次挥手 服务端向客户端发起断开连接请求 第四次挥手 客户端向服务端确认断开请求 ``` ### 什么叫网站灰度发布? ``` 也叫金丝雀发布,AB test就是一种灰度发布方式,让一部用户继续用A,一部分用户开始用B 如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来 灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度 ``` ### 统计ip访问情况,要求分析nginx访问日志,找出访问页面数量在前十位的ip `cat access.log | awk '{print $1}' | uniq -c | sort -rn | head -10` ### 关于nginx access模块的面试题 编写一个Nginx的access模块,要求准许192.168.3.29/24的机器访问,准许10.1.20.6/16这个网段的所 有机器访问,准许34.26.157.0/24这个网段访问,除此之外的机器不准许访问。 ``` location / { access 192.168.3.29/24; access 10.1.20.6/16; access 34.26.157.0/24; deny all; } ``` ### nginx默认配置文件 在 nginx 的配置文件中,大概分为几个区域:events {}、http {}、和没有被 {}包裹的区域。而 http {} 中还有 server {},以及 server {} 中的 location {}。结构如下: ``` ... worker_processes 1; events { worker_connections 1024; } http { ... server { ... location { ... } } server { ... } } 没有被 {} 包裹的部分为全局配置,如 worker_processes 1; 设置工作进程(子进程)数为 1 events {} 为 nginx 连接配置的模块,如 worker_connections 1024; 设置每一个子进程最大允许连接 1024 个连接 http {} 为 nginx http 核心配置模块 server {} 为虚拟主机配置模块,包括监听端口、监听域名等 location {} URI 匹配 ``` ### 配置nginx防盗链 ``` Nginx的防盗链原理是加入location项,用正则表达式过渡图片类型文件,对于信任的网址可以正常使用, 对于不信任的网址则返回相应的错误图片,在源主机(bt.com)的配置文件中加入以下代码: vi /usr/local/nginx/conf/nginx.conf location ~*\.(jpg|gif|swf)$ { valid_referers none blocked *.test.com test.com; if ($invalid_referer) { rewrite ^/http://www.bt.com/error.png; } } 下面分析一下这段代码: ~*\.(jpg|gif|swf)$:这段正则表达式表示匹配不区分大小写,以.jpg或.gif或.swf结尾的文件。 valid_referers:设置信任的网站,可以正常使用图片。 none:浏览器中referer为空的情况,这就是直接在浏览器访问图片。 blocked:浏览器中referer不可空的情况,但是值被代理或防火墙删除了,这些值不以http://或https://开头。 后面的网站或者域名:referer中包含相关字符串的网址。 if语句:如果链接的来源域名不在valid_referers所列出的列表中,$invalid_referer为1,则执行后面的操作, 即进行重写或返回403页面。 把图片error.png放到源主机(bt.com)的工作目录下。 ls /usr/local/nginx/html 50x.html index.html logo.jpg error.png 这是重启服务器,重新访问http://www.test.com/index.html,显示的是被重写的图片。 ``` ## MySQL ### MySQL主从原理 ``` 主库会生成一个log dump线程,用来给从库i/o线程传binlog; 从库生成两个线程,一个I/O线程,一个SQL线程; i/o线程去请求主库的binlog,并将得到的binlog日志写到relay log(中继日志) 文件中; SQL线程,会读取relay log文件中的日志,并解析成具体操作,来实现主从的操作一致,而最终数据一致; ``` ![image.png](https://cos.easydoc.net/97954506/files/l1exe9zi.png) ### MySQL主从复制存在哪些问题? ``` mysql主从复制存在的问题:主库宕机后,数据可能丢失,从库只有一个sql Thread,主库写压力大,复制很可能延时。 解决方法: 用半同步复制解决数据丢失的问题,用并行复制解决从库复制延迟的问题。 ``` ### MySQL复制的方法 `级联复制:将主库的数据同步到级联库,然后级联库把自己的数据同步到从库上,这样可以减少主库的压力` ![image.png](https://cos.easydoc.net/97954506/files/l1ext9mt.png) ``` 半同步复制: 默认情况下,MySQL的复制功能是异步的,异步复制可以提供最佳的性能,主库把binlog日志发送给从库即结束,并 不验证从库是否接收完毕。这意味着当主库或从库发生故障时,有可能从库没有接收到主库发送过来的binlog日志, 这就会造成主库和从库的数据不一致,甚至在恢复时造成数据的丢失。在开启了半同步复制机制后,主库只有当有任意 一台从库已经接收到主库的数据后,告诉主库。主库收到从库同步成功的信息后,才继续后面的操作。 ``` ### MySQL的数据备份方式 ``` 工具一: MySQLdump工具备份 工具二: xtrabackup工具备份 备份分为:冷备,温备和热备 根据要备份的数据集合又分为:完全备份,增量备份和差异备份 需要备份的对象: -数据 -配置文件 -OS相关的配置文件 -代码: 存储过程,存储函数和处罚器 -复制相关的配置 -二进制日志 基于MySQLdump做备份策略: 周日做全备,备份同时滚动日志 周一到周六:备份二进制文件 恢复的时候: 完全备份+二进制文件中到此处的事件 数据量比较大的时候用xtrabackup,xtrabackup的特点: 1) 备份过程快速、可靠; 2) 备份过程不会打断正在执行的事务; 3) 能够基于压缩等功能节约磁盘空间和流量; 4) 自动实现备份检验; 5) 还原速度快; ``` ![image.png](https://cos.easydoc.net/97954506/files/l1ey0shr.png) ### 如何加强MySQL安全,请给出可行的具体措施? ``` 1.避免直接从互联网访问mysql数据库,确保特定主机才拥有访问权限。 2.定期备份数据库 3.禁用或限制远程访问 ,在my.cnf文件里设置bind-address指定ip 4.移除test数据库(默认匿名用户可以访问test数据库) 5.禁用local infile: 6.移除匿名账户和废弃的账户 7.限制mysql数据库用户的权限 8.移除和禁用.mysql_history文件 ``` ### Binlog工作模式有哪些?各什么特点,企业如何选择? ``` 1.row level行级模式 优点:记录数据详细(每行),主从一致 缺点:占用大量的磁盘空间,降低了磁盘的性能 2.statement level模式(默认) 优点:记录的简单,内容少 ,节约了IO,提高性能 缺点:导致主从不一致 3.MIXED混合模式 结合了statement和row模式的优点,会根据执行的每一条具体的SQL语句来区分对待记录的日志形式。 对于函数,触发器,存储过程会自动使用row level模式 企业场景选择: 1.互联网公司使用mysql的功能较少(不用存储过程、触发器、函数),选择默认的statement模式。 2.用到mysql的特殊功能(存储过程、触发器、函数)则选则MIXED模式 3.用到mysql的特殊功能(存储过程、触发器、函数),有希望数据最大化一致则选择row模式。 ``` ### 生产一主多从从库宕机,如何手工恢复? ``` 处理方法:重做slave 1. 停止slave 2. 导入备份数据 3. 配置master.info信息 4. 启动slave 5. 检查从库状态 ``` ### 网站打开慢,请给出排查方法,如是数据库慢导致,如何排查并解决,请分析并举例? ``` 1. 检查操作系统是否负载过高 2. 登陆mysql查看有哪些sql语句占用时间过长,show processlist; 3. 用explain查看消耗时间过长的SQL语句是否走了索引 4. 对SQL语句优化,建立索引 ``` ### 误执行drop数据,如何通过xtrabackup恢复? ``` 1. 关闭mysql服务 2. 移除mysql的data目录及数据 3. 将备份的数据恢复到mysql的data目录 4. 启动mysql服务 ``` ### 如何做主从数据一致性校验? `主从一致性校验有多种工具 例如checksum、mysqldiff、pt-table-checksum等` ### MySQL有多少日志 ``` 错误日志:记录出错信息,也记录一些警告信息或者正确的信息。 查询日志:记录所有对数据库请求的信息,不论这些请求是否得到了正确的执行。 慢查询日志:设置一个阈值,将运行时间超过该值的所有SQL语句都记录到慢查询的日志文件中。 二进制日志:记录对数据库执行更改的所有操作。 中继日志。 事务日志。 ``` ## Redis ### redis是单线程还是多线程? ``` 从redis4.0开始引入多线程,在 redis 6.0 之前,redis 的核心操作是单线程的。 因为 redis 是完全基于内存操作的,通常情况下CPU不会是redis的瓶颈,redis 的瓶颈最有可能是机器 内存的大小或者网络带宽。 ``` ### redis 的使用场景? `缓存、分布式锁、排行榜(zset)、计数(incrby)、消息队列(stream)、地理位置(geo)、访客统计(hyperloglog)` ### redis常见的数据结构 ``` 常见的5种: String:字符串,最基础的数据类型。 List:列表。 Hash:哈希对象。 Set:集合。 Sorted Set:有序集合,Set 的基础上加了个分值。 ``` ### redis持久化你们怎么做的? ``` redis持久化主要有两种 ROD和AOF,当先现在还有混合的,从reids4.0后引入的 RDB实现原理: RDB类似于快照,在某个时间点,将 Redis 在内存中的数据库状态(数据库的键值对等信息)保存到磁盘里面。 RDB 持久化功能生成的 RDB 文件是经过压缩的二进制文件。 RDB的优点: RDB文件是经过压缩的,占用空间很小,它保存了某个时间点的数据集,很适合做备份。 比如你可以在24小时内,每 个小时备份一次RDB文件,并且每个月的每一天备份一个RDB文件。 RDB非常适合用来做灾备恢复,可以加密后传送到数据中心 RDB可以最大化redis的性能 从恢复速度来看,RDB明显要比AOF要快 但是RDB也有一定的缺点: RDB在服务器故障的时候,容易造成数据损失。 我们通常设置每5分钟保存一次快照,这样数据丢失也只有5分钟的数据。 RDB保存时使用fork子进程数据的持久化,如果数据量大的话,会非常耗时,造成redis停止处理服务N毫秒。 AOF: 保存 Redis 服务器所执行的所有写操作命令来记录数据库状态,并在服务器启动时,通过重新执行这些 命令来还原数据集。 AOF默认是关闭的,可以通过appendonley yes 开启 AOF 持久化功能的实现可以分为三个步骤:命令追加、文件写入、文件同步。 AOF的优点: 1)AOF 比 RDB可靠。你可以设置不同的 fsync 策略:no、everysec 和 always。默认是 everysec,在 这种配置下,redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据。 2)AOF文件是一个纯追加的日志文件。即使日志因为某些原因而包含了未写入完整的命令(比如写入时 磁盘已满,写入中途停机等等), 我们也可以使用 redis-check-aof 工具也可以轻易地修复这种问题。 3)当 AOF文件太大时,Redis 会自动在后台进行重写:重写后的新 AOF 文件包含了恢复当前数据集所 需的最小命令集合。整个重写是绝对安全,因为重写是在一个新的文件上进行,同时 Redis 会继续往旧 的文件追加数据。当新文件重写完毕,Redis 会把新旧文件进行切换,然后开始把数据写到新文件上。 4) AOF 文件有序地保存了对数据库执行的所有写入操作以 Redis 协议的格式保存, 因此 AOF 文件的 内容非常容易被人读懂, 对文件进行分析也很轻松。如果你不小心执行了 FLUSHALL 命令把 所有数据刷掉了,但只要 AOF 文件没有被重写,那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。 AOF缺点: 1) 对于相同的数据集,AOF的文件一般会比RDB大 2) AOF所使用的fsync策略,备份速度也会比RDB曼 如何使用: 如果想尽量保证数据安全性, 你应该同时使用 RDB 和 AOF 持久化功能,同时可以开启混合持久化。 如果你的数据是可以丢失的,则可以关闭持久化功能,在这种情况下,Redis 的性能是最高的。 ``` ### 主从复制实现的原理 ``` Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况,为分担读压力,Redis支持主 从复制,Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全 量同步和增量同步 ``` ### redis哨兵模式原理 ``` 哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。 哨兵架构下client端第一次从 哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过 sentinel代理访问redis的主 节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且哨兵会早主从模式的从节点中重新选出 来一个新的master,并且将新的master信息通知给client端。 这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息。 ``` ![image.png](https://cos.easydoc.net/97954506/files/l1ez3mv0.png) ### redis有哪些架构模式? #### 单机版 ![image.png](https://cos.easydoc.net/97954506/files/l1ez5td7.png) `存在问题: 内容容量有限,处理能力有限,无法高可用` #### 主从复制 ![image.png](https://cos.easydoc.net/97954506/files/l1ez6mz2.png) ``` Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品, 其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器 (slave)。 只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一 直将发生在自己身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。 特点: 1、master/slave 角色 2、master/slave 数据相同 3、降低 master 读压力在转交从库 问题: 无法保证高可用,没有解决 master 写的压力 ``` #### 哨兵 ![image.png](https://cos.easydoc.net/97954506/files/l1eza1yl) ``` Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性: 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。 提醒(Notification):当被监控的某个 Redis 服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移操作。 特点: 1、保证高可用 2、监控各个节点 3、自动故障迁移 缺点:主从模式,切换需要时间丢数据,没有解决 master 写的压力 ``` #### 集群 ![image.png](https://cos.easydoc.net/97954506/files/l1ezovkz) ``` Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是 一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。 特点:1、多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins 2、支持失败节点自动删除 3、后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致 缺点:增加了新的 proxy,需要维护其高可用。 failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预 ``` ### 什么是缓存雪崩? ``` Redis挂掉了,请求全部走数据库。 对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。 缓存雪崩如果发生了,很可能就把我们的数据库搞垮,导致整个服务瘫痪! 解决方法:在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。 对于“Redis挂掉了,请求全部走数据库”这种情况,我们可以有以下的思路:事发前:实现Redis的高可用(主从架构 +Sentinel 或者Redis Cluster),尽量避免Redis挂掉这种情况发生。 事发中:万一Redis真的挂了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库 被干掉(起码能保证我们的服务还是能正常工作的) 事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。 ``` ### 缓存穿透 #### 什么是缓存穿透 ``` 缓存穿透是指查询一个一定不存在的数据。由于缓存不命中,并且出于容错考虑,如果从数据库查不到 数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,失去了缓存的意义 请求的数据在缓存大量不命中,导致请求走数据库。 缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪! ``` #### 如何解决缓存穿透 ``` 由于请求的参数是不合法的(每次都请求不存在的参数),于是我们可以使用布隆过滤器(BloomFilter)或者 压缩filter提前拦截,不合法就不让这个请求到数据库层! 当我们从数据库找不到的时候,我们也将这个空对象设置到缓存里边去。下次再请求的时候,就可以从缓存里边获取了。 这种情况我们一般会将空对象设置一个较短的过期时间。 ``` ### 缓存击穿 ``` 某一个热点key,在不停地扛着高并发,当这个热点key在失效的瞬间,持续的高并发访问就击破缓存直接访问数据库,导致数据库宕机。 设置热点数据"永不过期" 加上互斥锁:上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个 查询数据的请求上使用一个互斥锁来锁住它,其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然 后将数据放到redis缓存起来。后面的线程进来发现已经有缓存了,就直接走缓存 总结: 雪崩是大面积的key缓存失效;穿透是redis里不存在这个缓存key;击穿是redis某一个热点key突然失 效,最终的受害者都是数据库。 ``` ### redis为什么这么快 ``` 1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。 2、数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的; 3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗; 4、使用多路 I/O 复用模型,非阻塞 IO; 5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自 己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求 ``` ## mongoDB ### mongoDB是什么? ``` MongoDB是一个文档数据库,提供好的性能,领先的非关系型数据库。采用BSON存储文档数据。 BSON()是一种类json的一种二进制形式的存储格式,简称Binary JSON.相对于json多了date类型和二进制数组。 ``` ### mongodb的优势 ``` 面向文档的存储:以 JSON 格式的文档保存数据。 任何属性都可以建立索引。 复制以及高可扩展性。 自动分片。 丰富的查询功能。 快速的即时更新。 ``` ### mongodb使用场景 ``` 大数据 内容管理系统 移动端Apps 数据管理 ``` ## kafka ### kafka中的broker 是干什么的 ``` broker 是消息的代理,Producers往Brokers里面的指定Topic中写消息,Consumers从Brokers里面拉 取指定Topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站。 ``` ### kafka中的 zookeeper 起到什么作用,可以不用zookeeper么 `zookeeper 是一个分布式的协调组件,broker依然依赖于ZooKeeper,zookeeper 在kafka中还用来选举controller 和 检测broker是否存活等等` ### kafka 为什么那么快 ``` Cache Filesystem Cache PageCache 缓存 顺序写 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快。 Zero-copy 零拷技术减少拷贝次数 Batching of Messages 批量量处理。合并小的请求,然后以流的方式进行交互,直顶网络上限。 Pull 拉模式 使用拉模式进行消息的获取消费,与消费端处理能力相符。 ``` ### kafka follower如何与leader同步数据 ``` Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。完全同步复制要求All Alive Follower 都复制完,这条消息才会被认为commit,这种复制方式极大的影响了吞吐率。 而异步复制方式下,Follower异步的从Leader复制数据,数据只要被Leader写入log就被认为已经 commit,这种情况下,如果leader挂掉,会丢失数据,kafka使用ISR的方式很好的均衡了确保数据不丢 失以及吞吐率。Follower可以批量的从Leader复制数据,而且Leader充分利用磁盘顺序读以及send file(zero copy)机制,这样极大的提高复制性能,内部批量写磁盘,大幅减少了Follower与Leader的消 息量差。 ``` ### Kafka中的消息是否会丢失和重复消费? ``` 要确定Kafka的消息是否丢失或重复,从两个方面分析入手:消息发送和消息消费。 1、消息发送 Kafka消息发送有两种方式:同步(sync)和异步(async),默认是同步方式,可通过producer.type属性进行 配置。Kafka通过配置request.required.acks属性来确认消息的生产: 0---表示不进行消息接收是否成功的确认; 1---表示当Leader接收成功时确认; -1---表示Leader和Follower都接收成功时确认; (1)acks=0,不和Kafka集群进行消息接收确认,则当网络异常、缓冲区满了等情况时,消息可能丢失; (2)acks=1、同步模式下,只有Leader确认接收成功后但挂掉了,副本没有同步,数据可能丢失; 2、消息消费 Kafka消息消费有两个consumer接口,Low-level API和High-level API: Kafka消息发送有两种方式:同步和异步,默认是同步方式,可通过producer.type属性进行配置。 Kafka通过配置request.required.acks属性来确认消息的生产: Low-level API:消费者自己维护offset等值,可以实现对Kafka的完全控制; High-level API:封装了对parition和offset的管理,使用简单; 如果使用高级接口High-level API,可能存在一个问题就是当消息消费者从集群中把消息取出来、并提交 了新的消息offset值后,还没来得及消费就挂掉了,那么下次再消费时之前没消费成功的消息就“诡异”的消失了; 解决办法: 针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader和Follower之后再确认消息发送成功; 异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态; 针对消息重复:将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可 ``` ### 为什么Kafka不支持读写分离? ``` (1)数据一致性问题。 (2)延时问题。对延时敏感的应用而言,主写从读的功能并不太适用。 ``` ### 什么是消费者组? ``` 消费者组是 Kafka 独有的概念: 1、定义:即消费者组是 Kafka 提供的可扩展且具有容错性的消费者机制。 2、原理:在 Kafka 中,消费者组是一个由多个消费者实例构成的组。多个实例共同订阅若干个主题,实现共同消 费。同一个组下的每个实例都配置有 相同的组 ID,被分配不同的订阅分区。当某个实例挂掉的时候,其他实例会自 动地承担起 它负责消费的分区。 ``` ### kafka适用于哪些场景 ``` 1. 日志收集 2. 消息系统 3. 用户轨迹(记录浏览器用户或者app用户产生的各种记录,点击和搜索浏览等) 4. 记录运营监控数据 5. 实现流处理 ``` ### Kafka写入流程: ``` 1.producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader 2. producer 将消息发送给该 leader 3. leader 将消息写入本地 log 4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK 5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送 ACK ``` ![image.png](https://cos.easydoc.net/97954506/files/l1f1087z.png) ## Keepalived ### keepalived 是什么? ``` 广义上讲是高可用,狭义上讲是主机的冗余和管理 keepalived的核心功能是健康检查和失败切换。 健康检查就是采用tcp三次握手,http请求等方式对负载均衡器后面的实际的服务器(通常是承载真实业务的服务器)进行保活; 而失败切换主要是应用于配置了主备模式的负载均衡器,利用VRRP维持主备负载均衡器的心跳,当主负载均衡器出现 问题时,由备负载均衡器承载对应的业务,从而在最大限度上减少流量损失,并提供服务的稳定性 ``` ### 你是如何理解VRRP协议的 ```为什么使用VRRP? VRRP协议是一种容错的主备模式的协议,保证当主机的下一跳路由出现故障时,由另一台路由器来代替出现故障的路 由器进行工作,通过VRRP可以在网络发生故障时透明的进行设备切换而不影响主机之间的数据通信。 VRRP的三种状态: VRRP路由器在运行过程中有三种状态: 1. Initialize状态: 系统启动后就进入Initialize,此状态下路由器不对VRRP报文做任何处理; 2. Master状态; 3. Backup状态; 一般主路由器处于Master状态,备份路由器处于Backup状态。 ``` ### keepalived的工作原理? ``` Keepalived高可用对之间是通过 VRRP进行通信的, VRRP是通过竞选机制来确定主备的,主的优先级高于备,因 此,工作时主会优先获得所有的资源,备节点处于等待状态,当主宕机的时候,备节点就会接管主节点的资源,然后顶 替主节点对外提供服务在Keepalived服务对之间,只有作为主的服务器会一直发送 VRRP广播包,告诉备它还活着, 此时备不会抢占主,当主不可用时,即备监听不到主发送的广播包时,就会启动相关服务接管资源,保证业务的连续 性.接管速度最快 ``` ### 出现脑裂的原因 ```什么是脑裂? 在高可用系统中,当联系2个节点的“心跳线”断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。 由于相互失去了联系,都以为是对方出了故障。两个节点上的HA软件争抢“共享资源”、争起“应用服务”,就会发生严 重后果。共享资源被瓜分、两边“服务”都起不来了;或者两边“服务”都起来了,但同时读写“共享存储”,导致数据损坏 ``` ### 都有哪些原因导致脑裂? ``` 高可用服务器对之间心跳线链路发生故障,导致无法正常通信。。 因网卡及相关驱动坏了,ip配置及冲突问题(网卡直连) 因心跳线间连接的设备故障(网卡及交换机) 高可用服务器上开启了 iptables防火墙阻挡了心跳消息传输。 高可用服务器上心跳网卡地址等信息配置不正确,导致发送心跳失败 其他服务配置不当等原因,如心跳方式不同,心跳广插冲突、软件Bug等。 ``` ### 如何解决keepalived脑裂问题? ``` 在实际生产环境中,我们从以下方面防止脑裂: 同时使用串行电缆和以太网电缆连接、同时使用两条心跳线路,这样一条线路断了,另外一条还是 好的,依然能传送心跳消息 当检查脑裂时强行关闭一个心跳节点(这个功能需要特殊设备支持,如stonith、fence)相当于备 节点接收不到心跳消息,通过单独的线路发送关机命令关闭主节点的电源 做好对脑裂的监控报警 解决常见方案: 如果开启防火墙,一定要让心跳消息通过,一般通过允许IP段的形式解决 可以拉一条以太网网线或者串口线作为主被节点心跳线路的冗余 开发检测程序通过监控软件检测脑裂 ```