面试题答案
一键面试可能导致性能问题的原因
- 阻塞式I/O操作:Python中默认的I/O操作是阻塞的,在高并发场景下,大量的I/O等待会浪费CPU资源,导致性能瓶颈。例如数据库查询、文件读取等操作。
- 全局解释器锁(GIL):CPython解释器存在GIL,同一时间只有一个线程能执行Python字节码,多线程在CPU密集型任务下无法利用多核优势,对于高并发的计算任务性能不佳。
- 数据库连接开销:每次处理请求都创建新的数据库连接开销较大,高并发时频繁的连接创建和销毁会降低性能。
- 缓存缺失:如果没有合理使用缓存,相同数据的重复查询会加重数据库负担,降低API响应速度。
- 缺乏负载均衡:单台服务器处理所有请求,在高并发下容易达到性能极限。
代码层面优化
- 异步编程
- FastAPI结合
async
和await
:FastAPI支持异步编程,可以将I/O操作定义为异步函数。例如,使用asyncpg
库进行异步数据库操作。
from fastapi import FastAPI import asyncpg app = FastAPI() async def get_user_from_db(user_id): conn = await asyncpg.connect(user='user', password='password', database='test', host='127.0.0.1') result = await conn.fetchrow('SELECT * FROM users WHERE id = $1', user_id) await conn.close() return result @app.get("/users/{user_id}") async def get_user(user_id: int): user = await get_user_from_db(user_id) return user
- 使用
uvloop
:uvloop
是一个快速的事件循环替代方案,可用于替代Python标准库中的asyncio
事件循环。在FastAPI项目中,可通过以下方式使用:
import uvloop import asyncio uvloop.install() asyncio.run(main()) # main是你的FastAPI应用启动函数
- FastAPI结合
- 数据库连接池
- 使用
aiomysql
连接池(以MySQL为例):在FastAPI中可以这样配置:
from fastapi import FastAPI import aiomysql app = FastAPI() async def create_pool(): pool = await aiomysql.create_pool( host='127.0.0.1', port=3306, user='user', password='password', db='test', autocommit=True ) return pool pool = asyncio.run(create_pool()) async def get_user_from_db(user_id): async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute('SELECT * FROM users WHERE id = %s', (user_id,)) result = await cur.fetchone() return result @app.get("/users/{user_id}") async def get_user(user_id: int): user = await get_user_from_db(user_id) return user
- 使用
架构层面优化
- 负载均衡
- 使用Nginx:Nginx可以作为反向代理服务器实现负载均衡。在Nginx配置文件中,可以这样设置:
upstream fastapi_backend { server 192.168.1.10:8000; server 192.168.1.11:8000; } server { listen 80; server_name your_domain.com; location / { proxy_pass http://fastapi_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
- 缓存策略
- 使用Redis缓存:在FastAPI中可以结合
aioredis
库使用Redis缓存。例如,缓存数据库查询结果:
from fastapi import FastAPI import aioredis app = FastAPI() redis = aioredis.from_url('redis://127.0.0.1:6379') async def get_user_from_db(user_id): # 假设这里是数据库查询逻辑 pass async def get_user(user_id: int): cached_user = await redis.get(f'user:{user_id}') if cached_user: return cached_user.decode('utf-8') user = await get_user_from_db(user_id) await redis.set(f'user:{user_id}', str(user)) return user
- 使用Redis缓存:在FastAPI中可以结合