一、性能优化概述
1.1 Web应用性能指标
Web应用的性能可以从三个核心维度来衡量。响应时间(Response Time)是指从用户发起请求到收到完整响应所经过的时间,通常以毫秒为单位。研究表明,页面加载时间每增加100毫秒,转化率就会下降约7%。吞吐量(Throughput)表示系统在单位时间内能处理的请求数量,常用RPS(Requests Per Second)或QPS(Queries Per Second)来衡量。并发数(Concurrency)则代表了系统在同一时刻能够处理的请求总数。这三者相互制约,高并发往往会导致响应时间上升和吞吐量下降,优化时需要综合权衡。
1.2 性能优化的原则
性能优化应当遵循两个基本原则。第一是80/20法则,即80%的性能瓶颈往往集中在20%的代码中,要优先解决主要矛盾而非全面铺开。第二是避免过早优化,Donald Knuth曾说:"过早优化是万恶之源。"在代码尚未明确成为瓶颈之前进行过度优化,不仅浪费时间,还可能降低代码的可读性和可维护性。正确的做法是先构建可工作的版本,然后通过性能分析工具找出真正的瓶颈所在,再有针对性地优化。
1.3 性能分析的步骤
系统化的性能分析通常包含四个步骤。第一步是定义性能目标,明确项目的性能基线(如API响应时间需小于200ms)。第二步是建立性能监控,在生产环境中部署APM工具持续采集性能数据。第三步是进行压力测试,模拟真实用户场景发现系统瓶颈。第四步是定位和修复问题,针对性地优化后重复测试验证效果。
1.4 常用性能工具
Python生态中有丰富的性能分析工具。cProfile是Python内置的性能分析器,可以精确统计每个函数的调用次数和执行时间。py-spy是一个采样分析器,可以附加到正在运行的Python进程中进行分析而无需修改代码。对于Web应用的压力测试,Locust提供了基于Python脚本的分布式负载测试方案,可以模拟数十万并发用户。siege则是一个轻量级的HTTP负载测试工具,适合快速验证。此外,Django Debug Toolbar可以在开发阶段直观地显示每个页面的SQL查询次数、耗时和缓存命中情况。
# 使用cProfile分析性能
python -m cProfile -o output.prof my_script.py
# 使用py-spy分析运行中的进程
py-spy record -o profile.svg --pid 12345
# 使用snakeviz可视化分析结果
snakeviz output.prof
二、数据库查询优化
2.1 N+1查询问题与解决
N+1查询是Web开发中最常见也最容易被忽视的性能问题。所谓N+1查询,是指首先执行一条查询获取N条主记录,然后在循环中对每条记录额外执行一次查询获取关联数据,总共执行了N+1次查询。例如,在Django中获取所有文章列表并显示每篇文章的作者时,如果使用常规的ForeignKey访问,就会触发N+1查询。
解决N+1查询的核心方法是使用预加载(Eager Loading)。在Django中,select_related用于一对一和一对多关系(通过SQL JOIN实现),而prefetch_related适用于多对多和多对一关系(通过额外的查询并在Python中合并)。在SQLAlchemy中,可以使用joinedload或subqueryload来实现相同的效果。
# 问题代码:每次循环都会执行一次数据库查询
articles = Article.objects.all()
for article in articles:
print(article.author.name) # N次额外查询
# 优化方案:使用select_related预加载
articles = Article.objects.select_related('author').all()
for article in articles:
print(article.author.name) # 仅1次查询(JOIN)
# 多对多关系使用prefetch_related
articles = Article.objects.prefetch_related('tags').all()
2.2 索引优化
数据库索引是提升查询性能最有效的手段之一。合理的索引可以将全表扫描转化为索引查找,将时间复杂度从O(n)降低到O(log n)。创建索引时需要遵循几个原则:经常出现在WHERE条件中的列应该建立索引;经常用于排序(ORDER BY)和分组(GROUP BY)的列应该建立索引;联合索引遵循最左前缀原则,将选择性最高的列放在最前面。
同时也要注意索引并非越多越好。每个额外的索引都会增加写入操作的开销,并占用额外的磁盘空间。通过Django的db_index=True或在模型Meta中添加indexes可以方便地管理索引。定期使用EXPLAIN命令分析查询执行计划,可以帮助发现缺少索引的查询。
# Django模型索引定义
class Article(models.Model):
title = models.CharField(max_length=200, db_index=True)
status = models.CharField(max_length=20, db_index=True)
created_at = models.DateTimeField()
class Meta:
indexes = [
models.Index(fields=['status', 'created_at']),
]
# 检查慢查询的SQL执行计划
EXPLAIN SELECT * FROM article
WHERE status = 'published'
ORDER BY created_at DESC
LIMIT 20;
2.3 查询优化技巧
除了使用select_related和prefetch_related外,还有几个重要的查询优化技巧。只查询需要的字段,使用only或defer方法避免加载不必要的大字段(如长文本内容)。values和values_list可以直接返回字典或元组,避免创建完整的模型实例,从而节省内存开销。对于只需要计数的场景,使用count()而非先all()再len(),让数据库完成计数操作。
# 只查询需要的字段
articles = Article.objects.only('id', 'title', 'created_at')
# 直接返回字典,避免模型实例化
data = Article.objects.filter(status='published').values('id', 'title')
# 批量更新,避免逐条操作
Article.objects.filter(status='draft').update(status='published')
2.4 连接池配置
数据库连接池是Web应用与数据库之间的重要性能优化手段。每次建立数据库连接都需要进行TCP握手和身份验证,开销较大。连接池维护一组已建立的连接,应用程序可以复用这些连接,避免频繁创建和销毁的开销。在Django中,CONN_MAX_AGE参数控制数据库连接的最大存活时间。对于高并发应用,建议配置适当的连接池大小:太小会导致请求排队等待连接,太大会耗尽数据库服务器的资源。
# Django数据库连接池配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'CONN_MAX_AGE': 300, # 连接存活300秒
'OPTIONS': {
'pool': {
'min_size': 5,
'max_size': 20,
}
}
}
}
# 使用独立的连接池库(如psycopg2的池)
from psycopg2 import pool
connection_pool = pool.SimpleConnectionPool(
minconn=5, maxconn=20,
host='localhost', database='mydb'
)
2.5 慢查询日志与优化
慢查询日志是发现数据库性能问题的第一道防线。在MySQL中设置long_query_time参数可以记录所有执行时间超过阈值的SQL语句。在PostgreSQL中,通过调整log_min_duration_statement参数实现相同的功能。分析慢查询日志后,使用EXPLAIN ANALYZE命令查看查询的执行计划,重点关注是否存在全表扫描、使用了不合适的索引、或产生了过多的临时表。
三、缓存策略
3.1 多级缓存架构
大型Web应用通常采用多级缓存架构来逐层分担压力。用户请求到达时,首先检查浏览器缓存(强缓存和协商缓存),命中则直接使用本地副本。未命中时请求到达CDN节点,CDN边缘节点缓存的静态资源可以直接返回。如果CDN也未命中,请求到达Nginx反向代理层,Nginx可以缓存部分动态页面和静态文件的响应。请求进入应用层后,应用缓存(如内存缓存或Redis)可以存储数据库查询结果或计算密集型的输出。最后,如果所有缓存都未命中,请求才会落到数据库层。
核心要点: 多级缓存的本质是以空间换时间。越靠近用户的缓存层延迟越低,但存储空间有限且命中率波动大;越靠近数据库的缓存层延迟相对较高,但可以缓存更丰富的数据内容。
3.2 页面缓存
页面缓存是粒度最粗的缓存策略,将整个HTTP响应缓存起来。对于内容不经常变化的页面(如首页、关于我们等),页面缓存可以显著减少服务器的计算开销。在Django中,使用cache_page装饰器可以轻松实现页面级缓存。可以指定缓存超时时间,也可以针对不同用户角色设置不同的缓存策略。
# Django页面级缓存
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 缓存15分钟
def home_view(request):
# 耗时计算...
return render(request, 'home.html', context)
# URL配置中的缓存
from django.views.decorators.cache import cache_page
urlpatterns = [
path('articles/', cache_page(60 * 5)(ArticleListView.as_view())),
]
3.3 查询结果缓存与片段缓存
查询结果缓存比页面缓存粒度更细。当页面上只有部分数据需要频繁更新而其他部分相对稳定时,片段缓存是更合适的方案。在Django模板中,使用cache模板标签可以缓存模板片段。在视图层面,可以手动将耗时的计算结果存入缓存,下次请求时优先从缓存中读取。
# Django模板片段缓存
{% load cache %}
{% cache 600 sidebar %}
{% endcache %}
# 手动查询结果缓存
from django.core.cache import cache
def get_hot_articles():
articles = cache.get('hot_articles')
if articles is None:
articles = Article.objects.filter(
views__gte=1000
).order_by('-created_at')[:10]
cache.set('hot_articles', articles, 300) # 缓存5分钟
return articles
3.4 缓存失效策略
缓存失效是缓存系统中最复杂的问题之一。常用的失效策略包括四种。TTL(Time To Live)策略为每个缓存条目设置过期时间,到期后自动失效,实现简单但可能导致缓存与数据源短暂不一致。主动失效策略在数据更新时主动删除或更新相关缓存,确保数据的一致性,但需要维护缓存键与数据之间的映射关系。写穿透(Write-Through)策略在写入数据库的同时更新缓存,保证缓存与数据库始终一致,但会增加写入延迟。写回(Write-Behind)策略先更新缓存,然后异步写入数据库,具有更好的写入性能,但在异常情况下可能存在数据丢失的风险。
# 主动失效:更新数据时清除相关缓存
def update_article(article_id, data):
article = Article.objects.get(id=article_id)
for key, value in data.items():
setattr(article, key, value)
article.save()
# 清除相关缓存
cache.delete(f'article_detail_{article_id}')
cache.delete('hot_articles')
cache.delete('article_list_page_1')
3.5 Django缓存框架使用
Django提供了抽象统一的缓存框架,支持多种后端切换而无需修改业务代码。可以通过settings.py中的CACHES配置选择使用本地内存缓存、文件缓存、数据库缓存或Redis缓存。生产环境推荐使用Redis作为缓存后端,通过django-redis或django.core.cache.backends.redis.RedisCache(Django 4.0+内置)进行集成。
# settings.py - Django缓存配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'TIMEOUT': 300,
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PARSER_CLASS': 'redis.connection.HiredisParser',
'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
'CONNECTION_POOL_CLASS_KWARGS': {
'max_connections': 50,
'timeout': 20,
},
'MAX_CONNECTIONS': 1000,
'PICKLE_VERSION': -1,
},
},
'session': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/2',
'TIMEOUT': 86400,
}
}
四、Redis缓存应用
4.1 热门数据缓存
Redis是生产环境中最常用的缓存后端,其基于内存的数据存储特性使得读写速度极快(通常在微秒级别)。热门数据缓存是Redis最典型的应用场景——将频繁访问但更新不频繁的数据存储在Redis中。例如,网站的导航菜单、配置信息、分类列表等全局数据,可以一次性加载到Redis中。对于需要排序的热门数据,Redis的有序集合(Sorted Set)可以在O(log N)的时间复杂度内完成插入和排名查询。
# 使用Redis缓存热门文章排行榜
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 增加文章阅读量并维护排行榜
def record_article_view(article_id):
r.zincrby('hot_articles_ranking', 1, article_id)
r.zincrby('daily_hot_articles', 1, f"{article_id}:{date.today()}")
# 获取热门文章TOP10
def get_hot_articles_top10():
article_ids = r.zrevrange('hot_articles_ranking', 0, 9)
return [get_article_detail(aid) for aid in article_ids]
4.2 Session集中存储
在水平扩展的架构中,用户的Session信息不能存储在某台服务器的内存中,因为下次请求可能被负载均衡转发到另一台服务器。Redis作为集中式Session存储是广泛使用的解决方案。Django默认支持将Session存储到Redis中,只需将SESSION_ENGINE指向Redis缓存后端即可。Redis的过期特性天然适合Session管理——用户在设定的时间内不活动,Session自动过期释放内存。
# settings.py - Redis Session存储
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'session' # 使用独立的session缓存配置
SESSION_COOKIE_AGE = 86400 * 7 # Session有效期7天
SESSION_SAVE_EVERY_REQUEST = True # 每次请求都刷新过期时间
4.3 API响应缓存
对于返回结果相对稳定的API接口,使用Redis缓存响应结果可以大幅降低响应时间和服务端负载。API缓存的关键在于合理设置缓存键。缓存键通常包含请求路径、查询参数、用户身份等信息。对于分页数据,缓存键需要包含页码和每页数量。缓存API响应时需要特别注意用户权限问题——不同角色的用户可能看到不同的数据,缓存键中需要区分用户角色或干脆不对需要权限控制的数据做全量缓存。
# API响应缓存中间件
from django.core.cache import cache
from django.utils.cache import get_cache_key
class APICacheMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.method != 'GET':
return self.get_response(request)
cache_key = f"api_cache:{request.get_full_path()}"
response = cache.get(cache_key)
if response is None:
response = self.get_response(request)
if response.status_code == 200:
cache.set(cache_key, response, 60)
return response
4.4 页面片段缓存
除了整个页面或查询结果的缓存,Redis还可以用于缓存页面中的特定片段。在Django中,可以通过自定义模板标签将页面的复杂部分(如侧边栏、推荐内容、热门标签云等)缓存到Redis中。片段缓存的粒度介于页面缓存和对象缓存之间,灵活性较高。
4.5 缓存预热
缓存预热是指系统启动或发布新版本时,主动将热点数据加载到缓存中的过程。未经预热的缓存系统在刚启动时命中率为零,大量请求直接穿透到数据库,可能导致数据库过载甚至崩溃(缓存雪崩)。缓存预热的实现方式可以是在应用启动时执行一个初始化脚本,从数据库加载核心数据写入Redis,也可以编写一个定时任务定时刷新缓存。
# 缓存预热脚本
def warm_up_cache():
"""应用启动时预热核心缓存"""
# 预热配置信息
configs = SystemConfig.objects.all()
for config in configs:
cache.set(f'config:{config.key}', config.value, timeout=86400)
# 预热热门文章
hot_articles = Article.objects.filter(
status='published'
).order_by('-views')[:100]
for article in hot_articles:
cache.set(f'article:{article.id}', article, timeout=3600)
# 预热分类导航
categories = Category.objects.prefetch_related('children').all()
cache.set('nav_categories', categories, timeout=3600)
logger.info(f"缓存预热完成: {len(configs)} 配置, "
f"{len(hot_articles)} 文章, {len(categories)} 分类")
五、代码层优化
5.1 减少数据库查询次数
每次数据库查询都有网络往返和SQL解析的开销,因此减少查询次数是性能优化的基本策略。除了前面提到的select_related和prefetch_related,还可以使用批量操作来合并多次查询。例如,通过IN查询代替逐条查询,通过update批量更新代替循环更新。在ORM层面,Django的bulk_create和bulk_update可以显著提升批量数据操作的性能。
# 批量创建 vs 逐条创建
# 慢:每次save()都执行一次INSERT
for i in range(1000):
Article.objects.create(title=f'Article {i}')
# 快:仅执行一次批量INSERT
articles = [Article(title=f'Article {i}') for i in range(1000)]
Article.objects.bulk_create(articles, batch_size=100)
# 批量更新
articles = Article.objects.filter(status='draft')
Article.objects.filter(id__in=articles.values('id')).update(status='published')
5.2 懒加载与预加载
懒加载(Lazy Loading)的核心思想是"按需加载"——只有当真正需要某个数据时才去获取它。在Django的QuerySet中,查询是惰性执行的,只有在迭代、切片或访问数据时才会真正执行SQL语句。开发者可以灵活地组合过滤条件,最后才执行查询。预加载(Eager Loading)则相反,在一次查询中尽可能加载后续会用到的关联数据。在开发中,需要根据具体场景在两者之间做出选择:对于关系型数据的列表展示,预加载更合适;对于详情页中某些可能不需要展示的深层关联数据,懒加载更节省资源。
5.3 异步任务队列(Celery)
Web请求处理中应当只包含与当前请求直接相关的核心逻辑。对于耗时的非核心操作(如发送邮件、生成缩略图、数据报表计算等),应将其放入异步任务队列中处理,让HTTP请求尽快返回。Celery是Python中最流行的分布式任务队列,与Redis或RabbitMQ配合使用。Celery Beat是Celery的定时任务调度器,可以像Linux的cron一样定期执行任务。
# Celery配置与任务定义
from celery import Celery
app = Celery('myproject',
broker='redis://localhost:6379/0',
backend='redis://localhost:6379/1')
@app.task
def send_welcome_email(user_id):
user = User.objects.get(id=user_id)
# 执行邮件发送
mail_service.send(user.email, 'Welcome!')
@app.task
def generate_report():
# 耗时报表生成
data = collect_data()
report = build_report(data)
save_report(report)
# 在视图中异步调用
def user_register(request):
user = create_user(request.POST)
send_welcome_email.delay(user.id) # 异步执行
return HttpResponse('注册成功')
5.4 循环中避免查询
在循环中执行数据库查询是性能问题的重大隐患。如果循环的每次迭代都触发数据库查询,随着数据量增长,性能会呈线性甚至指数级下降。解决方案是:尽可能将循环内的查询提取到循环外部,通过一次查询获取所有需要的数据,然后在内存中进行关联。使用Python的字典进行数据归并可以在O(1)时间内完成数据查找。
# 错误的做法:循环内查询
article_ids = [1, 2, 3, 4, 5]
for aid in article_ids:
article = Article.objects.get(id=aid) # 5次查询
print(article.title)
# 正确的做法:一次查询获取全部
articles = Article.objects.filter(id__in=article_ids) # 1次查询
article_map = {a.id: a for a in articles}
for aid in article_ids:
article = article_map.get(aid)
print(article.title)
5.5 使用生成器处理大数据
当需要处理大量数据时(如导出数十万条记录),将所有数据一次性加载到内存中可能导致MemoryError。此时应该使用生成器(Generator)逐条处理数据。Django的iterator()方法可以将QuerySet转换为生成器,每次从数据库获取一批数据(默认2000条),处理完后释放内存再获取下一批。对于文件处理,使用with open()和逐行读取的方式也能有效控制内存使用。
# 使用iterator()处理大数据集
def export_articles_csv():
import csv
with open('articles.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['ID', 'Title', 'Created'])
# iterator()逐批从数据库读取,不会一次性加载到内存
for article in Article.objects.all().iterator(chunk_size=5000):
writer.writerow([article.id, article.title, article.created_at])
六、并发与异步
6.1 异步任务处理
Celery与Redis的组合是Python生态中最成熟的异步任务处理方案。Celery Worker作为独立进程运行,从Redis(或RabbitMQ)中获取任务并执行。任务执行结果可以存储在后端(如Redis、数据库)中供主进程查询。Celery支持多种任务模式:异步任务(Async Task)立即放入队列执行;定时任务(Periodic Task)按照cron表达式定期执行;链式任务(Canvas)将多个任务按特定顺序编排执行。
# 更完整的Celery项目结构
# tasks.py
from celery import Celery
from celery.schedules import crontab
app = Celery('myproject')
app.config_from_object('celeryconfig')
# 定时任务配置
app.conf.beat_schedule = {
'clean-expired-sessions': {
'task': 'tasks.clean_expired_sessions',
'schedule': crontab(hour=3, minute=0), # 每天凌晨3点执行
},
'generate-daily-report': {
'task': 'tasks.generate_daily_report',
'schedule': crontab(hour=23, minute=59), # 每天23:59执行
},
}
@app.task
def clean_expired_sessions():
Session.objects.filter(expire_at__lt=timezone.now()).delete()
6.2 Gunicorn Worker优化
Gunicorn是Python Web应用最常用的WSGI服务器。Worker类型的选择对性能影响显著。同步Worker(sync)是最简单的方式,每个Worker一次处理一个请求,适合CPU密集型任务。异步Worker(gevent或uvicorn)使用协程或事件循环,适合I/O密集型任务。Worker数量的设置遵循一个经验公式:Worker数 = 2 * CPU核心数 + 1。对于内存消耗较大的应用,需要适当减少Worker数量以避免内存溢出。
# Gunicorn配置示例
# gunicorn.conf.py
import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "gevent" # 使用gevent异步Worker
worker_connections = 1000
timeout = 30
max_requests = 1000 # Worker处理1000个请求后重启,防止内存泄漏
max_requests_jitter = 100 # 随机抖动避免Worker同时重启
# 启动命令
# gunicorn myproject.wsgi:application -c gunicorn.conf.py
6.3 水平扩展
当单台服务器无法满足性能需求时,水平扩展是最终的解决方案。水平扩展的核心思想是将负载分散到多台服务器上。应用服务器可以通过负载均衡器(如Nginx、HAProxy)实现水平扩展。对于数据库的水平扩展,可以采用读写分离(主库写入、从库读取)和分库分表策略。Session集中存储到Redis后,水平扩展的应用服务器无需关心用户的Session在哪台机器上。需要注意的是,水平扩展并非万能药,它增加了系统的复杂度和运维成本,并且随着节点数量的增加,边际收益递减。
七、CDN与静态文件优化
7.1 CDN加速原理
CDN(内容分发网络)将源站的静态资源缓存到分布在全球各地的边缘节点上。当用户请求资源时,CDN通过DNS解析将用户引导至最接近的边缘节点,从而显著减少网络延迟。CDN不仅可以加速静态资源的加载速度,还能减轻源站服务器的负载。对于Python Web应用,常见的CDN加速对象包括CSS、JavaScript、图片和字体文件等静态资源,以及部分适合缓存的动态内容。
7.2 静态文件版本管理
浏览器缓存会存储已加载的静态文件,但文件更新后浏览器无法自动感知。为解决这个问题,需要在文件名中加入版本标识。Django的ManifestStaticFilesStorage会在collectstatic时自动为静态文件生成基于内容的哈希文件名。当文件内容变化时,哈希值随之变化,浏览器加载新的文件名从而绕过缓存。
# settings.py - 静态文件版本管理
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# 模板中使用static标签自动获得带哈希的URL
{% load static %}
7.3 文件压缩
对传输内容进行压缩是减少网络传输量的最有效手段。Gzip是应用最广泛的压缩方案,几乎所有浏览器和服务器都支持。Brotli是Google开发的更高效的压缩算法,在压缩率上比Gzip高出约20%。在Nginx中启用Gzip或Brotli压缩通常只需要几行配置。对于Django应用,django-gzip-middleware或Whitenoise可以帮助在应用层面启用压缩。自Gunicorn后端的压缩通常在Nginx反向代理层完成,而非应用本身。
# Nginx启用Gzip压缩
gzip on;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml text/javascript image/svg+xml;
gzip_vary on;
gzip_proxied any;
# Nginx启用Brotli压缩(需安装brotli模块)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript;
7.4 图片优化
图片通常是网页中体积最大的资源。优化图片加载可以显著提升页面性能。关键策略包括使用WebP或AVIF等现代图片格式替代传统的JPEG和PNG,大幅减少文件体积;通过srcset属性为不同设备分辨率提供不同尺寸的图片;延迟加载(Lazy Loading)屏幕外的图片,使用loading="lazy"属性让浏览器自动处理;对于图标类图形,使用SVG格式或CSS Sprite合并为一张大图减少HTTP请求次数。
# 图片延迟加载与响应式
<img
src="thumbnail.jpg"
data-src="fullsize.jpg"
srcset="small.jpg 480w, medium.jpg 768w, large.jpg 1200w"
sizes="(max-width: 480px) 100vw, (max-width: 768px) 50vw, 33vw"
loading="lazy"
alt="示例图片"
class="lazyload">
# Django中使用sorl-thumbnail或easy_thumbnails自动生成缩略图
from sorl.thumbnail import get_thumbnail
thumbnail = get_thumbnail(image_file, '200x200', crop='center', quality=85)
print(thumbnail.url) # 输出缩略图URL
核心要点总结: 后端性能优化是一个系统性的工程,没有银弹。正确的做法是从架构层面做好分层缓存设计,在数据库层面优化查询和索引,在代码层面减少不必要的计算和数据库交互,在部署层面合理配置Worker和CDN。始终遵循"先测量,再优化"的原则,避免在没有数据支持的情况下盲目优化。