Các thành viên
id SessionId
Id máy chủ được liên kết với phiên này
phương pháp
abortTransaction [ gọi lại ]{Promise}session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",0 của loại hoạt động mà nó muốn chuyển sang
commitTransaction [ gọi lại ]{Promise}session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",2 Tùy chọn giao dịchtùy chọn
Cài đặt tùy chọn cho giao dịch
Các giao dịch là mới trong MongoDB nhưng đã tồn tại trong cơ sở dữ liệu SQL hơn 30 năm. Các giao dịch được sử dụng để duy trì tính nhất quán và chính xác trong các hệ thống cơ sở dữ liệu chịu sự thay đổi đồng thời do nhiều người dùng đưa ra
Các giao dịch thường dẫn đến tính nhất quán được cải thiện với chi phí giảm đồng thời. Do đó, các giao dịch có ảnh hưởng lớn đến hiệu suất cơ sở dữ liệu
Bài đăng này không nhằm mục đích hướng dẫn về giao dịch. Để tìm hiểu cách lập trình giao dịch, hãy xem phần thủ công MongoDB về giao dịch[1]. Trong bài đăng này, chúng tôi sẽ tập trung vào việc tối đa hóa thông lượng giao dịch và giảm thiểu thời gian chờ giao dịch
Giao dịch thoáng quaLỗiKhông giống như nhiều cơ sở dữ liệu giao dịch khác như MySQL hay Oracle, MongoDB không sử dụng khóa chặn để ngăn xung đột giữa các giao dịch. Thay vào đó, nó phát hành
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
8 để hủy bỏ các giao dịch có thể gây xung độtHình bên dưới minh họa mô hình MongoDB. Khi một phiên cập nhật một tài liệu, nó sẽ không khóa nó. Tuy nhiên, nếu phiên thứ hai cố gắng sửa đổi tài liệu trong một giao dịch, một
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
9 sẽ được cấpĐây là một số mã minh họa mô hình TransientTransactionError. Đoạn mã tạo hai phiên, mỗi phiên nằm trong giao dịch riêng của nó. Sau đó, chúng tôi cố gắng cập nhật cùng một tài liệu trong mỗi giao dịch
var session1=db.getMongo[].startSession[];
var session2=db.getMongo[].startSession[];var session1Collection=session1.getDatabase[db.getName[]].transTest;
var session2Collection=session2.getDatabase[db.getName[]].transTest;session1.startTransaction[];
session2.startTransaction[];session1Collection.update[{_id:1},{$set:{value:1}}];
session2Collection.update[{_id:1},{$set:{value:2}}];session1.commitTransaction[];
session2.commitTransaction[];
Khi gặp câu lệnh cập nhật thứ hai, MongoDB sẽ báo lỗi
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
Giao dịch trong trình điều khiển MongoDBTừ MongoDB 4. 2 trở đi, trình điều khiển MongoDB ẩn
async function myTransaction[session, db,0 khỏi bạn, bằng cách tự động thử lại giao dịch. Chẳng hạn, bạn có thể chạy đồng thời nhiều bản sao của mã NodeJS này mà không gặp phải bất kỳ
fromAcc, toAcc, dollars] {
try {
await session.withTransaction[async [] => { await db.collection['accounts'].
updateOne[{ _id: fromAcc },
{ $inc: { balance: -1*dollars } },
{ session }]; await db.collection['accounts'].
updateOne[{ _id: toAcc },
{ $inc: { balance: dollars } },
{ session }]; }, transactionOptions];
} catch [error] {
console.log[error.message];
}
}
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
8 nàoasync function myTransaction[session, db,
fromAcc, toAcc, dollars] {
try {
await session.withTransaction[async [] => { await db.collection['accounts'].
updateOne[{ _id: fromAcc },
{ $inc: { balance: -1*dollars } },
{ session }]; await db.collection['accounts'].
updateOne[{ _id: toAcc },
{ $inc: { balance: dollars } },
{ session }]; }, transactionOptions];
} catch [error] {
console.log[error.message];
}
}
Trình điều khiển NodeJS — và trình điều khiển cho các ngôn ngữ khác như Java, Python, Go, v.v. , — tự động xử lý mọi
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
8 và gửi lại mọi giao dịch bị hủy bỏ. Tuy nhiên, các lỗi vẫn do máy chủ MongoDB gây ra và bạn có thể thấy chúng được ghi lại trong nhật ký MongoDB~$ grep -i 'assertion.*writeconflict' \
/usr/local/var/log/mongodb/mongo.log \
|tail -1|jq
{
"t": {
"$date": "2020-08-08T14:04:47.643+10:00"
},
…
"msg": "Assertion while executing command",
"attr": {
"command": "update",
"db": "MongoDBTuningBook",
"commandArgs": {
"update": "transTest",
"updates": [
{
"q": {
"_id": 1
},
"u": {
"$inc": {
"value": 2
}
},
"upsert": false,
"multi": false
}
],
/* Other transaction information */
},
"error": "WriteConflict: WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction."
}
}
Ở cấp độ toàn cầu, các lần thử lại có thể nhìn thấy trong bộ đếm
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
1 mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
2function txnCounts[] {Ý nghĩa về hiệu suất của TransientTransactionErrors
var ssTxns = db.serverStatus[].transactions;
print[ssTxns.totalStarted + 0, 'transactions started'];
print[ssTxns.totalAborted + 0, 'transactions aborted'];
print[ssTxns.totalCommitted + 0, 'transactions commited'];
print[Math.round[ssTxns.totalAborted * 100 /
ssTxns.totalStarted] + '% txns aborted'];
}mongo> txnCounts[];
203628 transactions started
167989 transactions aborted
35639 transactions commited
82% txns aborted
Các lần thử lại từ
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
8 rất tốn kém — chúng không chỉ liên quan đến việc loại bỏ bất kỳ công việc nào đã thực hiện trong giao dịch cho đến nay mà còn hoàn nguyên trạng thái cơ sở dữ liệu trở lại lúc bắt đầu giao dịch. Tác động của việc thử lại giao dịch nhiều hơn bất kỳ thứ gì khác khiến giao dịch MongoDB trở nên đắt đỏ. Biểu đồ bên dưới cho thấy khi tỷ lệ hủy bỏ giao dịch tăng lên, thời gian trôi qua cho các giao dịch giảm xuống nhanh chóngGiảm tác động của lỗi giao dịch nhất thời
Cho rằng các lần thử lại của
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
9 có ảnh hưởng nghiêm trọng đến hiệu suất giao dịch, nên chúng ta cần phải làm bất cứ điều gì có thể để giảm thiểu các lần thử lại này. Có một vài chiến lược mà chúng ta có thể sử dụng- Tránh một giao dịch hoàn toàn
- Phân vùng các tài liệu “nóng” có mức độ xung đột ghi cao
- Thứ tự các hoạt động để giảm thiểu số lượng các hoạt động xung đột
Bạn có thể tránh các giao dịch theo một số cách, có thể bằng cách đặt các mục liên quan vào một tài liệu duy nhất để bạn có thể cập nhật chúng một cách nguyên tử. Bạn có thể giảm tranh chấp tài liệu bằng cách phân vùng dữ liệu trên nhiều tài liệu. Trong cuốn sách của chúng tôi, chúng tôi đưa ra một vài ví dụ về những kỹ thuật này
Tùy chọn thứ ba là thay đổi thứ tự các hành động trong giao dịch. Cách tiếp cận này có thể mang lại hiệu quả bất ngờ
Ví dụ: xem xét giao dịch sau
await session.withTransaction[async [] => {
await db.collection['txnTotals'].
updateOne[{ _id: 1 },
{ $inc: { counter: 1 } },
{ session }];
await db.collection['accounts'].
updateOne[{ _id: fromAcc },
{ $inc: { balance: -1*dollars } },
{ session }];
await db.collection['accounts'].
updateOne[{ _id: toAcc },
{ $inc: { balance: dollars } },
{ session }];}, transactionOptions];;
Giao dịch này chuyển tiền giữa hai tài khoản, nhưng trước tiên, nó cập nhật một “bộ đếm giao dịch” toàn cầu. Mọi giao dịch cố gắng phát hành giao dịch này sẽ cố gắng cập nhật bộ đếm này và kết quả là nhiều giao dịch sẽ gặp phải lần thử lại
mongo>session1Collection.update[{_id:1},{$set:{value:1}}];
WriteCommandError[{
"errorLabels" : [
"TransientTransactionError"
],
"operationTime" : Timestamp[1596785629, 1],
"ok" : 0,
"errmsg" : "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.",
"code" : 112,
"codeName" : "WriteConflict",
9Nếu chúng ta di chuyển tuyên bố gây tranh cãi đến cuối giao dịch, thì khả năng xảy ra lỗi TransientTransactionError sẽ giảm đi, vì khoảng thời gian xung đột sẽ giảm xuống một vài thời điểm cuối cùng trong quá trình thực hiện giao dịch. Dưới đây chúng ta thấy hiệu quả của việc tối ưu hóa này
Phần kết luậnCân nhắc việc đặt các hoạt động “nóng” — những hoạt động thường gặp phải TransientTransactionErrors — cuối cùng trong các giao dịch của bạn để giảm khoảng thời gian xung đột
Giao dịch là một bổ sung thực sự hữu ích cho MongoDB, nhưng chúng có tác động đến hiệu suất. Cụ thể, việc thử lại giao dịch có thể có tác động tiêu cực đáng kể đến thông lượng. Trong bài đăng này, chúng tôi đã thảo luận về một số tùy chọn để giảm tác động của giao dịch
Để biết thêm thông tin, hãy thử cuốn sách của chúng tôi Điều chỉnh hiệu suất MongoDB — Chương 9 dành riêng cho việc sử dụng và điều chỉnh các giao dịch
Guy Harrison và Michael Harrison là tác giả của MongoDB Performance Tuning [Apress, 2021]. Cả hai đều làm việc tại ProvenDB, trong số những thứ khác, mang lại sự bất biến và tin cậy của các Chuỗi khối công cộng cho sức mạnh và năng suất của MongoDB