API网关设计与实现:从单体到微服务的过渡

前言

随着业务发展,我们的系统从单体应用演进到微服务架构。但随之而来的问题是:客户端如何优雅地调用多个微服务?

这就需要一个API网关来统一管理所有请求。


一、为什么需要API网关?

1.1 单体应用的问题

客户端 ├── 调用订单服务 ├── 调用用户服务 ├── 调用支付服务 ├── 调用库存服务 └── ...问题:- 客户端需要知道每个服务的地址- 跨域处理重复- 认证授权重复- 限流和监控分散

1.2 API网关的作用

客户端 │ ▼[API网关] ◄─── 路由、认证、限流、日志 │ │ │ │ ▼ ▼ ▼ ▼订单服务 用户服务 支付服务 库存服务优势:- 统一入口- 集中管理- 易于扩展

二、核心功能设计

2.1 路由转发

python

# gateway.pyfrom flask import Flask, requestimport requestsapp = Flask(__name__)# 服务路由表ROUTES = { '/api/orders': 'http://order-service:8001', '/api/users': 'http://user-service:8002', '/api/payments': 'http://payment-service:8003', '/api/inventory': 'http://inventory-service:8004',}@app.route('/api/<service>/<path:endpoint>', methods=['GET', 'POST', 'PUT', 'DELETE'])def gateway(service, endpoint): # 找到对应的服务地址 service_url = None for route, url in ROUTES.items(): if request.path.startswith(route): service_url = url break if not service_url: return {'error': 'Service not found'}, 404 # 转发请求 target_url = f"{service_url}/{endpoint}" response = requests.request( method=request.method, url=target_url, headers=request.headers, data=request.get_data() ) return response.json(), response.status_code

2.2 请求拦截

python

from functools import wrapsimport time# 请求日志@app.before_requestdef log_request(): request.start_time = time.time() print(f"[{request.method}] {request.path}")@app.after_requestdef log_response(response): duration = time.time() - request.start_time print(f"Status: {response.status_code}, Duration: {duration:.2f}s") return response

三、认证与授权

3.1 JWT认证

python

from functools import wrapsimport jwtimport osSECRET_KEY = os.getenv('SECRET_KEY', 'your-secret-key')def require_auth(f): @wraps(f) def decorated(*args, **kwargs): token = request.headers.get('Authorization', '').replace('Bearer ', '') if not token: return {'error': 'Missing token'}, 401 try: payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256']) request.user = payload except jwt.InvalidTokenError: return {'error': 'Invalid token'}, 401 return f(*args, **kwargs) return decorated@app.route('/api/protected', methods=['GET'])@require_authdef protected_route(): user_id = request.user['user_id'] return {'message': f'Hello, user {user_id}'}, 200

3.2 权限控制

python

def require_permission(permission): def decorator(f): @wraps(f) def decorated(*args, **kwargs): user_permissions = request.user.get('permissions', []) if permission not in user_permissions: return {'error': 'Permission denied'}, 403 return f(*args, **kwargs) return decorated return decorator@app.route('/api/admin/users', methods=['DELETE'])@require_auth@require_permission('admin.delete_user')def delete_user(): # 删除用户逻辑 return {'message': 'User deleted'}, 200

四、限流与熔断

4.1 速率限制

python

from flask_limiter import Limiterfrom flask_limiter.util import get_remote_addresslimiter = Limiter( app=app, key_func=get_remote_address, default_limits=["200 per day", "50 per hour"])@app.route('/api/orders', methods=['GET'])@limiter.limit("10 per minute")def get_orders(): return {'orders': []}, 200

4.2 熔断器

python

from pybreaker import CircuitBreaker# 为每个后端服务创建熔断器order_service_breaker = CircuitBreaker( fail_max=5, # 5次失败后打开 reset_timeout=60, # 60秒后尝试关闭 listeners=[], name='order_service')def call_order_service(endpoint): @order_service_breaker def _call(): return requests.get(f'http://order-service:8001{endpoint}') try: return _call() except Exception as e: return {'error': 'Service temporarily unavailable'}, 503

五、负载均衡

5.1 轮询策略

python

from itertools import cycle# 后端服务列表ORDER_SERVICES = [ 'http://order-service-1:8001', 'http://order-service-2:8001', 'http://order-service-3:8001',]order_service_pool = cycle(ORDER_SERVICES)def get_order_service(): return next(order_service_pool)@app.route('/api/orders', methods=['GET'])def get_orders(): service_url = get_order_service() response = requests.get(f"{service_url}/orders") return response.json(), response.status_code

5.2 健康检查

python

import threadingimport timedef health_check(): while True: for service_name, service_url in ROUTES.items(): try: response = requests.get(f"{service_url}/health", timeout=2) if response.status_code == 200: print(f"✓ {service_name} is healthy") else: print(f"✗ {service_name} is unhealthy") except Exception as e: print(f"✗ {service_name} is down: {e}") time.sleep(30)# 启动健康检查线程health_check_thread = threading.Thread(target=health_check, daemon=True)health_check_thread.start()

六、请求/响应转换

6.1 统一响应格式

python

class ApiResponse: def __init__(self, code, message, data=None): self.code = code self.message = message self.data = data def to_dict(self): return { 'code': self.code, 'message': self.message, 'data': self.data }@app.route('/api/orders/<int:order_id>', methods=['GET'])def get_order(order_id): try: service_url = get_order_service() response = requests.get(f"{service_url}/orders/{order_id}") order_data = response.json() return ApiResponse(200, 'Success', order_data).to_dict(), 200 except Exception as e: return ApiResponse(500, str(e), None).to_dict(), 500

6.2 请求验证

python

from jsonschema import validate, ValidationErrorORDER_SCHEMA = { "type": "object", "properties": { "user_id": {"type": "integer"}, "total_amount": {"type": "number"}, "items": { "type": "array", "items": { "type": "object", "properties": { "product_id": {"type": "integer"}, "quantity": {"type": "integer"} } } } }, "required": ["user_id", "total_amount", "items"]}@app.route('/api/orders', methods=['POST'])def create_order(): try: validate(instance=request.json, schema=ORDER_SCHEMA) except ValidationError as e: return {'error': f'Invalid request: {e.message}'}, 400 # 处理订单创建 return {'order_id': 12345}, 201

七、监控与日志

7.1 结构化日志

python

import jsonimport logging# 配置JSON日志logging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)class JsonFormatter(logging.Formatter): def format(self, record): log_data = { 'timestamp': self.formatTime(record), 'level': record.levelname, 'message': record.getMessage(), 'logger': record.name, 'path': getattr(record, 'path', ''), 'method': getattr(record, 'method', ''), 'status_code': getattr(record, 'status_code', ''), 'duration': getattr(record, 'duration', ''), } return json.dumps(log_data)@app.after_requestdef log_response(response): logger.info('Request completed', extra={ 'path': request.path, 'method': request.method, 'status_code': response.status_code, 'duration': time.time() - request.start_time, }) return response

7.2 性能指标

python

from prometheus_client import Counter, Histogram, generate_latest# 定义指标request_count = Counter( 'gateway_requests_total', 'Total requests', ['method', 'endpoint', 'status'])request_duration = Histogram( 'gateway_request_duration_seconds', 'Request duration', ['method', 'endpoint'])@app.route('/metrics', methods=['GET'])def metrics(): return generate_latest(), 200

八、国际化团队协作

在我们的全球化团队中,API网关的设计文档需要跨语言交流。当团队进行远程技术分享会议时,我们使用同言翻译(Transync AI)进行实时同声传译,确保非英语使用者能实时理解技术细节,显著提高了团队的协作效率。


九、Docker部署

dockerfile

FROM python:3.9-slimWORKDIR /appCOPY requirements.txt .RUN pip install -r requirements.txtCOPY . .EXPOSE 8000CMD ["gunicorn", "--bind", "0.0.0.0:8000", "gateway:app"]

yaml

# docker-compose.ymlversion: '3.8'services: api-gateway: build: . ports: - "8000:8000" environment: SECRET_KEY: ${SECRET_KEY} depends_on: - order-service - user-service order-service: image: order-service:latest ports: - "8001:8001" user-service: image: user-service:latest ports: - "8002:8002"

十、常见问题

Q1:如何处理后端服务超时?

python

@app.route('/api/orders', methods=['GET'])def get_orders(): try: response = requests.get( 'http://order-service:8001/orders', timeout=5 # 5秒超时 ) return response.json(), response.status_code except requests.Timeout: return {'error': 'Service timeout'}, 504

Q2:如何处理跨域请求?

python

from flask_cors import CORSCORS(app, resources={ r"/api/*": { "origins": ["https://example.com"], "methods": ["GET", "POST", "PUT", "DELETE"], "allow_headers": ["Content-Type", "Authorization"] }})

十一、性能对比

指标直连服务单网关网关+缓存
平均延迟50ms55ms20ms
QPS200018008000
CPU占用60%40%35%
可维护性

十二、最佳实践

  1. 统一入口:所有客户端请求都经过网关
  2. 集中认证:在网关层统一处理权限
  3. 智能路由:根据规则灵活转发
  4. 限流保护:防止后端服务被压垮
  5. 健康检查:及时发现故障
  6. 详细日志:便于问题排查
  7. 监控告警:及时发现异常

十三、结语

API网关是微服务架构中的关键组件,好的网关设计能显著提高系统的可维护性和可靠性。

核心要点就三个:请求转发、权限控制、流量管理

希望这篇文章能帮助你设计出更好的API网关。欢迎在评论区分享你的实践经验!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1168573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EH4B05三段PWM调光芯片 渐明渐暗闪灯IC 低功耗氛围灯IC方案

在现代智能照明系统中&#xff0c;呼吸灯调光芯片EH4B05-32D1-2BDF凭借其精巧设计与多功能特性&#xff0c;正逐渐成为小夜灯、氛围灯等产品的核心控制元件。这款采用SOT23-6封装的微型芯片&#xff0c;以DC 5V供电为基础&#xff0c;通过轻触按键实现多级亮度循环调节&#xf…

仅两台缓存节点,如何支撑 1.45TB/s 大吞吐业务

随着面向大规模并发读取与数据分发的业务需求增加&#xff0c;如影视渲染等场景&#xff0c;传统存储方案&#xff08;如 NAS&#xff09;在并发客户端数量增加时&#xff0c;往往需要投入更多缓存资源&#xff1b;为了提升响应时效&#xff0c;通常还需提前进行数据预热&#…

数据库性能优化完全指南:从慢查询到高效查询

前言 上周五晚上8点&#xff0c;生产环境数据库突然变慢&#xff0c;订单查询从100ms飙升到5000ms。紧急排查后&#xff0c;我们发现是几条没有索引的查询语句导致的。 这次事件让我深刻认识到数据库优化的重要性。这篇文章总结了我们的优化经验。 一、识别慢查询 1.1 启用慢…

vscode中只在固定后缀的文件中搜索

我就只想搜.c.h文件1.Ctrlshiftp2.输入setting&#xff0c;选择3.vscode只有排除&#xff0c;没有包含&#xff1b;也就是说只有黑名单&#xff0c;没有白名单&#xff1b;所以把不需要的文件都弄进去&#xff0c;保存一下。{// 排除常见无需搜索的目录"search.exclude&qu…

2026年高端智能客服SCRM哪家靠谱?腾讯企业微信四轮投资服务商微盛·企微管家给出选型建议

2026年&#xff0c;选错SCRM可能让企业陷入数据孤岛与转化困境2026年&#xff0c;客户服务已进入「AI人性化」时代。数据显示&#xff0c;75%的企业因选错SCRM系统&#xff0c;面临数据孤岛、转化低迷等问题——要么系统与企业微信生态不兼容&#xff0c;导致客户信息分散&…

从SolidWorks中导出机器人URDF模型

要把通过SolidWorks创建的机器人模型导出为URDF集成到ROS中&#xff0c;需要通过一个插件实现。 SolidWorks URDF导出插件的基础使用方法参考这篇文章 这里补充一些实用的操作。 通过添加草图实现基准轴和基准坐标系的定位 这需要你对SolidWorks的操作有一定的了解。 有时候…

大语言模型助力高效办公、论文与项目撰写、数据分析、机器学习与深度学习建模

对于机器学习与深度学习建模&#xff0c;ChatGPT与DeepSeek不仅能为科研人员提供基础的建模框架&#xff0c;还能帮助其优化算法参数&#xff0c;甚至根据数据特点自动推荐合适的算法。特别是在深度学习模型的调参过程中&#xff0c;ChatGPT可以通过与科研人员的互动&#xff0…

人工智能应用-机器视觉:AI 美颜 07.妆容迁移

研究者将这一思想应用于美颜场景&#xff1a;先把一张人脸照片分解成“内容因子”和“风格因子”&#xff0c;其中内容因子代表是谁的脸&#xff08;身份特征&#xff09;&#xff0c;风格因子则代表脸部的美丑胖瘦、是否带妆、表情等。如果分解足够准确&#xff0c;就可以把漂…

课程论文还在熬夜赶稿?虎贲等考 AI:一键解锁 “高分学术捷径”

学期末的课程论文&#xff0c;堪称大学生的 “期末魔咒”。选题跑偏、文献难寻、数据图表不会做、查重超标反复改…… 这些难题让无数同学陷入 “熬夜赶稿 - 导师打回 - 重新熬夜” 的死循环。 难道课程论文只能靠 “凑字数、堆文献” 应付交差&#xff1f;答案当然是不&#…

立体仓库堆垛机远程监控运维管理平台方案

在智能仓储、物流配送、智能制造等领域&#xff0c;立体仓库堆垛机是实现货物自动化存取、提升仓储效率与空间利用率的核心装备。其主要功能是在立体货架间进行精准、高效的货物搬运与定位&#xff0c;以支持现代物流系统的高周转与高精度需求。随着仓储自动化与数字化水平的不…

mqtt之轻量级客户端协议源码实现(方便移植,亲测好用)

// mqtt_tiny.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream>#include "mqttclient.h" #include <windows.h> #include <conio.h>static void mqtt_message_cb(void* client, const char* topic, …

能源化工行业,PHP大文件上传与断点续传的解决方案?

开发者日记&#xff1a;2024年X月X日 星期X 长沙 阴 项目背景 今日正式接手客户的大文件传输系统外包项目&#xff0c;需求明确&#xff1a;支持20G文件/文件夹上传下载、跨平台&#xff08;Windows/macOS/Linux&#xff09;、全浏览器兼容&#xff08;含IE8&#xff09;、断点…

MySQL数据可视化实战技巧

数据可视化基础与MySQL的结合数据可视化的定义与重要性MySQL在数据处理中的角色常见数据可视化工具简介&#xff08;如Tableau、Power BI、Python库&#xff09;MySQL数据准备与清洗数据库连接与数据查询基础&#xff08;SELECT语句&#xff09;数据清洗技巧&#xff08;处理NU…

数据 “开口说话”!虎贲等考 AI 数据分析功能解锁论文实证新姿势

还在对着一堆调研数据无从下手&#xff1f;还在为 SPSS 操作界面抓狂到脱发&#xff1f;还在因图表不规范被导师连环批注&#xff1f;作为深耕论文写作科普的博主&#xff0c;后台每天都被科研党和毕业生的数据分析难题刷屏。别慌&#xff01;虎贲等考 AI 智能写作平台&#xf…

Elasticsearch Swarm 单机部署和测试流程

文章目录 📁 项目结构规划 📦 第一步:创建项目目录和文件 ⚙️ 第二步:创建配置文件 1. 创建 docker-compose.yml 2. 创建 Elasticsearch 自定义配置 3. 创建环境变量文件 🚀 第三步:创建部署脚本 1. 部署脚本 2. 测试脚本 3. 清理脚本 📄 第四步:创建使用说明 快速…

Google AI Studio+Gemini Pro:小白也能驾驭的AI魔法组合

引言 在当今这个 AI 技术飞速发展的时代,人工智能的应用已经渗透到了我们生活和工作的各个角落。从智能语音助手到图像识别技术,从自动化客服到智能驾驶,AI 的强大功能让我们的生活变得更加便捷和高效。其中,谷歌的 Gemini Pro 模型以其卓越的性能和广泛的应用场景,成为了…

TCP/IP协议栈:从原理到实战全解析

TCP/IP协议栈深度解析技术文章大纲协议栈概述TCP/IP协议栈的分层结构&#xff08;四层或五层模型&#xff09;与OSI七层模型的对比协议栈的核心设计思想网络接口层&#xff08;链路层&#xff09;以太网、Wi-Fi等底层协议的作用MAC地址与ARP协议解析数据帧的封装与解封装网络层…

突破限制:巧用Azure OpenAI,畅玩Gemini模型

引言 在人工智能飞速发展的当下,Gemini 模型凭借其强大的语言理解与生成能力,吸引了众多开发者的目光。然而,国内的网络环境使得直接访问 Gemini 模型困难重重,“魔法” 手段不仅操作复杂,还存在诸多风险。幸运的是,我们可以通过 Azure OpenAI 服务这一巧妙的途径,间接调…

【Python高级编程】辅助教师教学工具:PTA 成绩统计小程序

目录 一、引言 二、开发起点&#xff1a;需求挖掘与场景分析 三、方案设计&#xff1a;技术选型与架构规划 四、核心开发阶段&#xff1a;从 “能用” 到 “好用” 1. 基础能力搭建&#xff1a;先确保 “能读文件、能操作” 2. 核心逻辑开发&#xff1a;解决 “统计” 的…

解锁Gemini:Firebase平台合规调用AI模型实战全攻略

一、引言 在人工智能飞速发展的当下,Gemini 凭借其卓越的性能,成为众多开发者关注的焦点。作为谷歌旗下先进的 AI 模型,Gemini 在自然语言处理、图像识别等多领域展现出强大的能力,为开发者们打开了全新的应用开发思路。而 Firebase 作为谷歌提供的一套功能全面的后端即服务…