摆脱 Docker Desktop 即将到来的收费

最近本人在 Mac OS X 下安装的 Docker Desktop 经常蹦出要升级的窗口,Skip this update PRO 不能用,Install & Restart  也总是失败,所以每次只能 SNOOZE。原来觉得事有蹊跷,后来才知道这或许与近日吵得沸沸扬扬的 Docker Desktop 收费计划有关。Docker Desktop 是专门为 Windows 和 Mac OS X 定制的,Mac OS X 和 Windows  都是开发人员用的平台。Linux 下可以不用 Docker Desktop,Linux 下 Docker 之间甚至一层窗户纸都没有,实际部署的 Docker 服务也是运行在 Linux 下的。

墙里边微信正在谋划着对聊天记录的云存储收年费,外边是 Docker 在向大公司和开发人员下手,这难道是美国加州版的共同富裕? 阅读全文 >>

DynamoDB Stream 应用及触发 Lambda 函数

DynamoDB Stream 的实质就是一个依附于表的流,对表的增删改像关系型数据的触发器一样,以日志形式按顺记录到该流中。我们可以用 API 去读取其中的记录,或用来触发一个 Lambda。DynamoDB Stream 非常类似于 Kinesis 的 Stream, 它们都是有 Shard 的概念,但是 DynamoDB Stream 的 Shard 数目是不太确定的。而且还能用 KCL(Kinesis Client Library) 来操作 DynamoDB Stream。

DynamoDB Stream 和 Kinesis Stream 有几个通用的 API 操作,像 list_streams(), describe_stream(), get_shard_iterator() 和 get_records() 函数。同时呢,在设置 Lambda 的触发器时,选择 DynamoDB Stream 与 Kinesis Stream 时可配置的参数几乎是一样的,有 Batch size, Batch window, Starting position 以及重试策略。而且也是一个 Shard 只能同时启动一个 Lambda 实例,由于 DynamoDB Stream 的 Shard 数目不太确定,所以它能同时启动几个 Lambda 实例也不确定的。

另外, 一个 DynamoDB Stream 只能最多被两个 Consumer 消费,而可用来消费 Kinesis Stream 的 Consumer 数目是不受限的。DynamoDB Stream 中的记录保存时间为 24 小时, Kinesis Stream 中记录保存时间也是可配置的。我们创建一个 DynamoDB 表时还能启用 Amazon Kinesis data stream details, 即把对 DynamoDB 的操作记录直接发送到 Kinesis Stream 中去,这样就能操作熟悉的 Kinesis Stream,Shard 数目可设定,坏处就是 Kinesis Stream 较费钱。 阅读全文 >>

如何调试 ECR Docker 镜像

常常因为在 AWS 上部署的 ECS 或 EKS 服务,甚至是使用了 ECR 镜像的 Lambda 服务这样或那样的原因无法启动,或其他莫名的异常,这时候最好能直接调试 ECR 上的 Docker 镜像,比调试用于打包 Docker 的源代码更接近真实环境。

要调试 Docker 镜像需要先从 ECR 中下载到 AWS 服务用的镜像,下面以运行 Java 的 Docker 为例,同时用 IntelliJ IDEA 关联源代码进行远程调试。

从 ECR 下载 Docker 镜像部分可参考 推送 Docker 镜像到 Amazon ECR 仓库, 那篇文章写作之时可能与现在略有不同。具体需直接进到 ECR 的页面,如 https://console.aws.amazon.com/ecr/repositories/private/<aws_account_id>/<ecr_name>?region=<region>,点击 View push commands 可看到用 AWS CLI 如何登陆 ECR,现在看到的在 macOS/Linux 下的命令是(假设 AWS AccountId 是 123456789, region 是 us-east-1)

aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com

假如 ECR 仓库名是 test-java, 那么要下载 tag 1.0.1 的命令是 阅读全文 >>

Python 子进程与子进程池的应用

去年记录过一篇如何使用 Python 的线程,线程池的日志 Python 多线程编程, 需用到 threading.Thread, concurrent.futures.ThreadPoolExecutor。本文可以当作是上一文 Python 多线程编程的姊妹篇。

Python 的多线程受到 GIL(Global Interpreter Lock) 的限制,GIL 是一把加到了 Python 的解释器的锁,使得在任意时刻只允许一个 Python  进程使用 Python 解释器,也就是任意时刻,Python 只有一个线程在运行。

GIL 严重影响了计算密集型(CPU-bound) 的多线程程序,此时的多线程与单线程性能没什么差异,也发挥不了多核的威力。但对 I/O 密集型(I/O-bound) 影响不大,因为 CPU 多数时候是在等待。

为了突破 GIL 的 CPU 密集型程序的限制,可以使用非 CPython 解释器,如 Jython, IronPython 或 PyPy, 更为现实的做法就是使用子进程来替代线程去承担较为繁重的计算任务,因为 GIL 是加在进程上的,所以新的进程有独立的 GIL. 阅读全文 >>

Python 调用动态库时 Segmentation fault (core dumped) 问题

这几天一直纠缠在如何调用动态库的问题上,先是 Go 语言,而后迁移到 Python 语言。在测试 Python 调用动态库时,出现过 "Segmentation fault (core dumped)" 的问题,本文记录下怎么去寻找线索,找到并解决问题的。

出现 "Segmentation fault (core dumped)" 的原因是多方面的,比如在 C/C++ 语言中

  1. 内存访问越界(数组越界,strcpy, strcat, sprintf, strcmp 等字符串函数读写越界)
  2. 多线程使用了线程不安全的函数
  3. 多线程读写的数据未加锁保护
  4. 非法指针(NULL 指针,随意的指针类型转换
  5. 堆栈溢出(如大的分配在栈上的局部变量)

用 Python 来调用动态库很大的可能性会是内存访问越界 阅读全文 >>

Python 调用 C 动态库(Linux)

Go 调用 C 写的动态库完整例子(Linux版) 弄完了 Go 语言如何调用动态库,又开始琢磨起 Python 怎么调用动态库,首先仍然是以前一篇中的 C 实现为例,C 函数为原型为 char * Add(char* src, int n), 由于用符号直接定位函数,所以无需 C 的头文件。本文仍然是以 Linux 平台为例,GCC 编译为动态库 so 文件。并实验了两个例子,一个为基本的类型,char* 和  int, 再一个就是在 C 中使用到了结构体指针和无类型指针(void*) 时,如何在 Python 进行调用。

测试环境为:

  1. Linux Ubuntu 20.04
  2. gcc: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
  3. Python: 3.8.10

阅读全文 >>

Go 运行期加载 C 动态库(Linux版)

前面写的一篇 Go 调用 C 写的动态库完整例子(Linux版),是在告诉编译器用 /* #cgo ...*/ 的方式去加载动态库 libadd.so,这让代码丧失了一定的灵活性,比如同样的函数由多个动态库提供了不同的实现。这就需要做到在 Go 程序中可根据不同的输入条件选择不同的动态库实现,大概是

if 条件1 {
    loadLibrary("libadd1.so")
    调用其中的实现函数 add
else if 条件 2 {
    loadLibrary("libadd2.so")
    调用其中的实现函数 add
else {
    loadLibrary("libaddx.so")
    调用其中的实现函数  add

当然上面那样写是不行的,首先每一个动态库应该在程序运行期间只加载一次,定位的函数应该要缓存起来复用。 阅读全文 >>

Go 语言使用 Go Modules(go.mod) 来管理依赖

前几日系统性差不多读完了一本讲解 Go 语言的书籍,记录下几篇笔记,现在终于能够开始看看专题性的知识了。首先就是关于 Go 如何管理依赖的问题,Java 经历了最早逐个下载  jar  包,到现在用 maven 来描述项目依赖,及进行项目的构建。而 Go 的起点还是要高一些,从一开始就有  go get, go install 命令来从中心库下载依赖。但管理多版本依赖是个问题,也没有明确的方式来怎么描述一个项目的依赖。

因此也就产生过一些第三方的 Go 依赖管理

  1. Glide(使用 glide.yaml 文件描述依赖)
  2. Godep (长时间没维护的项目)
  3. govendor (不再维护了,在 Go modules 出来后也不被推荐使用)
  4. 还有其他的 GPM, gb, gom, gvt 等都相继退出了历史的舞台

也就是说 Go Modules 才是王道,在理解 Go Modules 之前也许有必要了解一下传统 GOPATH 管理依赖的方式,其他第三方的管理工具用不着去学习了,早已成了云烟。

Go 语言首次在  1.11 版本中引进了 Go Modules, 在这之前或者没有启用 GO111MODULE 的话,我们用 go get 或 go install 来下载依赖,编译器会从 GOPATH 和 vendor 文件夹中查找包。 阅读全文 >>

Go 调用 C 写的动态库完整例子(Linux版)

总有那么一些老的,或高效的库是用 C/C++ 实现的,于是在其他语言中如果使用动态共享库就成了个问题。Java 要调用动态库需要用 JNI, 更快捷的话可使用第三方包装好的 JNI 调用库。在 Java 中要映射 C/C++ 的类型麻烦些,因为 Java 没有指针类型,所以从这方面来讲 Go 调用动态库幸许会更简单些。

下面我们自己在 Linux 下做一个动态库(.so 文件  - Shared Object),然在用 Go 来使用它。本文所用的操作系统为 Ubuntu20.04, 以 gcc  作为编译器。动态库的生成过程参考自 Linux动态库生成与使用指南 阅读全文 >>

Go 语言新手笔记(五)

终于来到的 Go 的网络编程了,来写一个 TCP 服务端与客户端的程序。要用到 Go 语言的  net 包,是一个标准的 Listen+Accept 结构, 下面是一个简单的 TCP Server/Client 端的例子,启动了 Server 端口,可以用 telnet 去连接,也可以用 client.go 来连接 阅读全文 >>