网站首页 文章专栏 《python微服务开发》
微服务的缺陷: - 不合理的拆分 - 更多的网络交互 - 数据存储与分享 - 兼容性问题 - 测试
greenlet是一个特别的CPython实现,用于将控制权从一个函数移交到另一个。这样可以在知道会阻塞时切换请求,但缺点在于需要显示完成,代码混乱。
gevent 构建在greenlet上层,采用隐性方式在greenlet之间切换。缺点是需要底层库的支持。
Twisted是异步的http框架,非WSGI标准,原生异步,比较难调试。Tornado类似,但是它有更轻的路由系统。
协程是能暂停和恢复程序执行的功能。asyncio模块使用async和await关键字来扩展Python语言实现协程。这让异步代码看起来接近于同步函数。 aiohttp就是一个使用协程的http框架。
GIL会限制python的速度。一种方法是使用Cython,会使代码更加复杂;另一种是用PyPy解释器来运行应用。
测试分为单元测试、功能测试、集成测试,负载测试和端到端测试。集成测试是不进行任何模拟的功能测试。端到端测试是使用客户惯用的UI进行测试。
可以用unittest和requests_mock来进行单元测试;用FlaskClient做功能测试;用Boom做负载测试,它类似于apache bench; 用Molotov做有交互的负载测试;用locust.io负载测试框架做更重的负载测试(将测试分发给多个代理).
在做负载测试时可能会想看服务器的一些指标,这时可以用Flaks Profiler。还可以用StatsD发送详细指标,并用Graphite等专用仪表盘应用。
WebTest是一个测试框架,有flask版本flask_webtest可用。可以通过修改HTTP_SERVER变量切换功能测试与集成测试。
pytest是另一个支持扩展的测试工具,会运行所有以test_开头的模块。pytest-cov扩展使用ocverage显示项目测试覆盖率,pytest-flake8运行Flake8 linter来确保代码遵循PEP8标准,而且不存在未使用的导入。
Tox是另一个与pytest结合的工具,可以在多个不同python版本中运行测试。
使用Sphinx生成python项目文档,使用Autodoc-Sphinx扩展可以从源代码中提取docstring,然后插入文档中。
持续集成可以使用Travis-CI,托管文档使用readthedocs,测试覆盖率使用coveralls
一个Python Web应用中重复性后台任务的流行方案是使用Celery,它是一个在独立进程中执行某些工作的分布式任务队列。
用户密码应该做哈希后再传输,可以使用的库有werkzeug.generate_password_hash和check_password_hash。而管理用户登录可以用Flask-Login模块,该模块只管理用户登录。如果需要使用权限管理,可以使用Flask-Principal。
Swagger(openapi)是一个帮助定义微服务之间API的良好工具。
缓存机制可以告诉客户端服务器上的资源是否发生更改,简单的方案是添加一个ETag头。给出了Flask添加ETag的方法。
压缩数据可以用gzip和二进制,二进制的可选方案有Protocol Buffers和MessagePack.前者类似数据库,需要先定义数据格式,而后者是一种无模式的二进制工具,只要通过一个函数就可以实现压缩和解压。
使用发布订阅模式可以实现微服务的异步调用,RabiitMQ是一个TCP服务器,在内部管理队列,并通过RPC调用将消息从发布者分发到订阅者服务器。python与RabbitMQ的交互可以用Pika,这是一个python rpc客户端,实现了针对Rabbit功能的所有RPC接口。
python内置logging模块,但在分布式系统中,这种方式无法扩展。Sentry可以集中管理错误日志,还提供用户界面来展示回溯信息,但它专注错误处理,不适合通用日志。Graylog是一个通用日志应用,日志保存在Elasticsearch中,使用MongoDB存储应用数据。python中可以用graypy包使用Graylog。
系统指标可以通过psutil获得,比如cpu、内存、磁盘。
使用PyJWT为微服务生成令牌,适用于微服务较少的情况。为防止秘钥泄露,可以使用公钥、私钥的方式,即使用X.509对令牌签名。在TokenDealer中对令牌进行验证,见 https://github.com/Runnerly/microservice
完整的工作流程如下: 1. TokenDealer为Strava职程保存client_id和client_secret 2. Strava职程使用client_id和client_secret向TokenDealer请求令牌 3. Strava职程在每次向Data Service发送请求时都带令牌。
常见的攻击方式: - SQL注入 - 跨站点脚本(XSS) - 跨站点请求伪造(XSRF/CSRF)
OpenResty是一个内嵌了Lua解释器的nginx分发器,Lua可用来编写Web服务器脚本。使用LuaJIT解释器运行Lua代码时,速度并不比nginx代码慢。OpenResty的速率限制库lua-resty-limit-traffic可以限制nginx流量,类似的包还有lua-resty-waf。
使用Bandit linter可以查找不安全的代码,如注入攻击等。
版本号规则: - MAJOR 会在为当前API引入向后不兼容的更改时递增 - MINOR 会在添加新功能但不破坏现有API时递增 - PATCH只会在修复bug时递增
python打包与分发
目 录 第 1 章 理解微服务 1 1.1 SOA的起源 2 1.2 单体架构 2 1.3 微服务架构 5 1.4 微服务的益处 7 1.4.1 分离团队的关注点 7 1.4.2 更小的项目 8 1.4.3 扩展和部署 8 1.5 微服务的缺陷 9 1.5.1 不合理的拆分 9 1.5.2 更多的网络交互 9 1.5.3 数据的存储和分享 10 1.5.4 兼容性问题 10 1.5.5 测试 10 1.6 使用Python实现微服务 11 1.6.1 WSGI标准 12 1.6.2 greenlet和gevent模块 13 1.6.3 Twisted和Tornado模块 15 1.6.4 asyncio模块 16 1.6.5 语言性能 18 1.7 本章小结 20 第 2 章 Flask框架 21 2.1 选择Python版本 22 2.2 Flask如何处理请求 23 2.2.1 路由匹配 26 2.2.2 请求 30 2.2.3 响应 32 2.3 Flask的内置特性 33 2.3.1 Session对象 34 2.3.2 全局值 34 2.3.3 信号 35 2.3.4 扩展和中间件 37 2.3.5 模板 38 2.3.6 配置 40 2.3.7 Blueprint 42 2.3.8 错误处理和调试 43 2.4 微服务应用的骨架 47 2.5 本章小结 49 第 3 章 良性循环:编码、测试和写文档 51 3.1 各种测试类型的差异 52 3.1.1 单元测试 53 3.1.2 功能测试 56 3.1.3 集成测试 58 3.1.4 负载测试 59 3.1.5 端到端测试 61 3.2 使用WebTest 62 3.3 使用pytest和Tox 64 3.4 开发者文档 67 3.5 持续集成 71 3.5.1 Travis-CI 72 3.5.2 ReadTheDocs 73 3.5.3 Coveralls 73 3.6 本章小结 75 第 4 章 设计Runnerly 77 4.1 Runnerly应用 77 4.2 单体设计 79 4.2.1 模型 80 4.2.2 视图与模板 80 4.2.3 后台任务 84 4.2.4 身份验证和授权 88 4.2.5 单体设计汇总 92 4.3 拆分单体 93 4.4 数据服务 94 4.5 使用Open API 2.0 95 4.6 进一步拆分 97 4.7 本章小结 98 第 5 章 与其他服务交互 101 5.1 同步调用 102 5.1.1 在Flask应用中使用Session 103 5.1.2 连接池 107 5.1.3 HTTP缓存头 108 5.1.4 改进数据传输 111 5.1.5 同步总结 115 5.2 异步调用 116 5.2.1 任务队列 116 5.2.2 主题队列 117 5.2.3 发布/订阅模式 122 5.2.4 AMQP上的RPC 122 5.2.5 异步总结 122 5.3 测试服务间交互 123 5.3.1 模拟同步调用 123 5.3.2 模拟异步调用 124 5.4 本章小结 127 第 6 章 监控服务 129 6.1 集中化日志 129 6.1.1 设置Graylog 131 6.1.2 向Graylog发送日志 134 6.1.3 添加扩展字段 136 6.2 性能指标 137 6.2.1 系统指标 138 6.2.2 代码指标 140 6.2.3 Web服务器指标 142 6.3 本章小结 143 第 7 章 保护服务 145 7.1 OAuth2协议 146 7.2 基于令牌的身份验证 147 7.2.1 JWT标准 148 7.2.2 PyJWT 150 7.2.3 基于证书的X.509身份验证 151 7.2.4 TokenDealer微服务 154 7.2.5 使用TokenDealer 157 7.3 Web应用防火墙 160 7.4 保护代码 166 7.4.1 断言传入的数据 166 7.4.2 限制应用的范围 170 7.4.3 使用Bandit linter 171 7.5 本章小结 174 第 8 章 综合运用 175 8.1 构建ReactJS仪表盘 176 8.1.1 JSX语法 176 8.1.2 React组件 177 8.2 ReactJS与Flask 181 8.2.1 使用 bower、npm和babel 182 8.2.2 跨域资源共享 185 8.3 身份验证与授权 188 8.3.1 与数据服务交互 188 8.3.2 获取Strava令牌 189 8.3.3 JavaScript身份验证 191 8.4 本章小结 192 第 9 章 打包和运行Runnerly 195 9.1 打包工具链 196 9.1.1 一些定义 196 9.1.2 打包 197 9.1.3 版本控制 204 9.1.4 发布 206 9.1.5 分发 208 9.2 运行所有微服务 210 9.3 进程管理 213 9.4 本章小结 216 第 10 章 容器化服务 217 10.1 何为Docker? 218 10.2 Docker简介 219 10.3 在Docker中运行Flask 221 10.4 完整的栈——OpenResty、Circus和Flask 223 10.4.1 OpenResty 224 10.4.2 Circus 226 10.5 基于Docker的部署 228 10.5.1 Docker Compose 230 10.5.2 集群和初始化简介 231 10.6 本章小结 233 第 11 章 在AWS上部署 235 11.1 AWS总览 236 11.2 路由:Route53、ELB和AutoScaling 237 11.3 执行:EC2和Lambda 237 11.4 存储:EBS、S3、RDS、ElasticCache和CloudFront 238 11.4.1 消息:SES、SQS和SNS 240 11.4.2 初始化资源和部署:CloudFormation和ECS 241 11.5 在AWS上部署简介 242 11.5.1 创建AWS账号 242 11.5.2 使用CoreOS在EC2上部署 244 11.6 使用ECS 部署 247 11.7 Route53 251 11.8 本章小结 253 第 12 章 接下来做什么? 255 12.1 迭代器和生成器 256 12.2 协同程序 259 12.3 asyncio库 260 12.4 aiohttp框架 262 12.5 Sanic 262 12.6 异步和同步 264 12.7 本章小结 265