FastAPI+Celery+Redis 分布式任务调度:搭建微服务任务调度平台

FastAPI+Celery+Redis 分布式任务调度:搭建微服务任务调度平台

最近在做一个微服务项目的时候,遇到了一个挺头疼的问题:用户上传一个大文件后,后端需要做解析、清洗、入库等一系列操作,整个过程可能要好几分钟。如果让用户在页面上干等着,体验肯定很差,而且还容易超时。

一开始我用了 FastAPI 自带的BackgroundTasks,确实能解决简单的异步问题,但后来发现几个痛点:任务没法持久化,服务重启就丢了;不支持分布式,多实例部署的时候任务可能重复执行;也没有任务状态追踪,用户想查进度都查不了。

折腾了一圈,最后还是上了 Celery+Redis 的经典组合。用了一段时间感觉真香,今天就把整个搭建过程和踩过的坑整理出来,希望能帮到有同样需求的朋友。

技术选型说明

先简单说下为什么选这三个组合:

FastAPI不用多说了,现在 Python Web 框架里的当红炸子鸡,性能好、自动生成 API 文档、类型提示舒服,写接口效率特别高。

Celery是 Python 生态里最成熟的分布式任务队列,支持任务重试、定时任务、任务状态追踪这些企业级特性,生产环境用着放心。

Redis在这里扮演两个角色:一是作为 Celery 的消息代理(Broker),负责存任务队列;二是作为结果后端(Backend),存任务执行结果。Redis 性能高,部署简单,中小型项目用它完全够用。

环境准备

先把依赖装上,我这里用的是 Python 3.10 版本:

bash

pip install fastapi uvicorn celery redis python-multipart

Redis 的话本地装一个就行,或者用 Docker 更方便:

bash

docker run -d -p 6379:6379 --name redis redis:latest

项目结构

我一般习惯把项目拆成这样的结构,清晰一点:

plaintext

task_scheduler/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI入口 │ ├── celery_app.py # Celery配置 │ ├── tasks/ # 任务定义 │ │ ├── __init__.py │ │ └── worker_tasks.py │ └── api/ # 接口 │ ├── __init__.py │ └── task_api.py └── requirements.txt

核心代码实现

1. Celery 配置

先写 Celery 的配置文件,这里有几个坑后面会说:

python

运行

# app/celery_app.py from celery import Celery from celery.schedules import crontab # Redis连接地址,生产环境建议用配置文件管理 REDIS_URL = "redis://localhost:6379/0" # 创建Celery实例 celery_app = Celery( "task_scheduler", broker=REDIS_URL, backend=REDIS_URL, include=["app.tasks.worker_tasks"] ) # 配置项 celery_app.conf.update( # 任务序列化方式 task_serializer="json", result_serializer="json", accept_content=["json"], # 时区设置,这个很重要,不然定时任务时间不对 timezone="Asia/Shanghai", enable_utc=False, # 任务结果过期时间,24小时自动清理,防止Redis内存爆了 result_expires=3600 * 24, # 任务重试相关配置 task_acks_late=True, task_reject_on_worker_lost=True, # 并发数,根据机器配置调 worker_concurrency=4, # 定时任务配置,这里举个例子 beat_schedule={ "daily_cleanup": { "task": "app.tasks.worker_tasks.daily_cleanup", "schedule": crontab(hour=2, minute=0), # 每天凌晨2点执行 }, } )

2. 任务定义

然后是具体的任务实现,我写了几个常用的例子:

python

运行

# app/tasks/worker_tasks.py import time import random from app.celery_app import celery_app from celery import shared_task # 用装饰器注册任务,name最好写全路径,避免冲突 @celery_app.task(name="app.tasks.worker_tasks.send_email", bind=True, max_retries=3) def send_email(self, to_email: str, subject: str, content: str): """ 模拟发送邮件的异步任务 bind=True可以获取self,用于重试等操作 max_retries=3最多重试3次 """ try: print(f"开始发送邮件到: {to_email}") # 模拟发送邮件耗时 time.sleep(2) # 模拟偶尔失败的情况,实际项目中可以去掉 if random.random() < 0.1: raise Exception("邮件服务暂时不可用") print(f"邮件发送成功: {subject}") return {"status": "success", "email": to_email} except Exception as e: print(f"发送邮件失败,准备重试: {str(e)}") # 重试,每次间隔指数增长 self.retry(exc=e, countdown=2 ** self.request.retries) @celery_app.task(name="app.tasks.worker_tasks.process_file") def process_file(file_path: str, file_type: str): """ 处理文件的耗时任务,比如解析Excel、生成报表等 """ print(f"开始处理文件: {file_path}") # 模拟文件处理进度 total_steps = 10 for i in range(total_steps): time.sleep(0.5) progress = int((i + 1) / total_steps * 100) # 更新任务状态和进度,前端可以轮询获取 process_file.update_state( state="PROGRESS", meta={"current": i + 1, "total": total_steps, "progress": progress} ) print(f"文件处理完成: {file_path}") return { "status": "success", "file_path": file_path, "file_type": file_type, "result": "处理完成,共处理1000条数据" } @celery_app.task(name="app.tasks.worker_tasks.daily_cleanup") def daily_cleanup(): """ 定时任务:每天清理过期数据 """ print("开始执行每日清理任务...") time.sleep(1) print("每日清理任务执行完成") return {"status": "success", "cleaned_count": 100}

3. FastAPI 接口

接下来写 FastAPI 的接口,提供任务提交、状态查询这些功能:

python

运行

# app/api/task_api.py from fastapi import APIRouter, HTTPException from pydantic import BaseModel from celery.result import AsyncResult from app.tasks.worker_tasks import send_email, process_file router = APIRouter(prefix="/api/tasks", tags=["任务管理"]) class EmailTaskRequest(BaseModel): to_email: str subject: str content: str class FileTaskRequest(BaseModel): file_path: str file_type: str = "excel" @router.post("/email", summary="提交发送邮件任务") async def submit_email_task(request: EmailTaskRequest): """提交异步发送邮件任务""" # delay()方法提交任务,立即返回task_id task = send_email.delay(request.to_email, request.subject, request.content) return { "task_id": task.id, "status": "PENDING", "message": "邮件任务已提交,后台处理中" } @router.post("/file", summary="提交文件处理任务") async def submit_file_task(request: FileTaskRequest): """提交文件处理任务""" task = process_file.delay(request.file_path, request.file_type) return { "task_id": task.id, "status": "PENDING", "message": "文件处理任务已提交" } @router.get("/{task_id}", summary="查询任务状态") async def get_task_status(task_id: str): """根据任务ID查询任务执行状态和结果""" task_result = AsyncResult(task_id) result = { "task_id": task_id, "status": task_result.status, "ready": task_result.ready() } # 如果任务执行成功,返回结果 if task_result.successful(): result["result"] = task_result.result # 如果任务失败,返回错误信息 elif task_result.failed(): result["error"] = str(task_result.result) # 如果任务执行中,返回进度信息 elif task_result.status == "PROGRESS": result["progress"] = task_result.info return result @router.post("/{task_id}/retry", summary="重试失败任务") async def retry_task(task_id: str): """手动重试失败的任务""" task_result = AsyncResult(task_id) if not task_result.failed(): raise HTTPException(status_code=400, detail="只有失败的任务才能重试") # 重新提交任务 # 注意:这里需要知道原来的任务名和参数,实际项目中可以存在数据库里 # 这里简化处理,实际使用时建议存任务日志表 raise HTTPException(status_code=501, detail="请根据业务场景实现重试逻辑")

4. 主入口文件

最后是 FastAPI 的入口:

python

运行

# app/main.py from fastapi import FastAPI from app.api.task_api import router as task_router app = FastAPI( title="分布式任务调度平台", description="基于FastAPI+Celery+Redis的微服务任务调度系统", version="1.0.0" ) # 注册路由 app.include_router(task_router) @app.get("/", summary="健康检查") async def root(): return { "message": "任务调度平台运行中", "status": "healthy", "docs": "/docs" } if __name__ == "__main__": import uvicorn uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)

启动与测试

启动服务

需要分别启动 FastAPI 和 Celery Worker:

bash

# 启动FastAPI服务 uvicorn app.main:app --reload # 启动Celery Worker(另开一个终端) celery -A app.celery_app worker --loglevel=info # 如果要用定时任务,还要启动Beat(再开一个终端) celery -A app.celery_app beat --loglevel=info

测试接口

启动后访问http://localhost:8000/docs就能看到自动生成的 Swagger 文档,可以直接在页面上测试接口。

提交一个邮件任务试试:

bash

curl -X POST "http://localhost:8000/api/tasks/email" \ -H "Content-Type: application/json" \ -d '{ "to_email": "test@example.com", "subject": "测试邮件", "content": "这是一封测试邮件" }'

返回结果里会有task_id,用这个 ID 去查状态:

bash

curl "http://localhost:8000/api/tasks/你的task_id"

踩过的坑和优化建议

用了这么久 Celery,踩过的坑真不少,给大家提个醒:

1. 时区问题

这个坑我踩过好几次!默认 Celery 用 UTC 时间,如果不配置时区,定时任务执行时间永远不对。一定要加上:

python

运行

timezone="Asia/Shanghai", enable_utc=False,

2. 任务结果不清理

默认任务结果会一直存在 Redis 里,时间长了 Redis 内存会爆。一定要设置result_expires,或者定期清理。

3. 任务参数不能太大

Celery 的任务参数是存在 Redis 里的,别传太大的对象,比如整个文件内容。建议传文件路径、ID 这些小数据,任务里自己去查。

4. Worker 进程和 API 进程隔离

Celery 任务是在独立的 Worker 进程里执行的,和 FastAPI 的请求进程完全分开。所以别想着在任务里直接用 FastAPI 的依赖注入、数据库连接这些,任务里需要的东西都得自己初始化。

5. 生产环境建议

  • 用 Supervisor 或者 Systemd 管理 Celery 进程,防止挂了
  • Redis 建议开持久化,避免重启丢任务
  • 任务执行日志要收集好,出问题好排查
  • 重要任务建议加幂等性处理,防止重复执行
  • 任务多的话可以考虑用 RabbitMQ 替代 Redis 做 Broker,性能更好

6. 监控方案

可以用 Flower 这个工具监控 Celery 任务状态,装一下就能用:

bash

pip install flower celery -A app.celery_app flower --port=5555

然后访问http://localhost:5555就能看到任务执行情况、Worker 状态这些,挺方便的。

总结

FastAPI+Celery+Redis 这套组合,搭建一个分布式任务调度平台其实挺简单的,核心代码也就几十行。但真正用到生产环境,还是有很多细节要注意。

这套方案适合大多数中小型项目的异步任务场景,比如发邮件、发短信、文件处理、数据同步、定时报表这些。如果是超大规模的任务调度,可能就要考虑更专业的方案了,比如 XXL-JOB、Airflow 这些。

今天先分享到这里,后面有时间再写写 Celery 的高级用法,比如任务链、任务组、工作流这些。有问题欢迎评论区交流~WWw.Share.01km.cN/Article/details/67921.sHtML
WWw.Share.01km.cN/Article/details/17246.sHtML
WWw.Share.01km.cN/Article/details/80533.sHtML
WWw.Share.01km.cN/Article/details/80357.sHtML
WWw.Share.01km.cN/Article/details/88756.sHtML
WWw.Share.01km.cN/Article/details/89096.sHtML
WWw.Share.01km.cN/Article/details/18478.sHtML
WWw.Share.01km.cN/Article/details/72023.sHtML
WWw.Share.01km.cN/Article/details/17305.sHtML
WWw.Share.01km.cN/Article/details/80390.sHtML
WWw.Share.01km.cN/Article/details/87322.sHtML
WWw.Share.01km.cN/Article/details/17132.sHtML
WWw.Share.01km.cN/Article/details/82912.sHtML
WWw.Share.01km.cN/Article/details/83533.sHtML
WWw.Share.01km.cN/Article/details/38747.sHtML
WWw.Share.01km.cN/Article/details/97432.sHtML
WWw.Share.01km.cN/Article/details/25570.sHtML
WWw.Share.01km.cN/Article/details/73235.sHtML
WWw.Share.01km.cN/Article/details/84224.sHtML
WWw.Share.01km.cN/Article/details/16128.sHtML
WWw.Share.01km.cN/Article/details/13873.sHtML
WWw.Share.01km.cN/Article/details/06329.sHtML
WWw.Share.01km.cN/Article/details/38163.sHtML
WWw.Share.01km.cN/Article/details/83191.sHtML
WWw.Share.01km.cN/Article/details/89205.sHtML
WWw.Share.01km.cN/Article/details/90586.sHtML
WWw.Share.01km.cN/Article/details/05760.sHtML
WWw.Share.01km.cN/Article/details/47696.sHtML
WWw.Share.01km.cN/Article/details/80240.sHtML
WWw.Share.01km.cN/Article/details/78229.sHtML
WWw.Share.01km.cN/Article/details/82842.sHtML
WWw.Share.01km.cN/Article/details/28376.sHtML
WWw.Share.01km.cN/Article/details/34009.sHtML
WWw.Share.01km.cN/Article/details/03390.sHtML
WWw.Share.01km.cN/Article/details/57818.sHtML
WWw.Share.01km.cN/Article/details/15662.sHtML
WWw.Share.01km.cN/Article/details/96022.sHtML
WWw.Share.01km.cN/Article/details/90877.sHtML
WWw.Share.01km.cN/Article/details/83050.sHtML
WWw.Share.01km.cN/Article/details/74625.sHtML
WWw.Share.01km.cN/Article/details/22532.sHtML
WWw.Share.01km.cN/Article/details/76648.sHtML
WWw.Share.01km.cN/Article/details/01353.sHtML
WWw.Share.01km.cN/Article/details/32117.sHtML
WWw.Share.01km.cN/Article/details/26118.sHtML
WWw.Share.01km.cN/Article/details/12363.sHtML
WWw.Share.01km.cN/Article/details/69003.sHtML
WWw.Share.01km.cN/Article/details/94124.sHtML
WWw.Share.01km.cN/Article/details/41603.sHtML
WWw.Share.01km.cN/Article/details/89045.sHtML
WWw.Share.01km.cN/Article/details/87009.sHtML
WWw.Share.01km.cN/Article/details/73759.sHtML
WWw.Share.01km.cN/Article/details/06496.sHtML
WWw.Share.01km.cN/Article/details/11330.sHtML
WWw.Share.01km.cN/Article/details/59897.sHtML
WWw.Share.01km.cN/Article/details/93307.sHtML
WWw.Share.01km.cN/Article/details/44814.sHtML
WWw.Share.01km.cN/Article/details/24303.sHtML
WWw.Share.01km.cN/Article/details/15146.sHtML
WWw.Share.01km.cN/Article/details/80900.sHtML
WWw.Share.01km.cN/Article/details/15037.sHtML
WWw.Share.01km.cN/Article/details/82415.sHtML
WWw.Share.01km.cN/Article/details/62833.sHtML
WWw.Share.01km.cN/Article/details/97625.sHtML
WWw.Share.01km.cN/Article/details/21995.sHtML
WWw.Share.01km.cN/Article/details/59694.sHtML
WWw.Share.01km.cN/Article/details/32471.sHtML
WWw.Share.01km.cN/Article/details/52888.sHtML
WWw.Share.01km.cN/Article/details/49909.sHtML
WWw.Share.01km.cN/Article/details/88739.sHtML
WWw.Share.01km.cN/Article/details/91593.sHtML
WWw.Share.01km.cN/Article/details/40127.sHtML
WWw.Share.01km.cN/Article/details/31929.sHtML
WWw.Share.01km.cN/Article/details/01847.sHtML
WWw.Share.01km.cN/Article/details/67594.sHtML
WWw.Share.01km.cN/Article/details/05348.sHtML
WWw.Share.01km.cN/Article/details/53816.sHtML
WWw.Share.01km.cN/Article/details/99164.sHtML
WWw.Share.01km.cN/Article/details/48060.sHtML
WWw.Share.01km.cN/Article/details/00653.sHtML
WWw.Share.01km.cN/Article/details/26933.sHtML
WWw.Share.01km.cN/Article/details/25256.sHtML
WWw.Share.01km.cN/Article/details/31279.sHtML
WWw.Share.01km.cN/Article/details/55978.sHtML
WWw.Share.01km.cN/Article/details/08597.sHtML
WWw.Share.01km.cN/Article/details/52959.sHtML
WWw.Share.01km.cN/Article/details/31872.sHtML
WWw.Share.01km.cN/Article/details/24227.sHtML
WWw.Share.01km.cN/Article/details/19110.sHtML
WWw.Share.01km.cN/Article/details/56637.sHtML
WWw.Share.01km.cN/Article/details/60580.sHtML
WWw.Share.01km.cN/Article/details/09526.sHtML
WWw.Share.01km.cN/Article/details/80946.sHtML
WWw.Share.01km.cN/Article/details/78311.sHtML
WWw.Share.01km.cN/Article/details/09357.sHtML
WWw.Share.01km.cN/Article/details/07471.sHtML
WWw.Share.01km.cN/Article/details/39214.sHtML
WWw.Share.01km.cN/Article/details/15756.sHtML
WWw.Share.01km.cN/Article/details/66148.sHtML
WWw.Share.01km.cN/Article/details/58256.sHtML
WWw.Share.01km.cN/Article/details/59601.sHtML
WWw.Share.01km.cN/Article/details/07314.sHtML
WWw.Share.01km.cN/Article/details/15761.sHtML
WWw.Share.01km.cN/Article/details/05040.sHtML
WWw.Share.01km.cN/Article/details/69249.sHtML
WWw.Share.01km.cN/Article/details/40670.sHtML
WWw.Share.01km.cN/Article/details/10244.sHtML
WWw.Share.01km.cN/Article/details/78614.sHtML
WWw.Share.01km.cN/Article/details/44885.sHtML
WWw.Share.01km.cN/Article/details/20282.sHtML
WWw.Share.01km.cN/Article/details/14961.sHtML
WWw.Share.01km.cN/Article/details/36970.sHtML
WWw.Share.01km.cN/Article/details/04330.sHtML
WWw.Share.01km.cN/Article/details/60161.sHtML
WWw.Share.01km.cN/Article/details/30761.sHtML
WWw.Share.01km.cN/Article/details/92499.sHtML
WWw.Share.01km.cN/Article/details/78582.sHtML
WWw.Share.01km.cN/Article/details/95277.sHtML
WWw.Share.01km.cN/Article/details/81420.sHtML
WWw.Share.01km.cN/Article/details/91368.sHtML
WWw.Share.01km.cN/Article/details/46368.sHtML
WWw.Share.01km.cN/Article/details/84920.sHtML
WWw.Share.01km.cN/Article/details/88467.sHtML
WWw.Share.01km.cN/Article/details/56923.sHtML
WWw.Share.01km.cN/Article/details/61264.sHtML
WWw.Share.01km.cN/Article/details/91783.sHtML
WWw.Share.01km.cN/Article/details/70368.sHtML
WWw.Share.01km.cN/Article/details/58626.sHtML
WWw.Share.01km.cN/Article/details/96799.sHtML
WWw.Share.01km.cN/Article/details/77593.sHtML
WWw.Share.01km.cN/Article/details/02078.sHtML
WWw.Share.01km.cN/Article/details/37820.sHtML
WWw.Share.01km.cN/Article/details/18261.sHtML
WWw.Share.01km.cN/Article/details/00856.sHtML
WWw.Share.01km.cN/Article/details/29988.sHtML
WWw.Share.01km.cN/Article/details/70614.sHtML
WWw.Share.01km.cN/Article/details/32925.sHtML
WWw.Share.01km.cN/Article/details/50379.sHtML
WWw.Share.01km.cN/Article/details/31857.sHtML
WWw.Share.01km.cN/Article/details/25191.sHtML
WWw.Share.01km.cN/Article/details/14283.sHtML
WWw.Share.01km.cN/Article/details/67414.sHtML
WWw.Share.01km.cN/Article/details/63682.sHtML
WWw.Share.01km.cN/Article/details/98281.sHtML
WWw.Share.01km.cN/Article/details/26396.sHtML
WWw.Share.01km.cN/Article/details/30731.sHtML
WWw.Share.01km.cN/Article/details/71299.sHtML
WWw.Share.01km.cN/Article/details/02708.sHtML
WWw.Share.01km.cN/Article/details/75917.sHtML
WWw.Share.01km.cN/Article/details/20485.sHtML
WWw.Share.01km.cN/Article/details/47162.sHtML
WWw.Share.01km.cN/Article/details/42432.sHtML
WWw.Share.01km.cN/Article/details/24122.sHtML
WWw.Share.01km.cN/Article/details/71411.sHtML
WWw.Share.01km.cN/Article/details/98353.sHtML
WWw.Share.01km.cN/Article/details/29325.sHtML
WWw.Share.01km.cN/Article/details/85679.sHtML
WWw.Share.01km.cN/Article/details/59465.sHtML
WWw.Share.01km.cN/Article/details/90655.sHtML
WWw.Share.01km.cN/Article/details/51804.sHtML
WWw.Share.01km.cN/Article/details/71758.sHtML
WWw.Share.01km.cN/Article/details/38165.sHtML
WWw.Share.01km.cN/Article/details/00583.sHtML
WWw.Share.01km.cN/Article/details/40399.sHtML
WWw.Share.01km.cN/Article/details/54909.sHtML
WWw.Share.01km.cN/Article/details/96900.sHtML
WWw.Share.01km.cN/Article/details/19768.sHtML
WWw.Share.01km.cN/Article/details/38424.sHtML
WWw.Share.01km.cN/Article/details/66033.sHtML
WWw.Share.01km.cN/Article/details/34198.sHtML
WWw.Share.01km.cN/Article/details/91989.sHtML
WWw.Share.01km.cN/Article/details/57002.sHtML
WWw.Share.01km.cN/Article/details/30910.sHtML
WWw.Share.01km.cN/Article/details/80987.sHtML
WWw.Share.01km.cN/Article/details/14841.sHtML
WWw.Share.01km.cN/Article/details/91914.sHtML
WWw.Share.01km.cN/Article/details/78192.sHtML
WWw.Share.01km.cN/Article/details/93741.sHtML
WWw.Share.01km.cN/Article/details/72375.sHtML
WWw.Share.01km.cN/Article/details/09363.sHtML
WWw.Share.01km.cN/Article/details/86819.sHtML
WWw.Share.01km.cN/Article/details/75257.sHtML
WWw.Share.01km.cN/Article/details/76599.sHtML
WWw.Share.01km.cN/Article/details/25955.sHtML
WWw.Share.01km.cN/Article/details/58879.sHtML
WWw.Share.01km.cN/Article/details/81953.sHtML
WWw.Share.01km.cN/Article/details/61749.sHtML
WWw.Share.01km.cN/Article/details/79700.sHtML
WWw.Share.01km.cN/Article/details/68930.sHtML
WWw.Share.01km.cN/Article/details/79923.sHtML
WWw.Share.01km.cN/Article/details/76108.sHtML
WWw.Share.01km.cN/Article/details/42482.sHtML
WWw.Share.01km.cN/Article/details/25469.sHtML
WWw.Share.01km.cN/Article/details/88779.sHtML
WWw.Share.01km.cN/Article/details/43982.sHtML
WWw.Share.01km.cN/Article/details/04295.sHtML
WWw.Share.01km.cN/Article/details/74478.sHtML
WWw.Share.01km.cN/Article/details/05563.sHtML
WWw.Share.01km.cN/Article/details/15255.sHtML
WWw.Share.01km.cN/Article/details/68289.sHtML
WWw.Share.01km.cN/Article/details/74953.sHtML
WWw.Share.01km.cN/Article/details/63879.sHtML
WWw.Share.01km.cN/Article/details/50692.sHtML
WWw.Share.01km.cN/Article/details/87270.sHtML
WWw.Share.01km.cN/Article/details/14939.sHtML
WWw.Share.01km.cN/Article/details/28142.sHtML
WWw.Share.01km.cN/Article/details/83705.sHtML
WWw.Share.01km.cN/Article/details/51244.sHtML
WWw.Share.01km.cN/Article/details/86767.sHtML
WWw.Share.01km.cN/Article/details/31385.sHtML
WWw.Share.01km.cN/Article/details/75236.sHtML
WWw.Share.01km.cN/Article/details/72608.sHtML
WWw.Share.01km.cN/Article/details/94974.sHtML
WWw.Share.01km.cN/Article/details/87337.sHtML
WWw.Share.01km.cN/Article/details/02285.sHtML
WWw.Share.01km.cN/Article/details/92352.sHtML
WWw.Share.01km.cN/Article/details/85851.sHtML
WWw.Share.01km.cN/Article/details/60855.sHtML
WWw.Share.01km.cN/Article/details/31637.sHtML
WWw.Share.01km.cN/Article/details/03162.sHtML
WWw.Share.01km.cN/Article/details/14678.sHtML
WWw.Share.01km.cN/Article/details/01519.sHtML
WWw.Share.01km.cN/Article/details/24649.sHtML
WWw.Share.01km.cN/Article/details/18744.sHtML
WWw.Share.01km.cN/Article/details/96018.sHtML
WWw.Share.01km.cN/Article/details/79130.sHtML
WWw.Share.01km.cN/Article/details/59332.sHtML
WWw.Share.01km.cN/Article/details/82798.sHtML
WWw.Share.01km.cN/Article/details/96743.sHtML
WWw.Share.01km.cN/Article/details/80356.sHtML
WWw.Share.01km.cN/Article/details/10443.sHtML
WWw.Share.01km.cN/Article/details/34199.sHtML
WWw.Share.01km.cN/Article/details/73525.sHtML
WWw.Share.01km.cN/Article/details/00149.sHtML
WWw.Share.01km.cN/Article/details/55244.sHtML
WWw.Share.01km.cN/Article/details/55370.sHtML
WWw.Share.01km.cN/Article/details/51967.sHtML
WWw.Share.01km.cN/Article/details/89242.sHtML
WWw.Share.01km.cN/Article/details/00573.sHtML
WWw.Share.01km.cN/Article/details/92061.sHtML
WWw.Share.01km.cN/Article/details/90990.sHtML
WWw.Share.01km.cN/Article/details/39772.sHtML
WWw.Share.01km.cN/Article/details/00033.sHtML
WWw.Share.01km.cN/Article/details/97386.sHtML
WWw.Share.01km.cN/Article/details/04116.sHtML
WWw.Share.01km.cN/Article/details/44855.sHtML
WWw.Share.01km.cN/Article/details/53499.sHtML
WWw.Share.01km.cN/Article/details/57579.sHtML
WWw.Share.01km.cN/Article/details/05741.sHtML
WWw.Share.01km.cN/Article/details/55117.sHtML
WWw.Share.01km.cN/Article/details/78759.sHtML
WWw.Share.01km.cN/Article/details/65500.sHtML
WWw.Share.01km.cN/Article/details/31999.sHtML
WWw.Share.01km.cN/Article/details/05536.sHtML
WWw.Share.01km.cN/Article/details/83670.sHtML
WWw.Share.01km.cN/Article/details/54939.sHtML
WWw.Share.01km.cN/Article/details/48827.sHtML
WWw.Share.01km.cN/Article/details/39072.sHtML
WWw.Share.01km.cN/Article/details/21170.sHtML
WWw.Share.01km.cN/Article/details/86439.sHtML
WWw.Share.01km.cN/Article/details/27654.sHtML
WWw.Share.01km.cN/Article/details/76817.sHtML
WWw.Share.01km.cN/Article/details/98448.sHtML
WWw.Share.01km.cN/Article/details/52080.sHtML
WWw.Share.01km.cN/Article/details/84507.sHtML
WWw.Share.01km.cN/Article/details/61709.sHtML
WWw.Share.01km.cN/Article/details/53488.sHtML
WWw.Share.01km.cN/Article/details/52406.sHtML
WWw.Share.01km.cN/Article/details/03768.sHtML
WWw.Share.01km.cN/Article/details/41762.sHtML
WWw.Share.01km.cN/Article/details/10921.sHtML
WWw.Share.01km.cN/Article/details/25463.sHtML
WWw.Share.01km.cN/Article/details/73905.sHtML
WWw.Share.01km.cN/Article/details/24742.sHtML
WWw.Share.01km.cN/Article/details/31283.sHtML
WWw.Share.01km.cN/Article/details/84951.sHtML
WWw.Share.01km.cN/Article/details/92142.sHtML
WWw.Share.01km.cN/Article/details/87153.sHtML
WWw.Share.01km.cN/Article/details/05942.sHtML
WWw.Share.01km.cN/Article/details/62146.sHtML
WWw.Share.01km.cN/Article/details/95746.sHtML
WWw.Share.01km.cN/Article/details/08353.sHtML
WWw.Share.01km.cN/Article/details/63780.sHtML
WWw.Share.01km.cN/Article/details/23241.sHtML
WWw.Share.01km.cN/Article/details/41001.sHtML
WWw.Share.01km.cN/Article/details/61495.sHtML
WWw.Share.01km.cN/Article/details/70794.sHtML
WWw.Share.01km.cN/Article/details/60877.sHtML
WWw.Share.01km.cN/Article/details/96172.sHtML
WWw.Share.01km.cN/Article/details/66588.sHtML
WWw.Share.01km.cN/Article/details/86826.sHtML
WWw.Share.01km.cN/Article/details/52685.sHtML
WWw.Share.01km.cN/Article/details/82232.sHtML
WWw.Share.01km.cN/Article/details/02217.sHtML
WWw.Share.01km.cN/Article/details/02045.sHtML
WWw.Share.01km.cN/Article/details/60324.sHtML
WWw.Share.01km.cN/Article/details/95985.sHtML
WWw.Share.01km.cN/Article/details/75000.sHtML
WWw.Share.01km.cN/Article/details/81569.sHtML
WWw.Share.01km.cN/Article/details/47698.sHtML
WWw.Share.01km.cN/Article/details/24688.sHtML
WWw.Share.01km.cN/Article/details/06298.sHtML
WWw.Share.01km.cN/Article/details/68196.sHtML
WWw.Share.01km.cN/Article/details/27957.sHtML
WWw.Share.01km.cN/Article/details/71837.sHtML
WWw.Share.01km.cN/Article/details/94750.sHtML
WWw.Share.01km.cN/Article/details/74621.sHtML
WWw.Share.01km.cN/Article/details/31196.sHtML
WWw.Share.01km.cN/Article/details/81687.sHtML
WWw.Share.01km.cN/Article/details/37442.sHtML
WWw.Share.01km.cN/Article/details/09019.sHtML
WWw.Share.01km.cN/Article/details/40418.sHtML
WWw.Share.01km.cN/Article/details/52418.sHtML
WWw.Share.01km.cN/Article/details/88857.sHtML
WWw.Share.01km.cN/Article/details/47494.sHtML
WWw.Share.01km.cN/Article/details/45196.sHtML
WWw.Share.01km.cN/Article/details/83774.sHtML
WWw.Share.01km.cN/Article/details/40533.sHtML
WWw.Share.01km.cN/Article/details/30269.sHtML
WWw.Share.01km.cN/Article/details/96853.sHtML
WWw.Share.01km.cN/Article/details/60666.sHtML
WWw.Share.01km.cN/Article/details/25902.sHtML
WWw.Share.01km.cN/Article/details/61709.sHtML
WWw.Share.01km.cN/Article/details/45597.sHtML
WWw.Share.01km.cN/Article/details/10362.sHtML
WWw.Share.01km.cN/Article/details/39218.sHtML
WWw.Share.01km.cN/Article/details/26974.sHtML
WWw.Share.01km.cN/Article/details/49540.sHtML
WWw.Share.01km.cN/Article/details/71616.sHtML
WWw.Share.01km.cN/Article/details/81976.sHtML
WWw.Share.01km.cN/Article/details/39487.sHtML
WWw.Share.01km.cN/Article/details/59457.sHtML
WWw.Share.01km.cN/Article/details/28823.sHtML
WWw.Share.01km.cN/Article/details/68801.sHtML
WWw.Share.01km.cN/Article/details/34404.sHtML
WWw.Share.01km.cN/Article/details/93400.sHtML
WWw.Share.01km.cN/Article/details/25969.sHtML
WWw.Share.01km.cN/Article/details/22167.sHtML
WWw.Share.01km.cN/Article/details/39271.sHtML
WWw.Share.01km.cN/Article/details/97721.sHtML
WWw.Share.01km.cN/Article/details/55010.sHtML
WWw.Share.01km.cN/Article/details/70184.sHtML
WWw.Share.01km.cN/Article/details/94306.sHtML
WWw.Share.01km.cN/Article/details/36355.sHtML
WWw.Share.01km.cN/Article/details/23550.sHtML
WWw.Share.01km.cN/Article/details/49147.sHtML
WWw.Share.01km.cN/Article/details/54644.sHtML
WWw.Share.01km.cN/Article/details/65267.sHtML
WWw.Share.01km.cN/Article/details/76851.sHtML
WWw.Share.01km.cN/Article/details/83558.sHtML
WWw.Share.01km.cN/Article/details/66409.sHtML