一 前言
1 特性
快速开发
(1) 多地域配置:配置支持多地域,配置可以统一管理
(2) 无需配置路由:根据 handlers 目录自动加载路由(目前不支持动态路由)
(3) 显示参数管理:Handler 的参数与 HTTP 参数保持一致,含有参数检查
(4) 简易调试模式:简易方便的 DEBUG
(5) 引擎之状态机:具有可复用性的状态处理
(6) 引擎之工作流:长流程分步执行,可生成 dot 流程图
(7) 对象关系映射:自带 ORM
(8) 定时任务调度:支持定时执行某些方法
方便运维
(1) 请求完整追溯:响应 Header 中包含请求的 reqid(会记录在日志中),便于 trace
(2) 自定义响应头:可自定义 HTTP header,如增加固定的接口版本号
(3) 代码耗时打点:通过代码打点可以准确获代码执行耗时,用于排查性能问题
(4) 线程堆栈打印:发送
kill -10 ${pid}
触发,用于排查程序夯住问题(5) 变量内存打印:发送
kill -12 ${pid}
触发,用于排查内存泄露问题容易扩展
(1) 消息队列通信:开启百川配置即成为消费者,以拉模式消费由其他实例发布的消息
2 架构
2.1 一气化三清
Butterfly 可以很方便将 Python 函数转换为 Http 服务,cmd,任务队列 task
+---------------+ +-------------+ +-------------+
| cmd | |HTTP Request | | Queue Msg |
+------+--------+ +------+------+ +------^------+
| | |
+-----------------------------------------------------+
| | | | |
| +------V--------+ +------V------+ +------+------+ |
| |test_handler.py| | Protocol | | worker | | Butterfly Framework
| +------+--------+ +------+------+ +------+------+ |
| | | | |
+-----------------------------------------------------+
| | |
+--------V------------------V----------------+--------+
| func | Application code
+-----------------------------------------------------+
开发人员将 func code 按照 Butterfly handler 规范放在 <butterfly_project>/handlers/<app_name> package 下
要求:
(1) 装饰器:添加 @funcattr.api 装饰器
(2) 参数:第一个参数增加 req
(3) 返回值:json_status, [content], [headers]
json_status: (string) 必须有,实际返回给用户时,json_status 也会放到 json 串中,如 "OK", "ERR", "ERR_BAD_PARAMS"
content : (dict)非必须,API 返回结果,如 {"data": "test"}
headers : (list)非必须,API headers 如 [("demo", "1.0.1")]
调用:
(1) cmd: python test_handler.py /<app_name>/<handler_name> <args>
(2) HTTP: 启动 Butterfly 后,可以通过 curl "http://<ip>:<port>/<app_name>/<handler_name>?arg=value"
(3) Queue: 开启百川后,自动监听对应 /<app_name>/<handler_name> 的消息
2.1.1 HTTP 请求流
+-------------------------------------------------------------+
| WEB brower |
+-----------------------------------^-------------------------+
/ | |
| +--------------------V--------------|-------------------------+
| | +----------------HTTPServer(Threadpool&Queue)-------------+ |
| | | +-------------------+ put +-----------------------+ | |
| | | |ThreadPool(Queue) <------+ HTTPConnection | | |
| | | |+---------------+ | | +-------------------+ | | |
| | | ||WorkerThread | | | |req=HTTPRequest() | | | |
| | | ||+-+ +-+ +-+ +-+| | | |req.parse_request()| | | |(把 socket 字节流,按 HTTP 协议解析)
| | | ||+-+ +-+ +-+ +-+| | | |req.respond()#^!^ | | | |(封装了 WSGIGateway.response)
| | | |+-|---|---|---|-+ | | +-------------------+ | | |
| | | +--|---|---|---|----+ +-----------------------+ | |
| | +------|---|---|---|-----------------------^--------------+ |
| | | | | | | | WSGI server
| | +------V---V---V---V-WSGIGateway(response)-|--------------+ |
| | | +------------------+-------------+| |
| | |+----------------+ | +----------+ +-------------+ || |
| | || gen environ | | |header_set| |response body| || |
| | |+-----+----------+ | +----------+ +-------------+ || |
| | | | +--^------^----------^-----------+| |
| | +------|-------------------|------|----------|------------+ |
| +--------|-------------------|------|----------|--------------+
| .........|...................|......|..........|......................
| | | | |
| +--------V--------+ | | |
| | req | | | | (1) 封装 environ 为 Request
| +-----------------+ | | | 生成 reqid
Butterfly | | | |
| | | | | \
| +--------V--------+ | | | |(2) 路由
| | apiname_getter | | | | | 在路由字典中匹配 environ['PATH_INFO']
| +-----------------+ | | | | {
| | | | | | '/apidemo/ping':
| | | | | | <xlib.protocol_json.Protocol object>,
| +--------V--------+ False +--+--+ | | | '/{app}/{handler}':
| |is_protocol_exist|------>| 400 | | | | <xlib.protocol_json.Protocol object>
| +-----------------+ +-----+ | | | }
| | | | /
| .........|..........................|..........|......................
| | (protocol_process) | | \
| V | | |(3) 返回 Response
| +-----------------+ | | | 参数:第一个参数为 Request 实例化对象 req
| | protocol | Exception +-----+ | | 其他参数为 GET 请求参数名
| | +-------------+ |------------->| 500 | | | 例子:environ['QUERY_STRING']: 'age=16'
| | |/app1/handler| | +-----+ | | +-------------handler demo---------------
| | |/app2/handler| |Normal+----------------------------+| |@funcattr.api # 标识 handler 类型
| | +--+-------+--+ |----->|httpstatus, headers, content|| |def demo(req, age):# req + HTTP 请求参数
| +----|-------|----+ +----------------------------+| | #(状态信息,数据信息,响应头列表)
| | | | | return "OK", {"data": age}, []
| | | / +----------------------------------------
| | +----V----------------------------------+
| | |+---------+ +---------+ +-----------+|
| | ||DiskCache| | FSM | |APScheduler|| 基础公共库
| | |+---------+ +---------+ +-----------+|
| | +---------------------------------------+
| +----V------------------------------------------+
| | (Redis ORM) / (MySQL ORM) / RAL | 数据访问层
\ +-----------------------------------------------+
2.1.2 Queue msg
+-----------------+
| register worker | 注册 worker
+-------+---------+
|
+-------V---------+
|check_task_status| 检查任务的状态
+-------+---------+
|
+-------V---------+
|queue.dequeue_any| 随机从多个队列中获取消息
+-----------------+
|
+-------V-----------------+
|msg.set_status("started")| 设置消息状态
+-------+-----------------+
|
+-------V---------+
| pool.submit | 提交到多线程队列中
+-----------------+
Last updated