Cách xử lý nhiều yêu cầu tranh chấp một tài nguyên ở cùng một thời điểm khi scaling Kubernetes Pod

0 0 0

Người đăng: Ninetyeight Savage

Theo Viblo Asia

Tôi có một business service (tạm gọi là Service W được viết bằng Nodejs) được subscribe vào keyspace của Redis theo cơ chế pub-sub (đang được serve trên Kubernetes), Service W này hoạt động như một worker có nhiệm vụ lắng nghe thông báo khi một redis key hết hạn, tiếp theo đó nó sẽ xử lý một số logic cập nhật xuống database (tôi dùng Prisma Orm để mapping tới Postgres) và publish một message vào Kafka cho một tài nguyên duy nhất

1. Vấn đề gặp phải

Lấy ví dụ dưới đây là một đoạn logic của Service W xử lý khi lắng nghe event từ Redis

const movieName = 'Bleach thousand year blood war' const availableSeat = await prisma.seat.findFirst({ where: { movie: { name: movieName, }, claimedBy: null, },
}) if (!availableSeat) { throw new Error(`Oh no! ${movieName} is all booked.`)
} await prisma.seat.update({ data: { claimedBy: userId, }, where: { id: availableSeat.id, },
}) // Send kafka an event to do something
await producer.send({ topic: 'topic-name', messages: [] })

Đối với đoạn logic phía trên, khi scale Service W lên N-pods (workers) thì sẽ có tương đương được subscribes vào Redis, khi một redis key hết hạn thì N-pods (workers) sẽ nhận được same event ở cùng một thời điểm (cơ chế pub-sub) dẫn tới sẽ gửi cho Kafka N-messages giống nhau (duplicated messages)

2. Cách giải quyết

Theo bài toán ở trên sẽ có nhiều cách để xử lý, nhưng trong bài này tôi sẽ đề cập tới Optimistic concurrency control

Optimistic concurrency control là một mô hình xử lý các hoạt động đồng thời trên một thực thể duy nhất mà không dựa vào locking (bạn có thể tìm hiểu thêm về cơ chế này), hiểu đơn giản OCC sẽ sử dụng mã thông báo (trường version hoặc timestamp trong table) để phát hiện những thay đổi với bản ghi

Chúng ta cần thay đổi logic một chút để thoả điều kiện chỉ một worker được gửi message tới Kafka, tránh duplicated messages

const userEmail = '98savage@gmail.io'
const movieName = 'Bleach thousand year blood war' const availableSeat = await client.seat.findFirst({ where: { Movie: { name: movieName, }, claimedBy: null, },
}) if (!availableSeat) { throw new Error(`Oh no! ${movieName} is all booked.`)
} const seats = await client.seat.updateMany({ data: { claimedBy: userEmail, version: { increment: 1, }, }, where: { id: availableSeat.id, version: 0, },
}) if (seats.count === 0) { throw new Error(`That seat is already booked! Please try again.`)
} // Send kafka an event to do something
await producer.send({ topic: 'topic-name', messages: [] })

Đối với cách thay đổi này, khi N-pods (workers) nhận same event ở cùng một thời điểm, thì chỉ có một worker xử lý và gửi message vào kafka, còn các workers còn lại sẽ throw error bởi vì worker đảm nhiệm nó đã tăng version record từ 0 lên 1, các worker còn lại query version record = 0 không còn match đối với record đó nữa

Related links:

https://www.prisma.io/docs/orm/prisma-client/queries/transactions#optimistic-concurrency-control

https://redis.io/docs/latest/develop/use/keyspace/

Bình luận

Bài viết tương tự

- vừa được xem lúc

Caching đại pháp 2: Cache thế nào cho hợp lý?

Caching rất dễ. Mình không nói đùa đâu, caching rất là dễ. Ai cũng có thể làm được chỉ sau 10 phút đọc tutorial. Nó cũng giống như việc đứa trẻ lên 3 đã có thể cầm bút để vẽ vậy.

0 0 126

- vừa được xem lúc

Caching đại pháp 1: Nấc thang lên level của developer

Bí quyết thành công trong việc đáp ứng hệ thống triệu user của những công ty lớn (và cả công ty nhỏ). Tại sao caching lại là kỹ thuật tối quan trọng để phù phép ứng dụng rùa bò của chúng ta thành siêu phẩm vạn người mê.

0 0 82

- vừa được xem lúc

Cache dữ liệu Nodejs với Redis

Một tí gọi là lý thuyết để anh em tham khảo. Cache là gì. Lợi ích của việc cache data. .

0 0 111

- vừa được xem lúc

Nguyên tắc hoạt động của redis server

Sự ra đời của Redis. . Câu chuyện bắt đầu khi tác giả của Redis, Salvatore Sanfilippo. (nickname: antirez), cố gắng làm những công việc gần như là không.

0 0 97

- vừa được xem lúc

Viết ứng dụng chat realtime với Laravel, VueJS, Redis và Socket.IO, Laravel Echo

Xin chào tất cả các bạn, đây là một trong những bài post đầu tiên của mình. Sau bao năm toàn đi đọc các blog tích luỹ được chút kiến thức của các cao nhân trên mạng.

0 0 918

- vừa được xem lúc

Tìm hiểu tổng quan về Redis

1. Lời mở đầu.

0 0 368