基础设施实战指南:从日志系统到负载均衡
前言:基础设施是系统的地基
看得见的是业务,看不见的是基础设施。日志、配置、负载均衡、网络协议——这些"幕后英雄"决定了系统的稳定性和可维护性。
一、日志系统
1.1 日志的五个级别
import logging
DEBUG = logging.DEBUG # 10 - 调试信息
INFO = logging.INFO # 20 - 正常运行
WARNING = logging.WARNING # 30 - 警告
ERROR = logging.ERROR # 40 - 错误
CRITICAL = logging.CRITICAL # 50 - 严重错误
| 级别 | 适用场景 | 生产环境 |
|---|---|---|
| DEBUG | 开发调试 | 关闭 |
| INFO | 正常运行事件 | 开启 |
| WARNING | 异常但可处理 | 开启 |
| ERROR | 影响功能 | 开启 + 告警 |
| CRITICAL | 系统不可用 | 开启 + 立即告警 |
1.2 结构化日志
import json
import logging
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log = {
'timestamp': datetime.utcnow().isoformat(),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno,
}
# 链路追踪 ID
if hasattr(record, 'request_id'):
log['request_id'] = record.request_id
if hasattr(record, 'user_id'):
log['user_id'] = record.user_id
return json.dumps(log)
# 配置
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.basicConfig(level=logging.INFO, handlers=[handler])
# 使用
logger = logging.getLogger(__name__)
logger.info('User logged in',
extra={'request_id': 'abc123', 'user_id': 42})
1.3 日志收集架构:ELK vs Loki
graph LR
subgraph ELK
A1[Filebeat] --> B1[Logstash]
B1 --> C1[Elasticsearch]
C1 --> D1[Kibana]
end
subgraph Loki
A2[Promtail] --> B2[Loki]
B2 --> C2[Grafana]
end
| 维度 | ELK | Loki |
|---|---|---|
| 存储 | 全文索引(大) | 只索引标签(小) |
| 查询 | 强大 | 简单 |
| 资源 | 大 | 小 |
| 成本 | 高 | 低 |
| 适用 | 复杂搜索 | 日志 + 监控一体化 |
1.4 日志最佳实践
# 1. 不要记录敏感信息
logger.info(f"User login: {username}") # ✓
logger.info(f"User login: {username}, password: {password}") # ✗
# 2. 记录足够上下文
logger.error(f"Database error",
extra={'query': sql, 'params': params, 'host': db_host})
# 3. 异步日志(不阻塞主线程)
from logging.handlers import QueueHandler, QueueListener
import queue
log_queue = queue.Queue()
queue_handler = QueueHandler(log_queue)
file_handler = logging.FileHandler('app.log')
listener = QueueListener(log_queue, file_handler)
listener.start()
logger.addHandler(queue_handler)
# 4. 日志轮转
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
'app.log',
maxBytes=100 * 1024 * 1024, # 100MB
backupCount=10
)
二、配置中心
2.1 为什么需要配置中心
- 多环境(dev/staging/prod)配置管理
- 配置变更不重新部署
- 配置版本管理
- 配置变更通知
2.2 配置中心选型
| 工具 | 特点 |
|---|---|
| Spring Cloud Config | Java 生态 |
| Apollo | 携程开源,功能全 |
| Nacos | 阿里开源,配置+注册 |
| Consul | HashiCorp,KV + 服务发现 |
| etcd | K8s 底层用 |
2.3 Nacos 配置示例
# Nacos 配置
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: production
group: ORDER_GROUP
data-id: order-service.yaml
# Python 客户端
from nacos import NacosClient
client = NacosClient('localhost:8848', namespace='production')
config = client.get_config('order-service.yaml', 'ORDER_GROUP')
# 监听配置变更
def on_config_change(args):
print(f"Config changed: {args['content']}")
client.add_config_watcher('order-service.yaml', 'ORDER_GROUP', on_config_change)
2.4 配置管理最佳实践
# 配置分层
application.yaml # 通用配置
application-dev.yaml # 开发环境
application-prod.yaml # 生产环境
# 敏感配置用 Secret
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
password: <base64-encoded>
三、负载均衡
3.1 四层 vs 七层
| 维度 | 四层(LVS) | 七层(Nginx) |
|---|---|---|
| 协议 | TCP/UDP | HTTP/HTTPS |
| 性能 | 高 | 中 |
| 功能 | 简单 | 丰富 |
| 适用 | 大流量入口 | API 网关 |
3.2 负载均衡算法
import random
import itertools
# 1. 轮询
class RoundRobin:
def __init__(self, servers):
self.servers = servers
self.cycle = itertools.cycle(servers)
def next(self):
return next(self.cycle)
# 2. 加权轮询
class WeightedRoundRobin:
def __init__(self, servers, weights):
self.servers = servers
self.weights = weights
def next(self):
expanded = []
for server, weight in zip(self.servers, self.weights):
expanded.extend([server] * weight)
return random.choice(expanded)
# 3. 最少连接
class LeastConnections:
def __init__(self, servers):
self.connections = {s: 0 for s in servers}
def next(self):
return min(self.connections, key=self.connections.get)
def acquire(self, server):
self.connections[server] += 1
def release(self, server):
self.connections[server] -= 1
# 4. 一致性哈希(会话保持)
import hashlib
class ConsistentHashing:
def __init__(self, servers, replicas=100):
self.ring = {}
for server in servers:
for i in range(replicas):
key = f"{server}:{i}"
hash_val = int(hashlib.md5(key.encode()).hexdigest(), 16)
self.ring[hash_val] = server
self.sorted_hashes = sorted(self.ring.keys())
def get_server(self, key):
hash_val = int(hashlib.md5(key.encode()).hexdigest(), 16)
for h in self.sorted_hashes:
if h >= hash_val:
return self.ring[h]
return self.ring[self.sorted_hashes[0]]
3.3 Nginx 负载均衡配置
# 加权轮询
upstream backend {
server 10.0.0.1 weight=3;
server 10.0.0.2 weight=1;
server 10.0.0.3 backup; # 备用
}
# IP 哈希(会话保持)
upstream backend {
ip_hash;
server 10.0.0.1;
server 10.0.0.2;
}
# 最少连接
upstream backend {
least_conn;
server 10.0.0.1 max_fails=3 fail_timeout=30s;
server 10.0.0.2 max_fails=3 fail_timeout=30s;
}
# 健康检查
upstream backend {
server 10.0.0.1;
server 10.0.0.2;
keepalive 32; # 保持长连接
}
四、TCP/IP 协议栈
4.1 TCP 三次握手
sequenceDiagram
participant C as 客户端
participant S as 服务端
C->>S: SYN (seq=x)
Note over S: SYN_RCVD
S->>C: SYN+ACK (seq=y, ack=x+1)
Note over C: ESTABLISHED
C->>S: ACK (ack=y+1)
Note over S: ESTABLISHED
4.2 TCP 四次挥手
sequenceDiagram
participant C as 客户端
participant S as 服务端
C->>S: FIN (seq=x)
Note over C: FIN_WAIT_1
S->>C: ACK (ack=x+1)
Note over C: FIN_WAIT_2
Note over S: CLOSE_WAIT
S->>C: FIN (seq=y)
Note over S: LAST_ACK
C->>S: ACK (ack=y+1)
Note over C: TIME_WAIT (2MSL)
Note over S: CLOSED
4.3 TCP 调优
# /etc/sysctl.conf
# 增加文件描述符
fs.file-max = 1000000
# TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 连接复用
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
# KeepAlive
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 生效
sysctl -p
4.4 HTTP 状态码
2xx 成功
200 OK
201 Created
204 No Content
3xx 重定向
301 Moved Permanently
302 Found
304 Not Modified
4xx 客户端错误
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
429 Too Many Requests
5xx 服务端错误
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
五、服务器性能优化
5.1 Linux 性能分析工具
# CPU
top / htop # 实时进程
mpstat # CPU 统计
perf # 性能分析
# 内存
free -h # 内存使用
vmstat # 虚拟内存
sar -r # 内存历史
# 磁盘 IO
iostat # IO 统计
iotop # IO top
df -h # 磁盘使用
# 网络
iftop # 网络流量
ss / netstat # 连接状态
tcpdump # 抓包
# 综合
dstat # 综合监控
sar # 历史数据
5.2 常见性能问题
问题一:CPU 100%
# 找到最耗 CPU 的进程
top -c
# 找到最耗 CPU 的线程
top -H -p <pid>
# 查看线程在做什么
printf "%x\n" <tid> # 转 16 进制
jstack <pid> | grep <hex_tid>
问题二:内存泄漏
# 查看进程内存
ps aux --sort=-%mem | head
# Java 堆 dump
jmap -dump:format=b,file=heap.hprof <pid>
问题三:磁盘 IO 瓶颈
# 查看 IO
iostat -x 1
# IOPS 高的进程
iotop
六、踩坑总结
坑一:日志写满磁盘
解决: 日志轮转 + 监控磁盘使用率。
坑二:配置变更没生效
解决: 配置变更通知机制 + 健康检查。
坑三:TIME_WAIT 过多
短连接过多导致 TIME_WAIT 堆积。解决:长连接 + tcp_tw_reuse=1。
坑四:负载均衡不均
权重配置不当或会话保持导致。检查算法 + 监控各节点负载。
七、写在最后
基础设施是"看不见"的工作,但决定了系统的上限。
几条核心原则:
- 结构化日志:JSON 格式 + 链路追踪
- 配置中心:动态配置不重新部署
- 负载均衡:根据场景选算法
- TCP 调优:高并发场景必须
- 监控是基础:CPU、内存、IO、网络都要看
- 日志是排查的关键:出了问题先看日志
本文整合了 5 篇基础设施相关文章,涵盖日志系统(ELK/Loki)、配置中心(Nacos/Apollo)、负载均衡算法、TCP/IP 协议栈、服务器性能优化等核心技术。
版权声明: 本文首发于 指尖魔法屋-基础设施实战指南:从日志系统到负载均衡(https://blog.thinkmoon.cn/post/infrastructure-comprehensive-guide/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。