面试题答案
一键面试优化性能减少延迟和资源消耗的技术方案
- I/O 复用
- 选择合适的 I/O 复用机制:在 Linux 系统下,对于高并发套接字通信,
epoll
是比select
和poll
更高效的选择。epoll
采用事件驱动的方式,避免了select
和poll
每次调用都需要遍历所有文件描述符的开销。 - 使用边缘触发(ET)模式:
epoll
有水平触发(LT)和边缘触发(ET)两种模式。ET 模式在事件发生时只通知一次,相比 LT 模式可以减少不必要的通知,从而提高效率。但使用 ET 模式时,需要确保一次性读取或写入完所有数据,以避免遗漏事件。
- 选择合适的 I/O 复用机制:在 Linux 系统下,对于高并发套接字通信,
- 处理网络丢包
- 使用可靠的传输协议:TCP 本身提供了可靠的数据传输,通过序列号、确认应答、重传机制等保证数据的完整性。在高并发场景下,合理设置 TCP 的参数,如
TCP_NODELAY
可以禁用 Nagle 算法,减少小包合并带来的延迟;TCP_CORK
可以延迟发送数据,直到缓冲区满或者达到一定时间,以提高网络利用率。 - 应用层重传机制:在应用层可以实现自己的重传逻辑。例如,为每个发送的数据包添加序列号,接收方根据序列号确认是否接收到完整的数据。如果发送方在一定时间内没有收到接收方的确认,就重传该数据包。
- 使用可靠的传输协议:TCP 本身提供了可靠的数据传输,通过序列号、确认应答、重传机制等保证数据的完整性。在高并发场景下,合理设置 TCP 的参数,如
- 重连机制
- 定时重连:当检测到连接断开时,启动一个定时器,在一定时间间隔后尝试重新连接服务器。例如,可以使用
sleep
函数设置重连的时间间隔,每次重连失败后适当增加时间间隔,以避免过于频繁的重连。 - 指数退避重连:指数退避重连是一种更智能的重连策略。每次重连失败后,将重连时间间隔翻倍(或按照一定的指数增长规律),这样可以避免在网络故障期间大量客户端同时频繁重连,对服务器造成过大压力。
- 定时重连:当检测到连接断开时,启动一个定时器,在一定时间间隔后尝试重新连接服务器。例如,可以使用
关键代码示例
- 使用
epoll
进行 I/O 复用
#!/bin/bash
# 创建 epoll 实例
epoll_fd=$(epoll_create 1024)
# 监听套接字
listen_fd=$(socket PF_INET SOCK_STREAM 0)
bind $listen_fd 0.0.0.0 8080
listen $listen_fd 1024
# 将监听套接字添加到 epoll 实例中
epoll_ctl $epoll_fd ADD $listen_fd EPOLLIN
while true; do
# 等待事件发生
events=$(epoll_wait $epoll_fd -1 1024)
for event in $events; do
fd=$(echo $event | awk '{print $1}')
if [ $fd -eq $listen_fd ]; then
# 处理新连接
client_fd=$(accept $listen_fd)
epoll_ctl $epoll_fd ADD $client_fd EPOLLIN
else
# 处理客户端数据
data=$(read $fd)
if [ -z "$data" ]; then
# 客户端关闭连接
epoll_ctl $epoll_fd DEL $fd EPOLLIN
close $fd
else
# 处理接收到的数据
echo "Received: $data"
# 回显数据
echo $data >&$fd
fi
fi
done
done
close $listen_fd
close $epoll_fd
- 简单的应用层重传机制示例
#!/bin/bash
# 假设已经建立了套接字连接 $socket_fd
seq_num=0
while true; do
data="Message $seq_num"
# 发送数据
echo -n $data >&$socket_fd
start_time=$(date +%s%N)
# 等待确认
while true; do
read -t 1 -u $socket_fd ack
if [ -n "$ack" ] && [ "$ack" = "ACK $seq_num" ]; then
break
fi
current_time=$(date +%s%N)
elapsed_time=$(( ($current_time - $start_time) / 1000000000 ))
if [ $elapsed_time -gt 5 ]; then
# 超时重传
echo -n $data >&$socket_fd
start_time=$(date +%s%N)
fi
done
seq_num=$((seq_num + 1))
done
- 定时重连机制示例
#!/bin/bash
server_ip="192.168.1.100"
server_port=8080
retry_interval=5
while true; do
socket_fd=$(socket PF_INET SOCK_STREAM 0)
if connect $socket_fd $server_ip $server_port; then
echo "Connected to server"
# 进行正常的数据通信
while true; do
read -u $socket_fd data
if [ -z "$data" ]; then
break
fi
echo "Received: $data"
echo "ACK" >&$socket_fd
done
close $socket_fd
else
echo "Connection failed, retry in $retry_interval seconds"
sleep $retry_interval
fi
done
以上代码示例只是简单演示相关机制,实际应用中可能需要根据具体需求进行更多的错误处理、优化和完善。