news 2026/4/17 23:37:43

大数据标准化自动化:基于Airflow的调度方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大数据标准化自动化:基于Airflow的调度方案

大数据标准化自动化:基于Airflow的调度方案

1. 引入与连接:凌晨3点的告警电话

"叮铃铃——"凌晨3点,数据工程师小张的手机突然炸开。睡眼惺忪的他抓起手机,看到屏幕上刺眼的消息:“今日用户行为报表生成失败,请紧急排查!”

他揉着太阳穴打开电脑,登录运维平台一看:哦,昨天新增的"用户画像更新"任务没跑成功,导致下游的"报表生成"任务因为依赖缺失直接跳过。再往下查,原因更无语——任务配置时把"依赖上游任务成功"写成了"依赖上游任务开始",结果上游任务还在重试,下游就急着跑了。

这不是小张第一次遇到这种问题:

  • 新人接手任务时,总搞不清"用户行为日志"要等"日志采集"完成才能处理;
  • 手动触发任务时,经常漏跑某个环节,导致数据不一致;
  • 故障排查要翻几十条日志,才能找到"哪个任务没跑"或"哪个依赖断了"。

大数据时代,"流程混乱"比"计算能力不足"更致命。当数据任务从10个增长到1000个,当团队从3人扩大到30人,我们需要的不是"更勤奋的运维",而是**“标准化的流程"和"自动化的调度”**——这正是Apache Airflow能解决的问题。

2. 概念地图:建立大数据调度的认知框架

在深入Airflow之前,我们需要先理清大数据标准化自动化的核心逻辑:

2.1 核心概念图谱

大数据标准化自动化 ├─ 目标:减少人为错误·提高效率·增强可维护性 ├─ 标准化维度: │ ├─ 元数据标准化(任务类型·依赖规则·参数规范) │ ├─ 流程标准化(固定步骤·模板化编排) │ ├─ 监控标准化(关键指标·告警规则) ├─ 自动化维度: │ ├─ 触发自动化(定时·事件·依赖) │ ├─ 执行自动化(重试·容错·资源调度) │ ├─ 监控自动化(状态跟踪·故障告警) └─ 工具载体:Apache Airflow(调度框架·流程编排·可视化)

2.2 Airflow的核心组件

Airflow不是"计算工具"(比如Spark、Flink),而是**“数据流程的调度指挥中心”**。它的核心组件可以用"餐厅运营"类比:

  • DAG(有向无环图):餐厅的"菜谱",定义了"菜要怎么做"(比如"番茄炒蛋"需要"打鸡蛋→切番茄→炒鸡蛋→炒番茄→混合");
  • Task(任务):菜谱中的"步骤",比如"打鸡蛋";
  • Operator(操作器):完成步骤的"工具",比如"打鸡蛋用碗和筷子",对应Airflow中的PythonOperator(执行Python函数)、SparkSubmitOperator(提交Spark任务);
  • Scheduler(调度器):餐厅的"厨师长",负责检查"哪些步骤可以开始"(比如"打鸡蛋完成了,才能切番茄");
  • Webserver(Web界面):餐厅的"监控屏",能看到"每个步骤的状态"(比如"打鸡蛋完成"、“切番茄正在进行”);
  • Metadata DB(元数据库):餐厅的"账本",记录所有菜谱、步骤、状态的历史数据。

3. 基础理解:Airflow的"简单真相"

让我们用一个最常见的ETL场景,直观理解Airflow的工作方式:
需求:每天凌晨2点,从MySQL抽取用户数据→用Spark清洗→加载到Redshift数据仓库。

3.1 第一步:写一个DAG(菜谱)

用Python代码定义DAG,就像写菜谱一样简单:

fromairflowimportDAGfromairflow.providers.mysql.operators.mysqlimportMySqlOperatorfromairflow.providers.apache.spark.operators.spark_submitimportSparkSubmitOperatorfromairflow.providers.amazon.aws.operators.redshiftimportRedshiftSQLOperatorfromairflow.utils.datesimportdays_ago# 1. 定义DAG的基本信息withDAG(dag_id="user_etl_pipeline",# DAG的名字(菜谱名)schedule_interval="@daily",# 每天运行(相当于CRON表达式"0 0 * * *")start_date=days_ago(1),# 从昨天开始运行catchup=False,# 不补跑历史数据)asdag:# 2. 定义Task(步骤)# 步骤1:从MySQL抽取用户数据(用MySqlOperator)extract_user=MySqlOperator(task_id="extract_user",# Task的名字(步骤名)mysql_conn_id="mysql_prod",# 数据库连接(预先在Airflow配置)sql="SELECT id, name, email FROM users WHERE dt = '{{ ds }}'",# SQL语句,{{ ds }}是Airflow的变量,代表"运行日期")# 步骤2:用Spark清洗数据(用SparkSubmitOperator)clean_user=SparkSubmitOperator(task_id="clean_user",conn_id="spark_cluster",# Spark集群连接application="s3://my-bucket/clean_user.py",# 清洗脚本的路径application_args=["--input","{{ ti.xcom_pull(task_ids='extract_user') }}","--output","s3://my-bucket/cleaned_users/{{ ds }}"],# 传递参数,{{ ti.xcom_pull() }}获取上一步的输出)# 步骤3:加载到Redshift(用RedshiftSQLOperator)load_user=RedshiftSQLOperator(task_id="load_user",redshift_conn_id="redshift_prod",sql=""" INSERT INTO dim_user (id, name, email, dt) SELECT id, name, email, '{{ ds }}' FROM s3://my-bucket/cleaned_users/{{ ds }} """,)# 3. 设置依赖关系(步骤的顺序)extract_user>>clean_user>>load_user# ">>"表示"先做extract_user,再做clean_user,最后做load_user"

3.2 第二步:运行与监控

把代码放到Airflow的dags目录下,Web界面会自动识别DAG。你可以:

  • Graph View中看到DAG的流程图(像菜谱的步骤图);
  • Tree View中看到每个任务的运行状态(成功/失败/正在运行);
  • 点击任务名,查看日志(比如Spark任务的输出)、XCom(任务间传递的数据)。

3.3 常见误解澄清

  • 误解1:Airflow是计算框架?
    不!Airflow只负责"调度"(比如"什么时候跑Spark任务"),不负责"计算"(比如Spark任务的具体执行)。计算由Spark、Flink等工具完成。
  • 误解2:DAG可以有环?
    绝对不行!DAG的全称是"有向无环图",如果有环(比如"任务A依赖任务B,任务B又依赖任务A"),会导致无限循环,Airflow会直接报错。
  • 误解3:任务失败了只能手动重跑?
    不需要!可以在Operator中设置retries=3(重试3次)、retry_delay=timedelta(minutes=5)(每次重试间隔5分钟),Airflow会自动重试。

4. 层层深入:从"能用"到"用好"Airflow

掌握基础后,我们需要深入Airflow的核心机制高级功能,解决更复杂的场景。

4.1 第一层:Airflow的调度逻辑

Airflow的调度核心是**“时间触发""依赖触发”**的结合:

  • 时间触发:用CRON表达式或预定义的间隔(比如@hourly@daily)设置任务的运行时间;
  • 依赖触发:任务必须等待所有上游任务成功(或满足其他条件)才能开始。

比如,我们的ETL任务:

  1. Scheduler每天凌晨2点检查DAG;
  2. 发现extract_user任务满足时间条件,触发执行;
  3. extract_user成功后,Scheduler触发clean_user
  4. clean_user成功后,触发load_user

4.2 第二层:细节与特殊场景处理

4.2.1 依赖的灵活配置

除了>>,Airflow还支持更灵活的依赖规则:

  • 多上游依赖task_c.set_upstream([task_a, task_b])(task_c要等task_a和task_b都成功);
  • 触发规则:用trigger_rule设置依赖条件,比如all_done(不管上游成功还是失败,都触发)、one_failed(只要有一个上游失败,就触发)。

比如,我们要在任何一个任务失败时发送告警

fromairflow.operators.emailimportEmailOperator send_alert=EmailOperator(task_id="send_alert",to="data_team@company.com",subject="ETL任务失败告警",html_content="任务{{ task_id }}失败,请查看日志:{{ ti.log_url }}",trigger_rule="one_failed",# 只要有一个上游任务失败,就发送邮件)extract_user>>clean_user>>load_user[extract_user,clean_user,load_user]>>send_alert# 三个任务的下游都是send_alert
4.2.2 任务间的数据传递:XCom

如果任务A需要把数据传递给任务B,比如extract_user要把"抽取的文件路径"传给clean_user,可以用XCom(Cross-Communication):

# 任务A:抽取数据,把文件路径推送到XComdefextract_data(**context):file_path=f"s3://my-bucket/raw_users/{context['ds']}.csv"# 执行抽取逻辑...context['ti'].xcom_push(key='file_path',value=file_path)# 推送XComextract_user=PythonOperator(task_id="extract_user",python_callable=extract_data,provide_context=True,# 传递上下文(包含ds、ti等变量))# 任务B:获取XCom中的文件路径defclean_data(**context):file_path=context['ti'].xcom_pull(task_ids='extract_user',key='file_path')# 拉取XCom# 执行清洗逻辑...clean_user=PythonOperator(task_id="clean_user",python_callable=clean_data,provide_context=True,)
4.2.3 动态生成DAG

如果有10个类似的ETL任务(比如"用户数据"、“订单数据”、“商品数据”),不需要写10个DAG,可以用动态生成

fromairflowimportDAGfromairflow.providers.mysql.operators.mysqlimportMySqlOperatorfromairflow.providers.apache.spark.operators.spark_submitimportSparkSubmitOperatorfromairflow.utils.datesimportdays_ago# 定义要处理的表列表tables=["user","order","product"]fortableintables:withDAG(dag_id=f"{table}_etl_pipeline",schedule_interval="@daily",start_date=days_ago(1),catchup=False,)asdag:# 抽取任务extract=MySqlOperator(task_id=f"extract_{table}",mysql_conn_id="mysql_prod",sql=f"SELECT * FROM{table}WHERE dt = '{{ ds }}'",)# 清洗任务clean=SparkSubmitOperator(task_id=f"clean_{table}",conn_id="spark_cluster",application=f"s3://my-bucket/clean_{table}.py",)# 加载任务(假设用Redshift)load=RedshiftSQLOperator(task_id=f"load_{table}",redshift_conn_id="redshift_prod",sql=f"INSERT INTO dim_{table}SELECT * FROM s3://my-bucket/cleaned_{table}/{{ ds }}",)# 依赖关系extract>>clean>>load

这样,只需要写一次代码,就能生成3个DAG,极大减少重复劳动!

4.3 第三层:底层逻辑与性能优化

4.3.1 执行器(Executor)的选择

Airflow的执行器决定了"任务在哪里运行",不同的执行器适合不同的场景:

执行器类型特点适用场景
LocalExecutor所有任务在Airflow服务器上运行测试环境·小任务量
CeleryExecutor用Celery分布式运行任务生产环境·中大型任务量
KubernetesExecutor用Kubernetes动态创建Pod运行任务云原生环境·弹性任务量

示例:配置CeleryExecutor
修改airflow.cfg

[core] executor = CeleryExecutor [celery] broker_url = redis://redis:6379/0 # 消息队列(Redis或RabbitMQ) result_backend = db+mysql://airflow:airflow@mysql/airflow # 结果存储(元数据库)
4.3.2 元数据库的优化

Airflow的元数据库(比如MySQL、PostgreSQL)存储了所有任务的状态、日志、XCom数据,优化元数据库能显著提升Airflow的性能

  • 定期清理历史数据(比如删除30天前的任务运行记录);
  • task_instancedag_run表添加索引;
  • 使用innodb_buffer_pool_size优化MySQL的缓存(建议设置为内存的70%)。

4.4 第四层:高级功能

4.4.1 传感器(Sensor):等待外部事件

如果任务需要等待某个外部条件满足(比如"文件上传到S3"、“API返回成功”),可以用Sensor

fromairflow.providers.amazon.aws.sensors.s3importS3KeySensor# 等待S3中出现"user_data.csv"文件wait_for_file=S3KeySensor(task_id="wait_for_file",bucket_name="my-bucket",bucket_key="raw_data/user_data.csv",aws_conn_id="aws_prod",timeout=3600,# 最多等待1小时poke_interval=60,# 每60秒检查一次)wait_for_file>>extract_user# 等文件出现后,再执行抽取任务
4.4.2 分支任务(Branch):根据条件选择路径

如果需要根据条件选择不同的执行路径(比如"数据符合要求→继续处理,否则→发送告警"),可以用BranchPythonOperator

fromairflow.operators.pythonimportBranchPythonOperatordefcheck_data_quality(**context):# 检查数据质量(比如行数是否≥1000)row_count=context['ti'].xcom_pull(task_ids='extract_user',key='row_count')ifrow_count>=1000:return"clean_user"# 数据符合要求,执行clean_userelse:return"send_quality_alert"# 数据不符合,发送告警branch_task=BranchPythonOperator(task_id="check_data_quality",python_callable=check_data_quality,provide_context=True,)send_quality_alert=EmailOperator(task_id="send_quality_alert",to="data_team@company.com",subject="数据质量告警",html_content="用户数据行数不足1000,请检查!",)# 依赖关系:extract_user→branch_task→[clean_user或send_quality_alert]extract_user>>branch_task branch_task>>clean_user branch_task>>send_quality_alert

5. 多维透视:Airflow的"过去、现在、未来"

5.1 历史视角:调度系统的演变

从"手动执行"到"智能调度",调度系统的演变反映了大数据流程的复杂度提升:

  1. Crontab:最原始的调度工具,适合单个任务,但无法处理依赖(比如"任务A没跑完,任务B就开始了");
  2. Oozie:Hadoop生态的调度工具,基于XML配置,适合批处理任务,但不够灵活(比如无法动态生成DAG);
  3. Airflow:2015年由Airbnb开源,用Python驱动,支持动态DAG、可视化监控,成为大数据调度的"事实标准";
  4. 现代调度系统:比如Prefect、Dagster,更强调"数据管线的可观察性"(Observability),但Airflow的生态和成熟度仍占优势。

5.2 实践视角:Airflow的典型应用场景

5.2.1 数据仓库构建

数据仓库的分层架构(ODS→DWD→DWS→ADS)需要严格的依赖管理,Airflow正好适合:

  • ODS层:抽取日志(比如Flume采集的Nginx日志)和数据库数据(比如MySQL的用户表);
  • DWD层:清洗数据(比如去除空值、转换字段类型);
  • DWS层:聚合数据(比如按天统计用户活跃量);
  • ADS层:生成报表(比如销售日报、用户画像)。

用Airflow编排这些层的任务,能保证"上层任务必须等下层任务完成",避免数据不一致。

5.2.2 机器学习Pipeline

机器学习的流程(数据预处理→特征工程→模型训练→评估→部署)需要自动化,Airflow可以:

  • 定时触发:每天自动更新训练数据;
  • 依赖管理:模型训练必须等特征工程完成;
  • 结果传递:用XCom传递特征数据的路径给训练任务;
  • 告警:如果模型准确率低于阈值,发送告警。

5.3 批判视角:Airflow的局限性

Airflow不是"银弹",它也有缺点:

  1. 重调度轻计算:Airflow不负责任务的执行,需要依赖其他工具(比如Spark、Flink),增加了系统复杂度;
  2. 大DAG性能问题:当DAG有几千个Task时,Scheduler扫描DAG的时间会变长,导致任务延迟;
  3. UI的局限性:Airflow的Web UI查看日志和监控不够直观,需要整合Prometheus、Grafana等工具;
  4. 依赖管理的复杂度:复杂的依赖关系(比如"任务A依赖任务B和C,任务B又依赖任务D")容易出错,需要仔细设计DAG。

5.4 未来视角:Airflow的发展趋势

Airflow的社区非常活跃,未来的发展方向包括:

  1. 云原生:KubernetesExecutor会成为主流,支持动态资源分配(比如根据任务需求创建Pod,任务完成后销毁);
  2. AI辅助调度:用机器学习预测任务时长,优化调度顺序(比如"长任务先跑,短任务后跑");用NLP分析日志,自动定位故障(比如"日志中出现’Connection refused’,可能是数据库宕机");
  3. 生态整合:与云服务(比如Snowflake、BigQuery、AWS Glue)深度集成,简化配置;
  4. Observability增强:内置更多监控指标(比如任务延迟率、资源使用率),支持Prometheus、Alertmanager等工具。

6. 实践转化:用Airflow实现大数据标准化自动化

说了这么多,如何落地Airflow的标准化自动化?我们需要分四步走:

6.1 第一步:元数据标准化

元数据是"数据的数据",比如任务的类型、依赖规则、参数规范。标准化元数据能让所有团队成员"说同一种语言"。

示例:任务元数据模板

字段说明示例
任务ID唯一标识user_etl_extract
任务类型ETL/ML/报表ETL
上游依赖依赖的任务ID[log_collect_user]
输入参数数据源地址·SQL脚本·文件路径mysql_conn_id: mysql_prod
输出参数目标路径·表名·XCom键file_path: s3://bucket/raw
重试次数失败后重试的次数3
重试间隔每次重试的间隔(分钟)5

6.2 第二步:流程模板化

开发通用的DAG模板,让新任务"填空式"生成,避免重复劳动。

示例:ETL模板

fromairflowimportDAGfromairflow.providers.mysql.operators.mysqlimportMySqlOperatorfromairflow.providers.apache.spark.operators.spark_submitimportSparkSubmitOperatorfromairflow.providers.amazon.aws.operators.redshiftimportRedshiftSQLOperatorfromairflow.utils.datesimportdays_agodefcreate_etl_dag(dag_id,schedule_interval,start_date,table_name,mysql_conn_id,spark_conn_id,redshift_conn_id):withDAG(dag_id=dag_id,schedule_interval=schedule_interval,start_date=start_date,catchup=False,)asdag:# 抽取任务extract=MySqlOperator(task_id=f"extract_{table_name}",mysql_conn_id=mysql_conn_id,sql=f"SELECT * FROM{table_name}WHERE dt = '{{ ds }}'",)# 清洗任务clean=SparkSubmitOperator(task_id=f"clean_{table_name}",conn_id=spark_conn_id,application=f"s3://my-bucket/clean_{table_name}.py",)# 加载任务load=RedshiftSQLOperator(task_id=f"load_{table_name}",redshift_conn_id=redshift_conn_id,sql=f"INSERT INTO dim_{table_name}SELECT * FROM s3://my-bucket/cleaned_{table_name}/{{ ds }}",)# 依赖关系extract>>clean>>loadreturndag# 生成用户ETL DAGuser_etl_dag=create_etl_dag(dag_id="user_etl_pipeline",schedule_interval="@daily",start_date=days_ago(1),table_name="user",mysql_conn_id="mysql_prod",spark_conn_id="spark_cluster",redshift_conn_id="redshift_prod",)# 生成订单ETL DAGorder_etl_dag=create_etl_dag(dag_id="order_etl_pipeline",schedule_interval="@daily",start_date=days_ago(1),table_name="order",mysql_conn_id="mysql_prod",spark_conn_id="spark_cluster",redshift_conn_id="redshift_prod",)

6.3 第三步:自动化策略

6.3.1 定时触发

用CRON表达式设置任务的运行时间,比如:

  • 每天凌晨2点:0 2 * * *
  • 每小时第10分钟:10 * * * *
  • 每周一凌晨3点:0 3 * * 1
6.3.2 事件触发

用Sensor监控外部事件,比如:

  • 当文件上传到S3时,触发ETL任务;
  • 当API返回成功时,触发数据同步任务。
6.3.3 依赖触发

让任务等待上游任务成功后自动运行,比如:

  • "用户画像更新"任务等待"用户数据抽取"任务成功;
  • "报表生成"任务等待"用户画像更新"和"订单数据更新"任务成功。

6.4 第四步:监控与告警标准化

没有监控的自动化是"裸奔",我们需要定义关键指标和告警规则:

6.4.1 关键指标
  • 任务成功率:≥99%(低于这个值说明有严重问题);
  • 任务延迟率:≤10分钟(超过这个值说明调度有问题);
  • 资源使用率:CPU≤80%,内存≤70%(超过这个值说明资源不足);
  • 数据质量指标:比如行数≥1000,空值率≤1%。
6.4.2 监控与告警实现
  1. 暴露指标:Airflow内置Prometheus指标(需要安装airflow-prometheus-exporter),可以暴露任务成功率、延迟率等指标;
  2. 可视化:用Grafana搭建监控Dashboard,展示DAG的运行状态、任务的成功率、资源使用率;
  3. 告警:用Alertmanager设置告警规则,比如:
    • 任务失败超过5分钟,发送Slack通知;
    • 任务延迟超过10分钟,发送邮件;
    • 资源使用率超过80%,发送短信。

7. 整合提升:从"工具使用者"到"流程设计者"

7.1 核心观点回顾

  • Airflow是大数据标准化自动化的核心工具,通过DAG实现流程的标准化编排,通过Operator实现任务的标准化执行,通过Scheduler实现自动化调度;
  • 标准化的关键是元数据、流程、监控的统一,自动化的关键是触发、重试、依赖的自动处理
  • Airflow不是"银弹",需要结合其他工具(比如Spark、Prometheus)才能发挥最大价值。

7.2 知识体系重构

把你的大数据流程映射到Airflow的框架中,问自己以下问题:

  1. 哪些任务是重复的?能不能用模板生成?
  2. 哪些依赖是混乱的?能不能用DAG图可视化?
  3. 哪些监控是缺失的?能不能用Prometheus+Grafana补充?
  4. 哪些手动操作可以自动化?能不能用Sensor或定时触发替代?

7.3 拓展任务

  1. 尝试云原生部署:用KubernetesExecutor部署Airflow,体验动态资源分配;
  2. 开发自定义Operator:比如调用公司内部API的Operator,提高复用性;
  3. 整合机器学习:用Airflow编排一个完整的ML Pipeline(数据预处理→训练→评估→部署);
  4. 优化监控系统:用Grafana搭建Airflow的Dashboard,展示任务成功率、延迟率等指标。

7.4 学习资源推荐

  • 官方文档:https://airflow.apache.org/docs/(最权威的资料);
  • 书籍:《Apache Airflow实战》(适合入门)、《Data Pipelines with Apache Airflow》(适合进阶);
  • 示例项目:https://github.com/apache/airflow/tree/main/examples(官方提供的示例DAG);
  • 社区:Airflow的Slack社区(https://airflow-slack.herokuapp.com/),可以提问和交流。

结语:从"救火队员"到"流程设计者"

回到文章开头的小张,现在他的团队已经用Airflow实现了大数据流程的标准化自动化:

  • 新人接手任务时,只要填写模板的参数,就能生成DAG;
  • 任务失败时,Airflow会自动重试,重试失败会发送告警;
  • 故障排查时,只要看Web界面的DAG图,就能快速找到问题所在。

凌晨3点的告警电话再也没响过,小张终于能睡个安稳觉了。而这一切的变化,源于他们从"救火队员"变成了"流程设计者"——用Airflow把"混乱的流程"变成了"标准化的流水线"。

大数据的价值不在于"数据多",而在于"数据能高效产生价值"。Airflow不是终点,而是起点——它让我们从"处理数据"转向"设计数据流程",从"应对问题"转向"预防问题"。

现在,轮到你了:打开Airflow的Web界面,创建第一个DAG,开始你的大数据标准化自动化之旅吧!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 13:50:22

无感启动领域有个低调的黑科技——Harnefors观测器,这个藏在论文里的十行代码算法,实测能在低速重载场景下直接拉回转子位置。咱们今天扒一扒它的实现奥秘

静态补偿电压观测器代码(Harnefors Observer)C语言_定点示例代码-低速无感重载启动推荐方案 该观测器来源Harnefors教授论文 《Synchronization at startup and stable rotation reversal of sensorless nonsalient PMSM drives》中提到的观测器 该观测器…

作者头像 李华
网站建设 2026/4/18 3:26:39

异常、模块与包

异常、模块与包 一、了解异常 1.1 什么是异常 当检测到一个错误时,python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”,也就是我们常说的bug 1.2 bug的由来 1.3 异常演示 二、异常捕获的方法 2.1 为什么要捕获异常 世界上没有完美的程序,…

作者头像 李华
网站建设 2026/4/18 7:01:02

为什么所有企业都离不开进销存?一篇说清进销存核心价值!

很多企业主都有过这样的真实体验:早上刚到办公室,仓库主管告诉你库存不足中午业务员却反馈客户要的型号肯定有货到了下午,客户已经催到第三次,而仓库和业务团队仍然各执一词销售端和库存端的信息不一致,让你每天都像在…

作者头像 李华
网站建设 2026/4/18 6:23:42

天机学堂项目文档Day07

Day07签到功能实现:1.思路分析:首先假设使用数据库中的签到表,当该项目的用户体量越来越大的时候,该数据库关于签到表的记录就会占用很大的空间。举个例子:假如一个用户1年签到100次,而网站有100万用户&…

作者头像 李华