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 提供用户和权限信息。

数据访问申请流程自动化 - 技术架构图 数据访问申请流程自动化 - 技术架构 用户(浏览器/客户端) Web 应用层 Flask / Django + 模板引擎 业务逻辑层 审批流程引擎 + 权限校验 数据访问层 SQLAlchemy ORM + 连接池 关系数据库 Celery Worker 异步任务执行 Redis Broker LDAP / AD 用户身份 & 组织架构 说明 所有组件通过 Docker Compose 编排 支持水平扩展 Celery Worker

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 个项目中验证过。从几十人的小团队到上千人的大企业,都能稳定运行。嗯,技术选型就聊到这儿,接下来咱们看看具体的数据库表怎么设计。