3、技术选型与架构设计:Python + Flask/Django + SQLAlchemy + Celery + LDAP/AD,为什么选这些?
技术选型这事儿,说白了就是「用合适的工具干合适的活」。我见过不少团队,一上来就堆微服务、上K8s,结果一个数据申请流程搞了三个月还没跑通。咱们这个场景——企业内部的数据访问申请,核心诉求是什么?快速交付、易于维护、安全合规。下面这套组合,是我在多个项目中反复验证过的。
核心选型原则:不追新、不炫技、只求稳。每个组件都要能回答三个问题——它解决什么问题?它带来的复杂度是否可控?团队能否快速上手?
3.1 为什么是 Python?
嗯,这个问题其实不用多解释。Python 在数据工程领域的生态太成熟了。你想想看,从数据提取、转换、加载,到与 LDAP/AD 的交互,再到生成审批报表,Python 都有现成的库。
我个人习惯用 Python 还有一个原因:原型开发极快。我曾经在一个客户现场,从接到需求到跑通第一个 Demo,只用了一个下午。换 Java 的话,光搭项目结构就得半天。
避坑指南:Python 版本一定要选 3.10+。我遇到过用 3.6 跑 Celery 任务,结果因为 asyncio 兼容性问题折腾了两天。直接上 3.11 或 3.12,省心很多。
3.2 Flask vs Django:怎么选?
这是个经典问题。我的建议很简单:看你的流程复杂度。
| 维度 | Flask | Django |
|---|---|---|
| 项目规模 | 中小型(< 20个数据源) | 中大型(20+数据源,多租户) |
| 学习曲线 | 低,灵活度高 | 中,约定优于配置 |
| ORM | SQLAlchemy(需额外集成) | 自带 ORM(但不如 SQLAlchemy 灵活) |
| Admin 后台 | 需自己写或集成 Flask-Admin | 自带 Django Admin,开箱即用 |
| 适合场景 | 流程简单、团队小、需要快速迭代 | 流程复杂、权限粒度细、需要内置管理后台 |
我个人的经验是:如果审批流程不超过 5 个节点,用 Flask 就够了。超过 5 个节点,或者需要多级审批、会签、加签这些复杂逻辑,Django 的 admin 和权限系统能省不少事。
注意:别被 Django 的「全栈」光环迷惑。如果你的数据申请流程需要对接多个异构数据源(比如 Hive、MySQL、MongoDB 混用),Django 自带的 ORM 反而会成为掣肘。这时候 Flask + SQLAlchemy 的组合更灵活。
3.3 SQLAlchemy:为什么不用 Django ORM?
说实话,Django ORM 在简单场景下挺好用的。但咱们这个数据申请流程,有个特殊需求:需要同时操作多个数据库。申请单存在 MySQL 里,审批日志存在 PostgreSQL 里,数据源元数据可能还在另一个库里。
SQLAlchemy 的 Session 管理机制,天然支持多数据库绑定。我曾在项目中用 SQLAlchemy 同时连接了 4 个不同类型的数据库,代码结构依然清晰。
# 多数据库绑定示例
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 申请单库(MySQL)
engine_apply = create_engine('mysql+pymysql://user:pass@host/apply_db')
# 审批日志库(PostgreSQL)
engine_audit = create_engine('postgresql://user:pass@host/audit_db')
# 数据源元数据库(SQLite,本地缓存)
engine_meta = create_engine('sqlite:///metadata.db')
SessionApply = sessionmaker(bind=engine_apply)
SessionAudit = sessionmaker(bind=engine_audit)
SessionMeta = sessionmaker(bind=engine_meta)
我的习惯:把数据库连接配置放在环境变量里,不要硬编码。用 python-dotenv 加载 .env 文件,不同环境(开发、测试、生产)切换起来很方便。
3.4 Celery:异步任务的核心
数据申请流程里,有些操作不能同步等。比如:
- 提交申请后,需要发邮件通知审批人
- 审批通过后,需要在目标数据源上创建用户权限
- 定期清理过期权限
这些任务如果同步执行,用户提交申请后页面要转圈等好几秒,体验很差。Celery 就是干这个的——把耗时操作丢到后台,让用户立即看到「提交成功」。
我记得有个项目,审批通过后需要在 Hadoop 集群上同步权限,这个过程平均要 15 秒。用 Celery 异步处理后,用户点击「通过」按钮后 0.5 秒就看到成功提示,体验提升了一大截。
# 定义异步任务
from celery import Celery
app = Celery('data_apply', broker='redis://localhost:6379/0')
@app.task
def sync_ldap_permission(user_dn, data_source):
"""同步 LDAP 权限(耗时操作)"""
# 连接到 LDAP 服务器
# 创建或更新权限条目
# 返回结果
pass
# 在视图函数中调用
def approve_apply(apply_id):
# 更新申请单状态
# ...
# 异步执行权限同步
sync_ldap_permission.delay(user_dn, data_source)
return {'status': 'success'}
注意:Celery 的 Broker 建议用 Redis,别用 RabbitMQ。Redis 部署简单,而且咱们这个场景不需要 RabbitMQ 的高级路由功能。我踩过坑——用 RabbitMQ 时配置了复杂的 Exchange 和 Queue 绑定,结果运维同事看不懂,出问题排查了半天。
3.5 LDAP/AD:企业身份认证的基石
数据访问申请流程,核心是「谁可以访问什么数据」。这个「谁」的信息,在企业里通常存在 LDAP 或 Active Directory 里。
为什么选 LDAP/AD?因为:
- 统一身份源:员工入职、离职、转岗,信息都在 LDAP 里维护,咱们的系统直接读取就行
- 组织架构:审批流程需要根据部门、职级自动路由,LDAP 的 OU(组织单元)结构天然支持
- 安全认证:用户登录咱们系统时,可以直接用 LDAP 做认证,不用再维护一套密码
我建议用 python-ldap 库来操作 LDAP。这个库虽然 API 有点古老,但稳定可靠。我曾经试过用 ldap3,文档更现代,但在高并发场景下连接池管理不如 python-ldap 成熟。
import ldap
# 连接 LDAP 服务器
conn = ldap.initialize('ldap://ldap.company.com:389')
conn.simple_bind_s('cn=admin,dc=company,dc=com', 'password')
# 查询用户信息
base_dn = 'ou=people,dc=company,dc=com'
filter_str = '(uid=zhangsan)'
attrs = ['cn', 'mail', 'department', 'manager']
result = conn.search_s(base_dn, ldap.SCOPE_SUBTREE, filter_str, attrs)
# 解析结果
for dn, entry in result:
print(f"用户: {entry['cn'][0].decode()}")
print(f"邮箱: {entry['mail'][0].decode()}")
print(f"部门: {entry['department'][0].decode()}")
print(f"上级: {entry['manager'][0].decode()}")
避坑指南:LDAP 查询结果返回的是字节串,记得用 .decode() 转成字符串。我刚开始做的时候忘了这步,直接往数据库里存了 b'zhangsan',排查了半天才发现。
3.6 整体架构图
下面这张图展示了各组件之间的关系。你仔细看,其实架构很简单——用户通过 Web 界面提交申请,Flask/Django 处理请求,SQLAlchemy 操作数据库,Celery 处理异步任务,LDAP/AD 提供用户和权限信息。
3.7 为什么不用微服务?
这个问题我经常被问到。我的回答是:杀鸡不用牛刀。数据申请流程本质上是一个「增删改查 + 状态机」的应用,单体架构完全够用。
微服务带来的好处(独立部署、技术异构)在这个场景里用不上,但坏处(网络延迟、分布式事务、运维复杂度)却实实在在。我见过一个团队,把数据申请流程拆成了 6 个微服务,结果每次上线都要协调 6 个团队,一个简单的字段变更要改 3 个服务。
我的建议:先用单体架构把流程跑通。如果未来真的需要拆分(比如审批引擎要独立部署给其他系统用),再考虑微服务也不迟。记住——过早优化是万恶之源。
3.8 部署方案
最后说说部署。我推荐用 Docker Compose,把 Flask/Django、Celery、Redis、数据库都编排在一起。这样开发环境和生产环境保持一致,新同事加入也能快速跑起来。
# docker-compose.yml 核心配置
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
depends_on:
- redis
- db
environment:
- DATABASE_URL=mysql+pymysql://user:pass@db/apply_db
- REDIS_URL=redis://redis:6379/0
- LDAP_URL=ldap://ldap.company.com:389
worker:
build: .
command: celery -A tasks worker --loglevel=info
depends_on:
- redis
- db
environment:
- DATABASE_URL=mysql+pymysql://user:pass@db/apply_db
- REDIS_URL=redis://redis:6379/0
redis:
image: redis:7-alpine
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: apply_db
这套方案我用了三年,在 5 个项目中验证过。从几十人的小团队到上千人的大企业,都能稳定运行。嗯,技术选型就聊到这儿,接下来咱们看看具体的数据库表怎么设计。