airflow mysql_Airflow 使用及原理分析

Airflow 入门及使用

什么是 Airflow?Airflow 是一个使用 Python 语言编写的 Data Pipeline 调度和监控工作流的平台。

Airflow 是通过 DAG(Directed acyclic graph 有向无环图)来管理任务流程的任务调度工具,不需要知道业务数据的具体内容,设置任务的依赖关系即可实现任务调度。

这个平台拥有和 Hive、Presto、MySQL、HDFS、Postgres 等数据源之间交互的能力,并且提供了钩子(hook)使其拥有很好地扩展性。除了使用命令行,该工具还提供了一个 WebUI 可以可视化的查看依赖关系、监控进度、触发任务等。

Airflow 的架构在一个可扩展的生产环境中,Airflow 含有以下组件:

元数据库:这个数据库存储有关任务状态的信息。

调度器:Scheduler 是一种使用 DAG 定义结合元数据中的任务状态来决定哪些任务需要被执行以及任务执行优先级的过程。调度器通常作为服务运行。

执行器:Executor 是一个消息队列进程,它被绑定到调度器中,用于确定实际执行每个任务计划的工作进程。有不同类型的执行器,每个执行器都使用一个指定工作进程的类来执行任务。例如,LocalExecutor 使用与调度器进程在同一台机器上运行的并行进程执行任务。其他像 CeleryExecutor 的执行器使用存在于独立的工作机器集群中的工作进程执行任务。

Workers:这些是实际执行任务逻辑的进程,由正在使用的执行器确定。

811e64e6838e38a8693ef343887ae827.png

Airflow 解决哪些问题通常,在一个运维系统,数据分析系统,或测试系统等大型系统中,我们会有各种各样的依赖需求。包括但不限于:

时间依赖:任务需要等待某一个时间点触发。

外部系统依赖:任务依赖外部系统需要调用接口去访问。

任务间依赖:任务 A 需要在任务 B 完成后启动,两个任务互相间会产生影响。

资源环境依赖:任务消耗资源非常多, 或者只能在特定的机器上执行。

crontab 可以很好地处理定时执行任务的需求,但仅能管理时间上的依赖。

Airflow 是一种 WMS,即:它将任务以及它们的依赖看作代码,按照那些计划规范任务执行,并在实际工作进程之间分发需执行的任务。

Airflow 提供了一个用于显示当前活动任务和过去任务状态的优秀 UI,并允许用户手动管理任务的执行和状态。

Airflow 中的工作流是具有方向性依赖的任务集合。

具体说就是 Airflow 的核心概念 DAG(有向无环图)—— 来表现工作流。

DAG 中的每个节点都是一个任务,DAG 中的边表示的是任务之间的依赖(强制为有向无环,因此不会出现循环依赖,从而导致无限执行循环)。

Airflow 在 ETL 上的实践ETL,是英文 Extract,Transform,Load 的缩写,用来描述将数据从来源端经过抽取(extract)、转换(transform)、加载(load)至目的端的过程。ETL 一词较常用在数据仓库,Airflow 在解决 ETL 任务各种依赖问题上的能力恰恰是我们所需要的。

在现阶段的实践中,我们使用 Airflow 来同步各个数据源数据到数仓,同时定时执行一些批处理任务及带有数据依赖、资源依赖关系的计算脚本。

本文立意于科普介绍,故在后面的用例中只介绍了 BashOperator,PythonOperator这俩个最为易用且在我们日常使用中最为常见的 Operator。

Airflow 同时也具有不错的集群扩展能力,可使用 CeleryExecuter 以及多个 Pool 来提高任务并发度。

Airflow在 CeleryExecuter 下可以使用不同的用户启动 Worker,不同的 Worker 监听不同的 Queue,这样可以解决用户权限依赖问题。Worker 也可以启动在多个不同的机器上,解决机器依赖的问题。

Airflow 可以为任意一个 Task 指定一个抽象的 Pool,每个 Pool 可以指定一个 Slot 数。每当一个 Task 启动时,就占用一个 Slot,当 Slot 数占满时,其余的任务就处于等待状态。这样就解决了资源依赖问题。

Airflow 安装及初始化假设:你已经安装好了 Python 及配置好了其包管理工具 pip。

pip install apache-airflow

# 初始化数据库

airflow initdb

# 上面的命令默认在家目录下创建 Airflow 文件夹和相关配置文件

# 也可以使用以下命令来指定目录

export AIRFLOW_HOME={yourpath}/airflow

# 配置数据库

# vim airflow/airflow.cfg

# 修改 sql_alchemy_conn

# 守护进程运行 webserver,默认端口为8080,也可以通过`-p`来指定端口

airflow webserver -D

# 守护进程运行调度器

airflow scheduler -D

定义第一个 DAG在 AIRFLOW_HOME 目录下新建 DAGs 文件夹,后面的所有 DAG 文件都要存储在这个目录。

新建 demo.py,语句含义见注释。

from datetime import datetime, timedelta

from airflow import DAG

from airflow.utils.dates import days_ago

from airflow.operators.bash_operator import BashOperator

from airflow.operators.python_operator import PythonOperator

from airflow.operators.dummy_operator import DummyOperator

def default_options():

default_args = {

'owner': 'airflow',  # 拥有者名称

'start_date': days_ago(1),  # 第一次开始执行的时间,为 UTC 时间(注意不要设置为当前时间)

'retries': 1,# 失败重试次数

'retry_delay': timedelta(seconds=5)  # 失败重试间隔

}

return default_args

# 定义 DAG

def test1(dag):

t = "echo 'hallo world'"

# operator 支持多种类型, 这里使用 BashOperator

task = BashOperator(

task_id='test1',  # task_id

bash_command=t,  # 指定要执行的命令

dag=dag  # 指定归属的 DAG

)

return task

def hello_world_1():

current_time = str(datetime.today())

print('hello world at {}'.format(current_time))

def test2(dag):

# PythonOperator

task = PythonOperator(

task_id='test2',

python_callable=hello_world_1,  # 指定要执行的函数

dag=dag)

return task

def test3(dag):

# DummyOperator

task = DummyOperator(

task_id='test3',

dag=dag)

return task

with DAG(

'test_task',  # dag_id

default_args=default_options(),  # 指定默认参数

schedule_interval="@once"  # 执行周期

) as d:

task1 = test1(d)

task2 = test2(d)

task3 = test3(d)

task1 >> task2 >> task3  # 指定执行顺序

写完后执行 python $AIRFLOW_HOME/dags/demo.py 检查是否有错误,如果命令行没有报错,就表示没问题。

Web UI打开 localhost:8080。

主视图:

0f94181efa7a58d8ecb9f05ff1eb220f.png

Airflow 的 WebUI 是其任务调度可视化的体现,可以在这个 WebUI 上监控几乎所有任务调度运行的实时及历史数据。一些命令如 Trigger、Clear 均可以在 WebUI 上完成;一些全局参数也可以在主页面导航栏 Admin 下配置。

点击 dag_name,进入任务预览:

任务图视图:

ff41b2655ac57b16246ee6efef7dd935.png

任务树视图:

4fd898640940e65a9bdb62d1435acdfa.png

其他常用命令# 测试任务,格式:airflow test dag_id task_id execution_time

airflow test test_task test1 2019-09-10

# 查看生效的 DAGs

airflow list_dags -sd $AIRFLOW_HOME/dags

# 开始运行任务(同 web 界面点 trigger 按钮)

airflow trigger_dag test_task

# 暂停任务

airflow pause dag_id

# 取消暂停,等同于在 web 管理界面打开 off 按钮

airflow unpause dag_id

# 查看 task 列表

airflow list_tasks dag_id  查看task列表

# 清空任务状态

airflow clear dag_id

# 运行task

airflow run dag_id task_id execution_date

Airflow 核心原理分析

概念及发展JOB:最上层的工作。分为 SchedulerJob、BackfillJob 和 LocalTaskJob。SchedulerJob 由 Scheduler 创建,BackfillJob 由 Backfill 创建,LocalTaskJob 由前面两种 Job 创建。

DAG:有向无环图,用来表示工作流。

DAG Run:工作流实例,表示某个工作流的一次运行(状态)。

Task:任务,工作流的基本组成部分。

TaskInstance:任务实例,表示某个任务的一次运行(状态)。

在早期版本 Airflow 中,DAG 执行主要有两种完全独立的执行途径:SchedulerJob 和 BackfillJob。在一次较大的重构中增加了 DagRun 方式,以跟踪 DAG 的执行状态。

结构关系图:

a2d657cfdb3f4b3c089f0ca3c65c9940.png

DagRun 执行流程描述DagRuns 表示某个时间点 DAG 的状态(也称为 DagInstances)。要运行 DAG 或管理 DAG 的执行,必须首先创建一个 DagRun 实例。但是仅创建 DagRun 不足以实际运行 DAG(就像创建 TaskInstance 与实际运行任务并不一样)。

因此需要一种机制来实现上述流程。结构相当简单,维护一组要执行的 DagRuns 集合,并循环遍历该集合,直到所有 DagRuns 成功或失败为止。

基本的 DagRuns 循环如下所示:

刷新 DAGs

收集新的 DagRuns

执行 DagRuns(包括更新 DagRuns 的状态为成功或失败)

唤醒 executor/心跳检查

Scheduler 的调度逻辑调度器实际上就是一个 airflow.jobs.SchedulerJob 实例 Job 持续运行 run 方法。job.run() 在开始时将自身的信息加入到 Job 表中,并维护状态和心跳,预期能够正常结束,将结束时间也更新到表中。但是实际上往往因为异常中断,导致结束时间为空。不管是如何进行的退出,SchedulerJob 退出时会关闭所有子进程。

这里主要介绍下 Scheduler 的调度逻辑:

遍历 DAGs 路径下的所有 DAG 文件,启动一定数量的进程(进程池),并且给每个进程指派一个 DAG 文件。每个 DagFileProcessor 解析分配给它的 DAG 文件,并根据解析结果在DB中创建 DagRuns 和 TaskInstance。

在 scheduler_loop 中,检查与活动 DagRun 关联的 TaskInstance 的状态,解析 TaskInstance 之间的任何依赖,标识需要被执行的 TaskInstance,然后将它们添加至 executor 队列,将新排列的 TaskInstance 状态更新为QUEUED状态。

每个可用的 executor 从队列中取一个 TaskInstance,然后开始执行它,将此 TaskInstance 的数据库记录更新为SCHEDULED。

当一个 TaskInstance 完成运行,关联的 executor 就会报告到队列并更新数据库中的 TaskInstance 的状态(例如“完成”、“失败”等)。

一旦所有的 DAG 处理完毕后,就会进行下一轮循环处理。这里还有一个细节就是上一轮的某个 DAG 的处理时间可能很长,导致到下一轮处理的时候这个 DAG 还没有处理完成。Airflow 的处理逻辑是在这一轮不为这个 DAG 创建进程,这样就不会阻塞进程去处理其余 DAG。

737f6e70b6a20cc0731c22e6c8420443.png

文档原文:

Enumerate the all the files in the DAG directory.

Start a configurable number of processes and for each one, assign a DAG file to process.

In each child process, parse the DAG file, create the necessary DagRuns given the state of the DAG's task instances, and for all the task instances that should run, create a TaskInstance (with the SCHEDULED state) in the ORM.

Back in the main scheduler process, query the ORM for task instances in the SCHEDULED state. If any are found, send them to the executor and set the task instance state to QUEUED.

If any of the child processes have finished, create another process to work on the next file in the series, provided that the number of running processes is less than the configured limit.

Once a process has been launched for all of the files in the DAG directory, the cycle is repeated. If the process to parse a particular DAG file is still running when the file's turn comes up in the next cycle, a new process is not launched and a process for the next file in the series is launched instead. This way, a DAG file that takes a long time to parse does not necessarily block the processing of other DAGs.

Scheduler 模块代码结构DagFileProcessor 在子进程中解析 DAG 定义文件。对于发现的 DAG,检查 DagRun 和 TaskInstance 的状态。如果有 TaskInstance 可以运行,将状态标记为 SCHEDULED。为每个 DAG 文件分配一个进程,同时在 DagFileProcessorManager 中保存有 DAG 和 processor 的映射表。在 DAG 没有被任何 processor 处理的时候,才会给它创建新的处理进程。

DagFileProcessorManager 控制 DagFileProcessors 如何启动。它追踪哪些文件应该被处理并且确保一旦有一个 DagFileProcessor 完成解析,下一个 DAG 文件应该得到处理。并且控制 DagFileProcessors 的数量。

SchedulerJob 通过 Agent 获取 manager 的 DAG 定义文件解析结果,并且将 SCHEDULED 状态的 TaskInstance 发送给 executor 执行。

DagFileProcessorAgent 作为一个采集代理,scheduler 可以借助 Agent 获取 manager 获取到的 DAG 解析结果,并且可以控制manager的行为。

核心类分析Dag

method:

following_schedule() 计算当前 DAG 的下一次调度时间

previous_schedule() 计算当前 DAG 的上一次调度时间

get_dagrun() 返回给定执行日期的 dagrun(如果存在)

create_dagrun() 创建一个包括与此 DAG 相关任务的 dagrun

ckear() 清除指定日期范围内与当前 DAG 相关的一组任务实例

run() 实例化为 BackfillJob 同时调用 job.run()

DagRun

model:

ID_PREFIX = 'scheduled__'

ID_FORMAT_PREFIX = ID_PREFIX + '{0}'

id = Column(Integer, primary_key=True)

dag_id = Column(String(ID_LEN))

execution_date = Column(UtcDateTime, default=timezone.utcnow)

start_date = Column(UtcDateTime, default=timezone.utcnow)

end_date = Column(UtcDateTime)

_state = Column('state', String(50), default=State.RUNNING)

run_id = Column(String(ID_LEN))

external_trigger = Column(Boolean, default=True)

conf = Column(PickleType)

method:

get_dag() 返回与当前 DagRun 相关的 Dag

get_task_instances() 返回与当前 DagRun 的所有 TaskInstances

update_state() 根据 TaskInstances 的状态确定 DagRun 的总体状态

get_latest_runs() 返回每个 Dag 的最新一次 DagRun

TaskInstance

model:

__tablename__ = "task_instance"

task_id = Column(String(ID_LEN), primary_key=True)

dag_id = Column(String(ID_LEN), primary_key=True)

execution_date = Column(UtcDateTime, primary_key=True)

start_date = Column(UtcDateTime)

end_date = Column(UtcDateTime)

duration = Column(Float)

state = Column(String(20))

_try_number = Column('try_number', Integer, default=0)

max_tries = Column(Integer)

hostname = Column(String(1000))

unixname = Column(String(1000))

job_id = Column(Integer)

pool = Column(String(50), nullable=False)

queue = Column(String(256))

priority_weight = Column(Integer)

operator = Column(String(1000))

queued_dttm = Column(UtcDateTime)

pid = Column(Integer)

executor_config = Column(PickleType(pickler=dill))

method:

get_dagrun() 返回当前 TaskInstance 的 DagRun

run() TaskInstance run

get_template_context() 通过 Jinja2 模板获取上下文

xcom_push() 创建一个 XCom 可用于 task 发送参数

xcom_pull() 创建一个 XCom 可用于 task 接收参数

SchedulerJob

def _execute(self):

"""

The actual scheduler loop. The main steps in the loop are:

#. Harvest DAG parsing results through DagFileProcessorAgent

#. Find and queue executable tasks

#. Change task instance state in DB

#. Queue tasks in executor

#. Heartbeat executor

#. Execute queued tasks in executor ake_aware(execution_date,

self.task.dag.timezone)

"""

self.processor_agent = DagFileProcessorAgent()  # 通过检查当前 processor 数量来控制进程个数

self.executor.start()

# Start after resetting orphaned tasks to avoid stressing out DB.

self.processor_agent.start()  # 在解析 DAG 文件时,只会对最近修改过的文件进行解析

execute_start_time = timezone.utcnow()

# For the execute duration, parse and schedule DAGs

while (timezone.utcnow() - execute_start_time).total_seconds() 

self.run_duration or self.run_duration 

# Starting Loop...

self.processor_agent.heartbeat()  # 控制 DagFileProcessor 解析 DAG 文件的速度

# Harvesting DAG parsing results

simple_dags = self.processor_agent.harvest_simple_dags()

if len(simple_dags) > 0:

self._execute_task_instances()

...

# Call heartbeats

self.executor.heartbeat()

# heartbeat() 中根据 parallelism 得出当前可用的 slots 数量,

# 决定 execute_async 多少个 task

# Process events from the executor

self._process_executor_events(simple_dag_bag)

# Ran scheduling loop for all tasks done

...

# Stop any processors

self.processor_agent.terminate()

# Verify that all files were processed, and if so, deactivate DAGs that

# haven't been touched by the scheduler as they likely have been

# deleted.

...

self.executor.end()

method:

create_dag_run() 根据调度周期检查是否需要为 DAG 创建新的 DagRun。如果已调度,则返回 DagRun,否则返回 None

process_file() 解析 DAG 定义文件

_execute_task_instances() 尝试执行调度器调度过的 TaskInstances

There are three steps:

Pick TaskInstances by priority with the constraint that they are in the expected states and that we do exceed max_active_runs or pool limits.

Change the state for the TaskInstances above atomically.

Enqueue the TaskInstances in the executor.

reduce_in_chunks() 用来进行小的分批处理

总结本文在第一部分着重介绍了 Airflow 的理念、使用场景及其一般架构。

提供了相对简单易懂的安装及操作命令,并附带了一个使用案例用来介绍代码如何编排以及 WebUI 的使用。

在第二部分开篇介绍了 Airflow 任务创建、调度和管理的一些基础概念,以及 Airflow 版本迭代的一些重要变化。Airflow 目前还是处于快速开发中,当前版本有很多遗留问题,版本升级也不是向后兼容的,变动很大。

Scheduler 毫无疑问是整个 Airflow 的核心模块,逻辑结构复杂。本文从 Scheduler 模块的主要逻辑入手,分析了控制循环和代码结构,重点分析了从 dag.py 代码文件到可调度执行的 TaskInstances 所经历的阶段;以及介绍了并发控制的实现和性能优化。

最后结合源码介绍了 Airflow 核心类的模型定义和主要方法,以了解各个类所扮演的角色及其实现的功能。

参考https://zhuanlan.zhihu.com/p/90282578

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wps怎么旋转页面_用WPS文字编辑一份试卷,详细教程来了,老师们赶快收藏吧

​ 试卷是每一个教师接触最多的资料了,很多教师在检测前找一些现成的试卷复印给学生练习,但是,有很多题不适合学生,因此,我们需要自己编辑一份试卷了,编辑试卷也并不是很难的,今天,就…

Java命令行界面(第15部分):Jargo

Jargo在其GitHub主页上定义为“一种减轻程序参数/选项处理的工具”。 当已经存在许多其他命令行处理库时,该页面为另一个命令行处理库提供了基本原理 ,该列表的顶部是“因为类型安全性,不变性和可读性很重要”。 Jargo的选项“定义”阶段使用…

java中序列化与反序列化_Java中的序列化

java中序列化与反序列化Java提供了一种称为序列化的机制,以按字节的有序或字节序列的形式持久化Java对象,其中包括对象的数据以及有关对象的类型和存储在对象中的数据类型的信息。 因此,如果我们已序列化了任何对象,则可以使用对象…

Java命令行界面(第3部分):jbock

在本系列中有关使用Java进行命令行分析的前两篇文章中,我介绍了Apache Commons CLI和args4j库。 在本系列的第三篇文章中,我将介绍jbock ,它是自我描述的“非常简单的CLI解析器”。 我在Java中进行命令行解析的文章使用了一些示例&#xff0…

java collection详解_java 7 collection 详解(一)

一、综述java集合框架定义了几个接口,这些接口决定了collection类的基本特性。不同的是,具体类仅仅是提供了标准接口的不同实现,如图,java集合框架接口图从图可知,java集合类的主要是由两个接口派生而出——Collection…

jsf tree组件_JSF:在传统组件和时尚性能杀手之间进行选择

jsf tree组件这篇博客文章起源于一个大型Web应用程序中的性能问题。 每个人都优化Java代码,但似乎没有人尝试优化JavaScript代码。 奇怪,因为在客户端有很多改进的空间。 我会说,甚至比服务器端还要多。 我们将分析可编辑的JSF标准组件&#…

如何在Java中转义JSON字符串-Eclipse IDE技巧

在Java应用程序中工作或进行JSON解析时,通常很常见的做法是从某些资源(例如RESTful Web服务)中复制粘贴JSON字符串,然后使用Jackson库解析JSON。 这是测试和学习Java中解析JSON字符串的最快方法,但是这种方法的主要问题…

spring javafx_带有Spring的JavaFX 2

spring javafx我将从一个大胆的声明开始:我一直很喜欢Java Swing或applet。 在那里,我说了。 如果我进行一些自我分析,那么这种钦佩可能是在我接触Java时开始的。 Swing(实际上)是我使用Java所做的第一件事&#xff0c…

jframe和mysql登陆_刚写的一个从数据库读取账户和密码进行登陆的小程序~高手请无~...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.sql.Connection;import java.sql.DriverManager;import java.sql.*; import javax.swing.*;public class LoginSystem extends JFrame{publi…

mycat mysql 物理部署_一、MyCat的搭建

一、什么是mycat简单直接点就是,MyCat其实就是一个数据库的中间件!一般我们都是app直接到数据库!有了MyCat以后,就是app到MyCat然后再访问数据库。mycat是个中间件,它负责连接管理mysql,应用程序连接mycat,把mycat当作…

Apache Camel中的短重试与长重试

《骆驼设计模式》一书介绍了20种模式以及用于设计基于Apache Camel的集成解决方案的众多技巧和最佳实践。 每个模式都基于真实的用例,并提供了Camel特定的实现细节和最佳实践。 为了让您有这本书的感觉,以下是该书的重试模式摘录,其中介绍了如…

java实现驾校考试系统_jsp驾校考试系统

本驾校考试系统采用了Browser/Server体系结构,JSP(Java Server Page)作为前台开发工具,MySQL作为后台数据库进行开发。最终系统实现的系统将分为管理员和学员两个角色,其中系统管理员部分的主要功能包括修改登录密码、学员信息管理、科目1题目…

java qlv转mp4 代码_怎么将qlv格式转换成mp4?教你快速转换视频格式的技巧

如何将qlv格式转换成mp4?众所周知qlv格式是腾讯视频的下载格式,而qlv格式的特点在于不能用别的播放器打开。如果用腾讯视频以外的播放器打开则需要将qlv格式转换成mp4,那你知道将qlv格式转换成mp4的技巧吗?下面小编教你一种转换qlv格式的技巧…

mysql导入竖杠分割的数据_MYSQL :逗号分隔串表,分解成竖表

DROP TEMPORARY TABLE IF EXISTS Temp_Num ;CREATE TEMPORARY TABLE Temp_Num ( xh INT PRIMARY KEY ); -- 创建数字辅助表SET i 0;INSERT INTO Temp_Num(xh) -- 写入数字辅助表SELECT i : i1FROM AdDataCenter.Ad_Targeting_Mobisage aLIMIT 0, 100 ;SELECT b.AdGroupID , SU…

浙大JAVA实验题12_2019浙大计算机考研机试模拟赛(2)——概念专题

题目链接 引用自晴神OJA - 边覆盖B - 极大独立集C - 稳定婚姻问题D - 笛卡尔树没赶得上全程的比赛,就做了两道,后面两道以后有时间再补。两道都是概念题,比较基础~ 以下是题解A - 边覆盖Case Time Limit: 200 MS (Others) / 400 MS (Java) …

hadoop小型集群_小型Hadoop集群的Ganglia配置和一些故障排除

hadoop小型集群Ganglia是一个针对大型集群的开源,可扩展且分布式的监视系统。 它收集,汇总并提供数十种与计算机相关的指标(例如CPU,内存,存储,网络使用情况)的时序视图。 您可以在UC Berkeley …

spring aop组件_安全性中的Spring AOP –通过方面控制UI组件的创建

spring aop组件以下文章将显示在我参与的一个项目中,我们如何使用Spring的AOP来介绍一些与安全性相关的功能。 这样的概念是,为了使用户能够看到某些UI组件,他需要具有一定级别的安全特权。 如果不满足该要求,则不会显示UICompone…

使用Spring Boot构建RESTFul服务

每个人都在谈论微服务,例如WSO2微服务框架 , Spring Boot等。由于我已经很长时间没有从事任何与Spring相关的项目了,所以我想到了使用Spring Boot实现一个简单的RESTFul服务。 因此,我从Spring文档开始。 这很简单。 您可以使用“…

将Swagger与Spring Boot REST API集成

在上一篇文章中,我谈到了我使用Spring Boot创建RESTFul Services的经验。 在创建REST API时,正确的文档是其中的必需部分。 昂首阔步是什么? Swagger (Swagger 2)是用于描述和记录REST API的规范。 它指定了REST Web…

php滴滴平台接口,图片服务API文档

简介滴滴云图片服务API提供标准的轻量级无状态HTTP接口,支持用户对数据的全方位管理。接口概览API描述图片信息获取文件的基本信息,包括长度、宽度、文件大小、格式。图片旋转将图片按顺时针旋转。图片模糊对图片进行模糊操作。图片缩放将图片缩小或者放…