基础设施实战指南:从日志系统到负载均衡

前言:基础设施是系统的地基

看得见的是业务,看不见的是基础设施。日志、配置、负载均衡、网络协议——这些"幕后英雄"决定了系统的稳定性和可维护性。

一、日志系统

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
维度ELKLoki
存储全文索引(大)只索引标签(小)
查询强大简单
资源
成本
适用复杂搜索日志 + 监控一体化

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 ConfigJava 生态
Apollo携程开源,功能全
Nacos阿里开源,配置+注册
ConsulHashiCorp,KV + 服务发现
etcdK8s 底层用

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/UDPHTTP/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

坑四:负载均衡不均

权重配置不当或会话保持导致。检查算法 + 监控各节点负载。

七、写在最后

基础设施是"看不见"的工作,但决定了系统的上限

几条核心原则:

  1. 结构化日志:JSON 格式 + 链路追踪
  2. 配置中心:动态配置不重新部署
  3. 负载均衡:根据场景选算法
  4. TCP 调优:高并发场景必须
  5. 监控是基础:CPU、内存、IO、网络都要看
  6. 日志是排查的关键:出了问题先看日志

本文整合了 5 篇基础设施相关文章,涵盖日志系统(ELK/Loki)、配置中心(Nacos/Apollo)、负载均衡算法、TCP/IP 协议栈、服务器性能优化等核心技术。

版权声明: 本文首发于 指尖魔法屋-基础设施实战指南:从日志系统到负载均衡https://blog.thinkmoon.cn/post/infrastructure-comprehensive-guide/) 转载或引用必须申明原指尖魔法屋来源及源地址!