Skip to content

Backend

Upgrade Golang to 1.21

日常升级.

Changes

  • Major
    • [x] go.mod
    • [x] Dockerfile
  • Minor
    • [x] Use builtin slices, slog
    • [x] Use builtin context.WithoutCause()

Check

  • [x] Build all apps' image
  • [x] Call a RPC which used context.WithoutCause()

About 1.21

https://tonybai.com/2023/08/20/some-changes-in-go-1-21/

分章分成四个部分:

  1. 语言本身
  2. 编译器与运行时
  3. 工具链
  4. 标准库

其中比较重要的有: loopvar, GC 优化, slog, 以及兼容性部分

Kimi

总结文章, 给出大纲以及重点, 使用 Markdown 的格式编写:

Go 1.21 版本更新概述:

  • 语言变化
    • builtin 包新增预定义函数:min、max 和 clear
    • 明确了包初始化顺序算法
    • 增强泛型的类型推断能力
    • 修正 Go1 中的两个“陷阱”:panic(nil)和 for 循环变量
  • Go 编译器与运行时变化
    • PGO 默认开启
    • 降低 GC 尾部延迟
    • 支持 WASI
  • Go 工具链更新
    • 向后兼容:扩展和规范化 GODEBUG 的使用
    • 向前兼容:go.mod 文件中的 go line 作为约束规则,引入 toolchain 指示符和 GOTOOLCHAIN 环境变量
  • Go 标准库更新
    • log/slog:结构化日志支持
    • slices、maps 和 cmp:泛型包加入标准库
    • 其他变化:errors.ErrUnsupported、flag.BoolFunc、 net 的多路径 TCP 支持、 reflect.ValueOf 优化、sync.OnceFunc 等
  • 参考资料
    • Go 1.21 Release Notes
    • Go 1.21 版本发布博客
    • 兼容性相关博客
    • Godebug 手册
    • LoopvarExperiment 页面
    • 如何 Golang Evolves without Breaking Programs 文章
    • PGO 用户指南

这个大纲总结了文章中关于 Go 1.21 版本的主要更新和变化, 包括语言特性的变更、编译器与运行时的改进、工具链的更新以及标准库的新增和改动。 同时,列出了文章末尾提供的参考资料链接,方便读者进一步阅读和了解。

Fix docker exec operation not permitted

Issue

服务器执行 docker exec 失败

Text Only
# docker exec -it user-ab107i9 sh
OCI runtime exec failed: exec failed: unable to start container process: open /dev/pts/0: operation not permitted: unknown

搜索一下发现 Issue:

https://github.com/moby/moby/issues/43969

Issue 中提到这个问题在 runc v1.1.4 中已经修复. 检查一下 runc 版本, 为 1.1.3, ok, 确认为 runc 的问题. 想着要升级 docker 版本会造成服务停止问题, 就没处理.

直到今天 [2023-11-30 Thu] 又想起这个问题, 搜了一下, 发现阿里云的文章提到可以避免业务中断的方法^aliyun, 尝试了一下, 没有问题.

Solution

Bash
## Download runc binary
# https://github.com/opencontainers/runc/releases
wget https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64
wget https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64.asc
wget https://raw.githubusercontent.com/opencontainers/runc/main/runc.keyring

## Verify runc binary
gpg --import runc.keyring
gpg --verify runc.amd64.asc runc.amd64

## Replace runc
docker info | grep runc         # Show old version info
sudo mv /usr/bin/runc /usr/bin/runc_old
sudo cp runc.amd64 /usr/bin/runc
sudo chmod +x /usr/bin/runc
docker info | grep runc         # Show new version info

这样就替换完成了, 对于有问题的容器直接重启就可以了.

About runc

runc 是最底层的容器运行时.

以最新版的 Docker 为例, 当我们执行运行容器时, Docker 会调用 containerd, containerd 再调用 runc, 最后通过 runc 来运行容器.

containerd 主要负责以下事情^qikqiak:

  1. 管理容器的生命周期(从创建容器到销毁容器)
  2. 拉取/推送容器镜像
  3. 存储管理(管理镜像及容器数据的存储)
  4. 调用 runc 运行容器(与 runc 等容器运行时交互)
  5. 管理容器网络接口及网络

架构:

containerd

Introduction to the eventbus service

The eventbus service is the Event-Driven Architecture (EDA) implementation in adoba services.

Introduction

Here, Redis Stream data structure serves as the message queue. In other services, events are added to the stream. The eventbus service then consumes these messages and utilizes Remote Procedure Call (RPC) for communication with other services.

See:

sequenceDiagram
  wallet->>redis: Add event to stream
  eventbus->>redis: Read stream
  eventbus->>order: Call RPC

In the past, the prevailing practice was to develop a sidecar queue service, like strandq or studioq, for each individual service. However, this approach introduced redundancy and demanded repetitive effort for each service, making it both time-consuming and resource-intensive. Consequently, a more efficient strategy emerged: consolidating the handling of all events within the eventbus service, eliminating the need for separate management. This consolidation encapsulates the core concept of an "eventbus."

When interacting with an external message system, such as Aliyun MNS, having a dedicated standalone queue service (like strandq) proves advantageous. This design choice preserves the conciseness of the eventbus service and aligns with the single responsibility principle, ensuring clear and modular responsibilities.

Why Event-Driven

Let's talk about the drawbacks first. The big one is that event-driven architecture makes the system more complex, and we have to spend more time developing a new feature.

But advantages are more!

Advantages of Event-Driven Architecture:

  1. Loose Coupling: EDA promotes loose coupling between different components of a system. Components communicate through events, and they don't need to be aware of each other's existence. This characteristic makes it easier to develop, test, and maintain individual components independently.

  2. Enhanced Fault Tolerance: Since components in an event-driven system are decoupled, the failure of one component doesn't necessarily lead to the failure of others. Components can continue processing events even if some other parts of the system are temporarily unavailable. This enhanced fault tolerance ensures system stability during partial failures.

  3. Event Replay: The advantage of replay is the ability to reprocess or reevaluate past events. This is useful for debugging, testing, correcting data, and recovering from errors or failures in a system.

  4. Asynchronous Communication: Events in an event-driven system are often communicated asynchronously. This enables systems to handle high loads and peak traffic more effectively. Components can publish events without waiting for subscribers to process them immediately. Asynchronous communication contributes to the scalability and responsiveness of the system.

  5. Improved Inter-Team Collaboration: When two services are controlled by different teams, EDA becomes an optimal choice, minimizing conflicts and arguments between teams. The loosely coupled nature of EDA allows teams to work more independently without directly impacting each other, fostering smoother collaboration and reducing potential friction.

Design Patterns

Several design patterns align with Event-Driven Architecture, further enhancing its suitability for complex systems. Notable patterns include: