实习技术
# 负载均衡
# 什么是Nginx,为什么要用Nginx,Nginx有哪些优势
Nginx 是一个高性能的 HTTP 和反向代理 web 服务器。 Nginx 优势:
- 高并发连接:Nginx 能够支持数以万计的并发连接
- 配置使用简单 总结 就是性能高、稳定。
# 为什么Nginx支持这么高的并发
- 事件驱动,IO多路复用的
- 多线程
# 正向代理、反向代理区别
正向代理: 客户端的代理 反向代理: 服务端的代理
# Nginx是如何工作的
Nginx一般启动一个master进程 和 多个worker进程,master进程负责管理worker进程,worker进程负责处理客户端请求。
# Nginx 压缩了解吗,如何开启压缩?
gzip压缩文件,节省带宽,提高传输效率
# Nginx 有哪些负载均衡策略
- 轮询
- IP哈希
- 最小连接数
- 权重weight
# Nginx 限流
- 控制速率
- 控制并发连接数
# Kafka
# Kafka如何保证分区顺序的
kafka的分区 是 基于日志文件 实现的, 消息按照它们的到来顺序写入日志文件
# Kafka高性能的原因
- 零拷贝,不需要把数据从内核缓存区拷贝到用户空间
- 数据压缩,传输的数据进行压缩,减少传输数据量
- Kafka 异步操作
# Kafka高可用
- 副本 机制 : 分区有多个副本,分区分布在多个broker,某个broker故障,数据从其它broker恢复(数据备份)
- ISR 机制 : 维护一个 leader副本 同步分区副本的集合,只有ISR集合里的才可以被选为leader
- ACK 机制 : 对应分区 如果写入成功消息的话,就会发送ACK确认信息
# Kafka如何保证数据不丢失
- 持久化日志
- 副本机制
- ACK机制
# Kafka 消息投递有且仅有一次语义怎么实现
Kafka 通过事务机制可以实现对多个 topic 的多个 partition 的原子性的写入,即处于同一个事务内的所有消息,不管最终需要落地到哪个 topic 的哪个 partition, 最终结果都是要么全部写成功,要么全部写失败(Atomic multi-partition writes)。 就比如说,下单数据,支付成功 与 库存扣减消息,这两个消息应该是原子操作的,所以得放到事务里。
# Kafka消息消费的实时性如何
- Kafka消费方是 拉取的方式获取消息的,消费方可以控制消费速率
- Kakfa消费方消费消息的时候,其实可以并行的消费,加快消费速率
- Kafka 可以设置消费组, 数据量大的时候 可以消费组消费Topic不同分区的消息
# Kafka异步流程
在 Kafka 中,生产者发送消息的过程是异步的。这意味着当生产者调用 send
方法时,消息会被存储在一个缓冲区中,而不是立即发送到服务器。这样,生产者可以继续执行其他操作,而不必等待消息发送完成。
Kafka 生产者端有两个线程:主线程和 sender IO 线程。当用户调用 send
方法时,消息会被缓存到 RecordAccumulator 中,send
方法会立即返回,此时并不能确定消息是否真正发送到 broker。sender IO 线程会不断轮询 RecordAccumulator,满足一定条件后就进行真正的网络 IO 发送,使用的是异步非阻塞的 NIO。
当缓冲区中的消息数量达到一定阈值(由 batch.size
参数控制)或者距离上一次发送的时间超过一定间隔(由 linger.ms
参数控制)时,sender IO 线程会将缓冲区中的消息批量发送到服务器。此外,用户也可以调用 flush
方法来强制发送缓冲区中的所有消息。
总之,在 Kafka 中,生产者发送消息的过程是异步的。生产者将消息存储在缓冲区中,并由 sender IO 线程负责将缓冲区中的消息批量发送到服务器。这种方式可以提高生产者的吞吐量,并减少网络传输压力。
Kafka 消费者是基于拉模式的,即消费者主动向服务端发起请求来拉取消息。Kafka 中的消息消费是一个不断轮询的过程,消费者所要做的就是重复地调用 poll()
方法,而 poll()
方法返回的是所订阅主题(或分区)上的一组消息³。
Kafka 消费者并不是通过操作系统异步回调来实现异步消费消息的。相反,它是通过消费者自己不断轮询来获取新的消息。这种方式可以让消费者更好地控制消息获取的速度和时间,从而保证消息消费的实时性。
# kafka短轮询有哪些优化方法
- 并行消费
- 消费组消费
- Kafka 时间轮算法实现延迟队列
# Netty
# 线程模型
两组线程池:
- BossGroup线程池, 负责接收连接请求,并将请求封装进NioSocketChannel
- WorkerGroup线程池, 负责处理连接上的IO操作
# 线程之间的交互通信方式
- 共享内存
- 管道
- 消息队列
- RPC
- 线程同步机制
# 数据库的设计
# 如何设计一个高并发系统
高并发系统就是可以理解为设计一个系统,保证整体可用的同时,能够处理很高的并发用户请求,可以承受住很大的流量冲击。高并发 (opens new window)。
# 高并发常见的瓶颈问题
- 内存不足
- 磁盘空间不足
- 连接数不足
- 网络带宽不够
# 具体方案措施
- 分布式集群部署
- 微服务拆分
- 分库分表
- 池化技术
- 主从分离
- 使用缓存
- CDN,加速静态资源访问
- 消息队列,削锋,降级熔断,限流
- 异步
# 一些常规的优化
- 在一次连接上批量操作数据库
- 异步思想
- 空间换时间,可以用缓存
- 异步非阻塞思想,IO多路复用
- 资源访问由串行变为并行
- 锁的粒度避免过粗
- 加索引
- 优化SQL
- 避免大事务问题
- 优化深分页问题(标签记录法/延迟关联法)
- 压缩传输内容
- 海量数据处理,可以考虑用NoSQL,像ES之类
- JVM FULLGC,线程太多,IO太多资源没关闭
# 订单微服务
# 订单基本概念
# 订单中心
- 用户信息
- 订单信息
- 商品信息
- 物流信息
- 优惠促销信息
# 订单状态
- 创建订单
- 已付款
# 订单流程
订单生成 -> 支付订单 -> 卖家发货 -> 确认收货 -> 交易完成 下单, 下单数据校验,查询商品信息,优惠信息,运费信息等等, 库存锁定, 订单生成; 订单支付, 支付回调, 发送异步消息 同步物流 订单签收, 订单已完成
# 订单微服务整体架构
# 接口幂等
- Token
- 加锁
- 唯一性约束
- 防重表
- 全局请求唯一ID
# 如何保证秒杀的时候不超卖和出现重复消费的情况?
- 乐观锁或悲观锁来控制库存
- 使用消息队列来削峰,控制请求流量
- 限流
# 如何设计数据库连接池
数据库连接池是一种用于管理数据库连接的技术。它的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。例如,外部使用者可以通过 getConnection
方法获取连接,使用完毕后再通过 releaseConnection
方法将连接返回。此时,连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备¹。
数据库连接池的优势在于资源重用,由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。同时,在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。此外,数据库连接池还能提供更快的系统响应速度,因为在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
设计一个数据库连接池需要考虑许多因素,包括最大活跃数、最大空闲数、最大空闲时间等参数。
# 如何设计AOP
如果我要设计一个AOP(面向切面编程),我会考虑以下几个方面:
定义切面:首先,我需要定义切面,即确定哪些功能需要被抽离出来,以便在不影响核心业务逻辑的情况下进行维护和管理。例如,日志统计、打点上报、异常处理等功能都可以被抽离出来¹。
动态织入:其次,我需要考虑如何将这些功能动态织入到业务逻辑模块中。这可以通过预编译方式和运行期间动态代理实现³⁴。
切入点选择:接下来,我需要确定切入点,即选择哪些连接点需要被切入。这可以通过方法匹配表达式来实现²。
编程思路:最后,我需要考虑AOP的编程思路。由于AOP是针对方法调用进行编程的,因此我需要考虑如何捕获方法调用,并在代理过程中插入业务代码²。
总之,设计一个AOP需要考虑许多因素,包括切面定义、动态织入、切入点选择和编程思路等。
# 设计秒杀系统
- 高并发
- 高可用
- 数据一致性
- 安全性 对于一个秒杀系统,可以理解为很多请求去 抢100个名额, 首先 怎么保证服务器/数据库能承受住这么大的流量,
- 负载均衡、动静分离(Nginx)、CDN加速(就近获取内容)、流量削峰,限流,熔断降级,异步处理,缓存,主从分离,读写分离
- 库存预热,将库存信息需要从数据库中加载到缓存中,在缓存中查验 和 扣减库存 其次,就是如何让并发的请求正确消费这 100个名额
在分布式环境中,为了防止超卖,我们可以使用分布式锁。具体的实现方式有很多,这里以Redis为例来说明:
加锁:当一个请求需要修改库存时,首先尝试获取锁。在Redis中,我们可以使用
SETNX
命令来实现。SETNX
命令只有在key不存在时才会设置成功,因此可以保证只有一个请求能够获取到锁。为了防止死锁,我们还需要为锁设置一个过期时间,可以使用EXPIRE
命令来实现。设计key和value:在分布式锁中,key通常是需要保护的资源,例如商品的ID。value则可以是一个随机生成的唯一标识(例如UUID),用来标识锁的拥有者。
释放锁:当请求处理完毕后,需要释放锁。在Redis中,我们可以使用
DEL
命令来删除锁。但是为了防止误删其他请求的锁,我们需要先判断当前请求是否是锁的拥有者¹。这个操作需要是原子性的,因此我们可以使用Lua脚本来实现。
# Linux指令
# 常用的一些命令
在面试中,你可能会被问到以下一些常用的Linux命令:
文件管理:
ls
(显示目录中的文件及其属性信息)¹²,cp
(复制文件或目录)¹²,mkdir
(创建目录)¹²,mv
(移动或重命名文件)¹²,pwd
(显示当前工作目录的路径)¹²,tar
(压缩和解压缩文件)¹²。文档编辑:
cat
(在终端设备上显示文件内容)²,grep
(强大的文本搜索工具)²,tail
(查看文件尾部内容)²。系统管理:
find
(根据路径和条件搜索指定文件)²,rpm
(RPM软件包管理器)²,uname
(显示系统内核信息)²。磁盘管理:
df
(显示磁盘空间使用量情况)²,fdisk
(管理磁盘分区)²,mount
(将文件系统挂载到目录)²。文件传输:
tftp
(上传及下载文件)²,rsync
(远程数据同步工具)².网络通讯:
ssh
(安全的远程连接服务器)²,netstat
(显示网络状态)²,ping
(测试主机间网络连通性)².设备管理:
mount
(将文件系统挂载到目录)²,lspci
(显示当前设备PCI总线设备信息)².备份压缩:
zip
(压缩文件)²,gzip
(压缩和解压文件)².
# grep 的常用用法
以下是一些 grep 的使用示例:
在文件 file.txt 中查找字符串 “hello”,并打印匹配的行: grep hello file.txt
在文件夹 dir 中递归查找所有文件中匹配正则表达式 “pattern” 的行,并打印匹配行所在的文件名和行号: grep -r -n pattern dir/
在标准输入中查找字符串 “world”,并只打印匹配的行数: echo "hello world" | grep -c world
在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行: grep test *file
# 文件数据量大,查看文件内容
当文件数据量非常大时,我们可以使用一些特定的命令来查看文件内容,而不必打开整个文件。以下是一些常用的命令:
less
:less
命令可以用来查看大文件的内容。它允许你在文件中上下移动,这样你就可以遍历内容,然后在文件中回退¹。head
:如果只想看一个文件的前几行,可以用head
命令¹。tail
:与head
相对,tail
是只显示末尾几行。比如我们想查看一个文件的更新情况,只要看最后几行就可以了¹。grep
:从一个文件中查找到某个关键词,并将包含该关键词的行显示出来¹。cat | more
:这个命令组合可以用来分页查看文件内容⁴。find / -type f -size +1G -print0 | xargs -0 du -h | sort -nr
:这个命令组合可以用来查找大于1G的文件,并按照大小排序²。
# Linux 中查找端口并找到流量最大的端口
在 Linux 中,netstat
命令可以用来显示网络状态,包括 TCP 和 UDP 连接、监听的端口、以及每个网络接口设备的状态信息¹²。然而,netstat
并不能直接显示每个端口的流量。要查看每个端口的流量,你可能需要使用其他的工具或方法。
一种可能的方法是使用 iftop
或 nethogs
这样的工具来查看网络流量。这些工具可以显示每个连接的流量,从而让你找到流量最大的连接。然后,你可以使用 netstat
或 ss
命令来查看这些连接对应的端口。
例如,你可以先使用 nethogs
来查看网络流量:
sudo nethogs
然后,你可以使用 netstat
来查看对应的端口:
sudo netstat -tunlp
在这个命令中,-tunlp
参数表示显示 TCP (-t
) 和 UDP (-u
) 连接,不解析服务和主机名 (-n
),并显示监听的端口 (-l
) 和对应的进程信息 (-p
)。
# git常用指令
在面试中,你可能会被问到以下一些常用的Git命令:
git config
:配置信息¹³。git init
:初始化本地git仓库(创建新仓库)¹²。git clone
:拷贝一份远程仓库,也就是下载一个项目¹²。git add
:添加文件到暂存区¹²。git commit
:提交暂存区到本地仓库¹²。git status
:查看仓库当前的状态,显示有变更的文件¹³。git diff
:比较文件的不同,即暂存区和工作区的差异¹³。git reset HEAD
:取消缓存命令³。git rm
:将文件从暂存区和工作区中删除¹³。git mv
:移动或重命名工作区文件。