Python Flask 框架的并发能力及线,进程模型

本文旨在测试 Python Flask 框架的默认并发能力,即同时能处理多少个请求,以及请求等待队列大致有多大; 并找到如何改变默认并发数。虽然网上或许很容易找到它们的默认并发数,但通过实验的方式可以得到更感性的认识。

本文写作时使用的环境为

  1. 测试机器为 MacBook Pro, CPU 6 核超线程,内存 16 Gb
  2. JMeter 5.5 -- 连续发送请或压力测试
  3. Python 3.10.9
  4. Flask 2.2.2

从 JMeter 每半秒发送一个请求,连续发送 1000 个,程序中 API 方法接受到请求后 sleep 800 秒,保证在全部 1000 个请求送出之前一直占着连接,以此来找到同时被处理的请求数目,并且有足够的时间统计当前的 TCP 连接数。在测试极端规模的并发数时,由于在 Mac OS X 很难突破 5000 个线程的限制,这时就让 JMeter 分布到远程 Linux(Docker 或虚拟机) 上执行。

请求的 URL 是 http://localhost:8080/?id=${count}, 带一个自增序列用以识别不同的请求, JMeter 的 Thread Group 配置为 Number of Threads (users): 1000, Ramp-up period (seconds): 500 阅读全文 >>

远程方式执行 JMeter 测试

JMeter 是一个极好的测试 Web API 及压力测试的工具,另一个的话就是 Python 版的 LOCUST(它也能远程运行测试)。JMeter 的测试可以在本地模拟并发用户,那么为什么要远程执行 JMeter 测试呢?因为一台机器能模拟的并发用户数受限,一个用户就是对应着一个 Java 线程。比如我在 MacBook Pro(内存 16Gb) 上无论如何调整 ulimit -n, ulimit -u, 或用 JAVA_TOOL_OPTIONS, HEAP, JVM_ARGS 设置 -Xmx, 调大到 10 G, 或用 -Xss 调小栈大小,都无法让 JMeter 模拟的用户数达到 5000。

文后有本人亲自测试 Java/Python 在 Mac OS X 和 Linux 下可创建多少个线程

如果能够远程运行 JMeter 的测试就能突破单机上的线程限制了,比如 Mac OS X 不行,找个 Linux 远程机器(可以是虚拟机)来执行,一台机器不够,找多个。想要模拟 15000 个并发用户,测试可分配到 5 台机器上执行,每个节点跑 3000 个用户并发就行,有点操控肉机的感觉。 阅读全文 >>

使用 ECS Exec 直通 ECS 容器会话(适用于 Fargate 和 EC2)

基于 EC2 的 ECS 服务,要看看容器内的状态,一直以来都是先 SSM(Simple System Manager) 或 SSH 进到 EC2 实例,然后再 docker exec -it <container-id> sh, 查看容器的控制台日志则用 docker logs <container-id> [--follow]. 但是对使用 Farget 的 ECS 服务就无能为力了,因为找不到 SSM 或 SSH 的主体, 只能通过程序日志来大概了解容器内发生的事了。

Amazon 在 2021-03-15 推出了一个新的特性 ECS Exec 允许我们直接连接 Fargate 或 EC2 中的容器会话,见 Amazon ECS now allows you to run commands in a container running on Amazon EC2 or AWS Fargate. ECS Exec 支持 Container Agent 版本为 1.50.2 及以上的 ECS Optimized AMI 系列,和 Fargate Platform Version 1.4.0(Linux) 或 1.0.0(Windows) 及以上。

ECS Exec 的实现原理是以往在 EC2 实例上启动的 SSM Agent,也在容器内部启动一份,然后命令 aws ecs execute-command 直指容器本身。参考本人写过的一篇 AWS Session Manager 管理 EC2 实例,连接过程中唯一的不同就是容器中也运行了一个 SSM Agent, 所以这个容器也就无所谓是在 EC2 实例还是在 Fargate 中。

阅读全文 >>

Python 基于多环境的配置方式

部署到不同环境的应用会使用到各自的配置,如 Dev, QA, Stg, Prod 有自己的数据库等资源。Spring Boot 可采用 Profile 对应不同的环境,不同 Profile 选择自己的配置文件 application-${profile}.properties。本人还是偏爱在同一个文件中分组配置,容易查错与编辑,类如在 application.properties 文件中以下面的方式

db.host=aaa
%dev.db.host=bbb
%prod.db.host=ccc 

那么在 Python 的项目中应该如何针对不同环境进行配置呢?大概有以下几种

  1. 不同环境的 Config 类
  2. YAML 文件
  3. TOML 文件
  4. JSON 文件
  5. INI 文件
  6. dotenv(.env) 文件

第一种方式是本人推荐的,其他的方式只是在不同格式的配置文件中,按环境组织不同的配置值,其他方式的不同配置读入内存中基本是体现为字典变量。在 Python 配置中要支持像配置的 placeholder(像 ${host} 还需自己实现。 阅读全文 >>

升级到 Spring Boot 3 后 javax.inject.Named 不可用

为了紧跟 Spring 6 的步伐,Spring Boot 在 2022 年 11 月 24 日释放了 3.0.0. 当前版本是 3.0.1(2022-12-23)。Spring 6 要求用 JDK 17+, Spring Boot 3 自然也要上 JDK 17+ 才能使用,对于一直死死抱住 JDK 8 不放的要升级到 Spring Boot 3 就是个比较大的挑战。

Spring Boot 到底带来了什么显著的特性呢?

  1. 依赖于 Spring 6, 最低 Java 17, 兼容 Java 19
  2. 支持生成 GraalVM 本地映像,取代实验性的 Spring Native 项目
  3. 最低 Java EE 9 和支持 Jakarta EE 10
  4. 依赖从 Java EE 迁移到 Jakarta EE API
  5. 升级到 Tomcat 10

从 Spring Boot 2.x 升级到 Spring Boot 3 的指南请阅官方的文档 Spring Boot 3.0 Migration Guide。Spring Boot 1 的项目还得老老实实的先升级到 Spring Boot 2,如果是早期的 Spring Boot 2,第一步是升级到 Spring Boot 2.7.x, 一步步来,免得步子大了扯到X。再到是把 JDK 换成  17 或更新的版本,编译,运行,有问题就改代码。 阅读全文 >>

Spring Boot Web 输出 Tomcat 的访问日志到控制台

当我们直接使用 Tomcat  时,访问日志的配置在 $TOMCAT_HOME/conf/server.xml 中

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
              prefix="localhost_access_log" suffix=".txt"
              pattern="%h %l %u %t &quot;%r&quot; %s %b" />

产生的日志文件在 $TOMCAT_HOME/logs 目录中,生成以日期戳进行区分的滚动日志文件,如 localhost_access_log.2022-10-25.txt 等

而在我们使用  Spring Boot Web 时, 默认的嵌入式 Web 应用服务器是 Tomcat,我们可以在 Spring 属性文件中配置是否启用 Tomcat 访问日志(默认不启用)。属性文件中的配置针对的是如何输出访问日志到文件,而我们有时候需要输出访问日志到控制台而不非文件,比如 AWS 上的 ECS 应用,控制台的输出可直接发送到 CloudWatch,这样便于分析日志。

在 Spring Web 中可以用 Interceptor 或 Filter 来记录访问日志,但在请求出错时无法准确显示出响应时间和状态码,毕竟 Tomcat 的访问日志在代码的外层,进出 Controller 方法的输入输出信息也就掌握的更清楚。

本文的任务是探索输出 Spring Boot Web 嵌入式 Tomcat 的访问日志到控制台。有两种方式 阅读全文 >>

HDFS 分布式文件系统的搭建与使用

HDFS(Hadoop Distributed File System) 是 Hadoop 的一个重要的模块,有点像磁盘阵列一样,不过它构建的是分布式网络文件系统。由于数据块从多个节上存取,也就能突破单点的网络带宽和硬件资源的限制而获得更好的性能; 能处理更大的数据,和克服单点故障的问题。许多公司正在使用 HDFS 构建自己的分布式文件系统,还比支持它的应用有 Spark, Presto, Hive, HBase, Zeppelin 等。

本文将实战自己搭建一个 HDFS 分布式文件系统,体验最基本的 HDFS 文件操作,看看它是如何分布文件块,以及如何进行冗余容错的。

本次实战环境:

  1. macOS Big Sur 11.7, VirtualBox 6.1.32 r149290, Vagrant 2.2.19
  2. Vagrant Ubuntu 22.04 LTS 虚拟机
  3. Open JDK 8
  4. Hadoop 3.3.4

我们将使用 4 个 Vagrant 虚拟机,其中一个为 NameNode, 其余为 DataNode。HDFS 沿袭了传统的 Master/Slave 系统架构,但因目前像传统的计算机名词 PC, CRT 被恶意使用的当下,Master/Slave 相应的更名为 NameNode 和 DataNode。在通常的系统中, Master 兼具协调与数据存储的功能,而 Slave 只存储数据,而 HDFS 的 NameNode 仅保管文件的元信息,数据块存储在 DataNode 中。

阅读全文 >>

细数 DB2 数据库的 Identity 字段

每种数据都有自己独特的自增列的声明方式,如 Oracle 的 Sequence, SQL Server 的 Identity, MySQL 的 auto_increment, PostgreSQL 的 Sequence 或 Serial。和 PostgreSQL 类似,DB2 也提供两种自增列的声明方式,它们是 Sequence 和 Identity。而本文主要着墨于 DB2 的 Identity 字段,并讲述它与 Sequence 的某种联系,以及它对数据表的导入的影响。

DB2 的 Sequence

在 DB2 中声明一个 Sequence 与表的 Identity 字段的参数差不多,我们可以看作 Identity 是一个内联的 Sequence。先来看如何创建一个序列 阅读全文 >>

向量间距离/相似度及用 Python 进行计算

计算距离的目的也是为了确定两个向量的相似度,这里的向量可以是纯数学的数组,或者是一系列带有某些可量化特征值的物件。写作本文的原由是需要用 Numpy 计算两个实际对象的相似度,实现代码非常简单,因此更不能满足于此,借此机会多多了解下向量之间距离和相似度的概念,还回顾下一些相关的数学知识。

计算两个向量的相似度有许多的方法,如

  1. 欧氏距离(Euclidean Distance): 点间直线距离,数值越小越相似
  2. 夹角余弦(Cosine): 余弦相似度(Cosine Similarity),计算两个向量之间的夹角,值在  -1 ~ 1 之间
  3. 曼哈顿距离(Manhattan Distance): 点间在坐标系上的绝对轴距总和
  4. 切比雪夫距离(Chebyshev Distance): 像国际象棋中的王从一格子到另一个格子间的距离
  5. 标准化欧氏距离(Standardized Euclidean distance): 先对各个分量进行标准化,再求欧氏距离
  6. 其他距离和相关系数,如马氏距离(Mahalanobis Distance), 兰氏距离(Lance Williams Distance); 皮尔逊相关系数(Pearson Correlation Coefficient), 杰卡德相似系数(Jaccard similarity coefficient)

本文主要关注到欧氏距离和余弦相似度这两个数值的求解上。 阅读全文 >>

为 S3 中的 CSV 文件创建带 Partition 的 Athena 表

CSV 文件是纯文本的,对人阅读和编辑来说是最友好的描述表格数据的格式。虽然当前处理大数据时会用到 JSON, avro, parquet 等数据格式,但是在处理平面数据时 CSV 仍然被广泛使用。

S3 Select 能支持 CSV, JSON 和 parquet 格式数据的直接查询。在 AWS s3 控制台选择一个 CSV 文件,从右上的 Object actions 下拉选项上选择 Query with S3 Select 就能直接查询该文件的内容,而无须下载后打开文件。

如 S3 Select 查询语句

SELECT * from s3object WHERE Name='Tom' LIMIT 5

如果 CSV 带 Header 的话,请勾选上 Exclude the first line of CSV data。当然 S3 Select 查看任意的文本文件也行,只是把它当成一个不规则的 CSV 文件来对待。

S3 Select 只能针对单个 S3 文件查询,如果要对一组 CSV 文件同时进行查询的话就要用到 Athena。把相同 Schema 的一系列 CSV 文件放到 S3 的某一个目录中,我们可为它们创建一个  Athena 表,然后查询该 Athena 表就会从对应 S3 目录中扫描所有的 CSV 文件。 阅读全文 >>