Làm thế nào để khắc phục tình trạng thiếu giao dịch trong MongoDB?


139

Tôi biết có những câu hỏi tương tự ở đây nhưng họ đang bảo tôi chuyển về hệ thống RDBMS thông thường nếu tôi cần giao dịch hoặc sử dụng các hoạt động nguyên tử hoặc cam kết hai pha . Giải pháp thứ hai có vẻ là sự lựa chọn tốt nhất. Thứ ba tôi không muốn làm theo vì dường như nhiều điều có thể sai và tôi không thể kiểm tra nó ở mọi khía cạnh. Tôi đang gặp khó khăn trong việc tái cấu trúc dự án của mình để thực hiện các hoạt động nguyên tử. Tôi không biết liệu điều này xuất phát từ quan điểm hạn chế của tôi (tôi mới chỉ làm việc với cơ sở dữ liệu SQL) hoặc liệu nó có thực sự không thể thực hiện được hay không.

Chúng tôi muốn thử nghiệm MongoDB tại công ty của chúng tôi. Chúng tôi đã chọn một dự án tương đối đơn giản - một cổng SMS. Nó cho phép phần mềm của chúng tôi gửi tin nhắn SMS đến mạng di động và cổng thực hiện công việc bẩn thỉu: thực sự giao tiếp với các nhà cung cấp thông qua các giao thức truyền thông khác nhau. Cổng cũng quản lý việc thanh toán các tin nhắn. Mỗi khách hàng đăng ký dịch vụ phải mua một số tín dụng. Hệ thống tự động giảm số dư của người dùng khi tin nhắn được gửi và từ chối quyền truy cập nếu số dư không đủ. Cũng bởi vì chúng tôi là khách hàng của các nhà cung cấp SMS của bên thứ ba, chúng tôi cũng có thể có số dư riêng với họ. Chúng tôi phải theo dõi những người là tốt.

Tôi bắt đầu suy nghĩ về cách tôi có thể lưu trữ dữ liệu cần thiết với MongoDB nếu tôi giảm bớt một số phức tạp (thanh toán bên ngoài, gửi tin nhắn SMS xếp hàng). Đến từ thế giới SQL, tôi sẽ tạo một bảng riêng cho người dùng, một bảng khác cho tin nhắn SMS và một bảng để lưu trữ các giao dịch liên quan đến số dư của người dùng. Giả sử tôi tạo các bộ sưu tập riêng cho tất cả những người trong MongoDB.

Hãy tưởng tượng một tác vụ gửi SMS với các bước sau trong hệ thống đơn giản này:

  1. kiểm tra xem người dùng có đủ số dư hay không; từ chối truy cập nếu không đủ tín dụng

  2. gửi và lưu trữ tin nhắn trong bộ sưu tập SMS với các chi tiết và chi phí (trong hệ thống trực tiếp, tin nhắn sẽ có một statusthuộc tính và một nhiệm vụ sẽ nhận nó để gửi và đặt giá của SMS theo trạng thái hiện tại của nó)

  3. giảm số dư của người dùng bằng chi phí của tin nhắn đã gửi

  4. đăng nhập giao dịch trong bộ sưu tập giao dịch

Bây giờ vấn đề với điều đó là gì? MongoDB chỉ có thể cập nhật nguyên tử trên một tài liệu. Trong luồng trước, có thể xảy ra một số loại lỗi xuất hiện và thông báo được lưu trữ trong cơ sở dữ liệu nhưng số dư của người dùng không được cập nhật và / hoặc giao dịch không được ghi lại.

Tôi đã đưa ra hai ý tưởng:

  • Tạo một bộ sưu tập duy nhất cho người dùng và lưu trữ số dư dưới dạng một trường, các giao dịch và tin nhắn liên quan đến người dùng dưới dạng tài liệu phụ trong tài liệu của người dùng. Bởi vì chúng tôi có thể cập nhật tài liệu nguyên tử, điều này thực sự giải quyết được vấn đề giao dịch. Nhược điểm: nếu người dùng gửi nhiều tin nhắn SMS, kích thước của tài liệu có thể trở nên lớn và giới hạn tài liệu 4MB có thể đạt được. Có lẽ tôi có thể tạo tài liệu lịch sử trong các tình huống như vậy, nhưng tôi không nghĩ đây sẽ là một ý tưởng hay. Ngoài ra tôi không biết hệ thống sẽ nhanh đến mức nào nếu tôi đẩy ngày càng nhiều dữ liệu vào cùng một tài liệu lớn.

  • Tạo một bộ sưu tập cho người dùng và một bộ sưu tập. Có thể có hai loại giao dịch: mua tín dụng với thay đổi số dư dương và tin nhắn được gửi với thay đổi số dư âm. Giao dịch có thể có một tiểu khu; ví dụ trong các tin nhắn được gửi, các chi tiết của SMS có thể được nhúng trong giao dịch. Nhược điểm: Tôi không lưu trữ số dư người dùng hiện tại vì vậy tôi phải tính toán số dư mỗi khi người dùng cố gắng gửi tin nhắn để cho biết tin nhắn có thể đi qua hay không. Tôi sợ tính toán này có thể trở nên chậm khi số lượng giao dịch được lưu trữ tăng lên.

Tôi hơi bối rối về việc chọn phương pháp nào. Có giải pháp nào khác không? Tôi không thể tìm thấy bất kỳ thực tiễn tốt nhất trực tuyến nào về cách khắc phục các loại vấn đề này. Tôi đoán rằng nhiều lập trình viên đang cố gắng làm quen với thế giới NoQuery đang phải đối mặt với những vấn đề tương tự ngay từ đầu.


61
Hãy tha thứ cho tôi nếu tôi sai nhưng có vẻ như dự án này sẽ sử dụng kho dữ liệu NoQuery bất kể nó có được lợi từ nó hay không. NoQuery không phải là một lựa chọn thay thế cho SQL như là một lựa chọn "thời trang" nhưng khi công nghệ của RDBMS không phù hợp với không gian vấn đề & kho dữ liệu không liên quan. Rất nhiều câu hỏi của bạn có "Nếu đó là SQL thì ..." & đó là hồi chuông cảnh báo cho tôi. Tất cả các NoQuery đều xuất phát từ nhu cầu giải quyết vấn đề mà SQL không thể và sau đó chúng đã được khái quát hóa một chút để dễ sử dụng hơn và dĩ nhiên, bandwagon bắt đầu hoạt động.
PurplePilot

4
Tôi biết rằng dự án này không chính xác là tốt nhất để dùng thử NoQuery. Tuy nhiên, tôi e rằng nếu chúng tôi bắt đầu sử dụng nó với các dự án khác (giả sử phần mềm quản lý bộ sưu tập thư viện vì chúng tôi đang quản lý bộ sưu tập) và đột nhiên một loại yêu cầu nào đó cần giao dịch (và thực tế là ở đó, hãy tưởng tượng rằng một cuốn sách được chuyển từ bộ sưu tập này sang bộ sưu tập khác) chúng ta cần biết làm thế nào chúng ta có thể khắc phục vấn đề. Có lẽ chỉ có tôi là người hẹp hòi và nghĩ rằng luôn có nhu cầu giao dịch. Nhưng nó có thể là một cách để vượt qua những điều này bằng cách nào đó.
NagyI

3
Tôi đồng ý với PurplePilot, bạn nên chọn một công nghệ phù hợp với giải pháp, không cố gắng ghép một giải pháp không phù hợp với vấn đề. Mô hình hóa dữ liệu cho cơ sở dữ liệu đồ thị là một mô hình hoàn toàn khác so với thiết kế RDBMS và bạn phải quên mọi thứ bạn biết và học lại cách suy nghĩ mới.

9
Tôi hiểu tôi nên sử dụng công cụ thích hợp cho nhiệm vụ. Tuy nhiên đối với tôi - khi tôi đọc câu trả lời như thế này - có vẻ như NoQuery không tốt cho bất cứ điều gì mà dữ liệu quan trọng. Thật tốt cho Facebook hoặc Twitter khi một số bình luận bị mất trên thế giới, nhưng bất cứ điều gì ở trên đó đều bị loại bỏ. Nếu đó là sự thật thì tôi không hiểu vì sao người khác quan tâm đến việc xây dựng, vd. một cửa hàng web với MongoDB: kylebanker.com/blog/2010/04/30/mongodb-and-ec Commerce Nó thậm chí còn đề cập rằng hầu hết các giao dịch có thể được khắc phục bằng các hoạt động nguyên tử. Những gì tôi đang tìm kiếm là làm thế nào.
NagyI

2
Bạn nói rằng "có vẻ như NoQuery không tốt cho bất cứ điều gì mà dữ liệu quan trọng" là không đúng khi nó không tốt (có thể) là xử lý giao dịch loại ACID giao dịch. Ngoài ra, NoQuery được thiết kế cho các kho lưu trữ dữ liệu phân tán mà các cửa hàng kiểu SQL có thể rất khó đạt được khi bạn tham gia vào các kịch bản sao chép nô lệ chính. NoQuery có các chiến lược cho tính nhất quán cuối cùng và đảm bảo chỉ có bộ dữ liệu mới nhất được sử dụng chứ không phải ACID.
PurplePilot

Câu trả lời:


23

Kể từ 4.0, MongoDB sẽ có các giao dịch ACID đa tài liệu. Kế hoạch là cho phép những người trong triển khai thiết lập bản sao trước, sau đó là các cụm được phân chia. Các giao dịch trong MongoDB sẽ có cảm giác giống như các nhà phát triển giao dịch quen thuộc với các cơ sở dữ liệu quan hệ - chúng sẽ là đa câu lệnh, với ngữ nghĩa và cú pháp tương tự (như start_transactioncommit_transaction). Điều quan trọng, các thay đổi đối với MongoDB cho phép các giao dịch không ảnh hưởng đến hiệu suất đối với khối lượng công việc không yêu cầu chúng.

Để biết thêm chi tiết xem tại đây .

Có các giao dịch phân tán, không có nghĩa là bạn nên mô hình hóa dữ liệu của mình như trong cơ sở dữ liệu quan hệ dạng bảng. Nắm bắt sức mạnh của mô hình tài liệu và tuân theo các thực tiễn tốt và được đề xuất của mô hình hóa dữ liệu.


1
Giao dịch đã đến! 4.0 GA'ed. mongodb.com/blog/post/ Kẻ
Grigori Melnik

Các giao dịch MongoDB vẫn có giới hạn về kích thước của giao dịch 16 MB, gần đây tôi có một trường hợp sử dụng khi tôi cần đưa 50k hồ sơ từ một tệp vào mongoDB, vì vậy để duy trì tài sản nguyên tử tôi đã nghĩ đến việc sử dụng các giao dịch nhưng vì hồ sơ json 50k vượt quá giới hạn này, nó sẽ xuất hiện lỗi "Tổng kích thước của tất cả các hoạt động giao dịch phải nhỏ hơn 16793600. Kích thước thực tế là 16793817". để biết thêm chi tiết, bạn có thể xem qua vé jira chính thức mở tại mongoDB jira.mongodb.org/browse/SERVER-36330
Gautam Malik

MongoDB 4.2 (hiện đang trong giai đoạn thử nghiệm, RC4) hỗ trợ các giao dịch lớn. Bằng cách thể hiện các giao dịch trên nhiều mục nhập oplog, bạn sẽ có thể ghi hơn 16 MB dữ liệu trong một giao dịch ACID duy nhất (tuân theo thời gian thực hiện tối đa mặc định 60 giây hiện tại). Bạn có thể dùng thử ngay bây giờ - mongodb.com/doad-center/community
Grigori Melnik

MongoDB 4.2 hiện là GA với sự hỗ trợ đầy đủ của các giao dịch phân tán. mongodb.com/blog/post/ Kẻ
Grigori Melnik

83

Sống không có giao dịch

Giao dịch hỗ trợ các thuộc tính ACID nhưng mặc dù không có giao dịch nào MongoDB, chúng tôi có các hoạt động nguyên tử. Chà, hoạt động nguyên tử có nghĩa là khi bạn làm việc trên một tài liệu duy nhất thì công việc đó sẽ được hoàn thành trước khi bất kỳ ai khác nhìn thấy tài liệu đó. Họ sẽ thấy tất cả những thay đổi chúng tôi đã thực hiện hoặc không có gì trong số họ. Và sử dụng các hoạt động nguyên tử, bạn thường có thể hoàn thành điều tương tự mà chúng ta đã hoàn thành bằng cách sử dụng các giao dịch trong cơ sở dữ liệu quan hệ. Và lý do là, trong một cơ sở dữ liệu quan hệ, chúng ta cần thực hiện các thay đổi trên nhiều bảng. Thông thường các bảng cần được nối và vì vậy chúng tôi muốn làm tất cả cùng một lúc. Và để làm điều đó, vì có nhiều bảng, chúng tôi sẽ phải bắt đầu một giao dịch và thực hiện tất cả các cập nhật đó và sau đó kết thúc giao dịch. Nhưng vơiMongoDB, chúng tôi sẽ nhúng dữ liệu, vì chúng tôi sẽ tham gia trước vào tài liệu và chúng là những tài liệu phong phú có phân cấp. Chúng ta thường có thể hoàn thành điều tương tự. Ví dụ, trong ví dụ về blog, nếu chúng tôi muốn đảm bảo rằng chúng tôi đã cập nhật một bài đăng blog về nguyên tử, chúng tôi có thể làm điều đó bởi vì chúng tôi có thể cập nhật toàn bộ bài đăng blog cùng một lúc. Nếu như đó là một loạt các bảng quan hệ, có lẽ chúng ta phải mở một giao dịch để có thể cập nhật bộ sưu tập bài đăng và bộ sưu tập bình luận.

Vì vậy, những cách tiếp cận của chúng ta mà chúng ta có thể thực hiện MongoDBđể khắc phục tình trạng thiếu giao dịch là gì?

  • tái cấu trúc - cơ cấu lại mã, để chúng tôi làm việc trong một tài liệu duy nhất và tận dụng các hoạt động nguyên tử mà chúng tôi cung cấp trong tài liệu đó. Và nếu chúng ta làm điều đó, thì thông thường chúng ta đều đã sẵn sàng.
  • triển khai trong phần mềm - chúng ta có thể thực hiện khóa trong phần mềm, bằng cách tạo một phần quan trọng. Chúng tôi có thể xây dựng một bài kiểm tra, kiểm tra và thiết lập bằng cách sử dụng tìm và sửa đổi. Chúng ta có thể xây dựng semaphores, nếu cần. Và theo một cách nào đó, đó là cách mà thế giới rộng lớn hơn hoạt động. Nếu chúng ta nghĩ về điều đó, nếu một ngân hàng cần chuyển tiền sang ngân hàng khác, họ sẽ không sống trong cùng một hệ thống quan hệ. Và họ từng có cơ sở dữ liệu quan hệ riêng của họ thường xuyên. Và họ đã có thể điều phối hoạt động đó mặc dù chúng tôi không thể bắt đầu giao dịch và kết thúc giao dịch trên các hệ thống cơ sở dữ liệu đó, chỉ trong một hệ thống trong một ngân hàng. Vì vậy, chắc chắn có những cách trong phần mềm để khắc phục vấn đề.
  • khoan dung - cách tiếp cận cuối cùng, thường hoạt động trong các ứng dụng web hiện đại và các ứng dụng khác có lượng dữ liệu khổng lồ là chỉ chịu đựng một chút mâu thuẫn. Một ví dụ sẽ là, nếu chúng ta đang nói về nguồn cấp dữ liệu bạn bè trên Facebook, sẽ không có vấn đề gì nếu mọi người đều thấy cập nhật tường của bạn đồng thời. Nếu okey, nếu một người bị chậm lại vài giây và họ bắt kịp. Nó thường không quan trọng trong nhiều thiết kế hệ thống rằng mọi thứ đều được giữ hoàn toàn nhất quán và mọi người đều có một quan điểm hoàn toàn nhất quán và cùng một cơ sở dữ liệu. Vì vậy, chúng tôi chỉ đơn giản là có thể chịu đựng một chút mâu thuẫn có phần tạm thời.

Update, findAndModify, $addToSet(Trong một bản cập nhật) & $push(trong một bản cập nhật) hoạt động hoạt động nguyên tử trong một tài liệu duy nhất.


2
Tôi thích cách mà câu trả lời này thực hiện, thay vì tiếp tục đặt câu hỏi liệu chúng ta có nên quay lại DB quan hệ không. Cảm ơn @xameeramir!
DonnyTian

3
một phần quan trọng của mã sẽ không hoạt động nếu bạn có nhiều hơn 1 máy chủ, phải sử dụng dịch vụ khóa phân tán bên ngoài
Alexander Mills

@AlexanderMills Bạn có thể giải thích rõ hơn không?
Zameer

answerere dường như là bản ghi video từ đây: youtube.com/watch?v=_Iz5xLZr8Lw
Fritz

Tôi nghĩ rằng điều này có vẻ tốt cho đến khi chúng tôi bị hạn chế phải hoạt động trên bộ sưu tập duy nhất. Nhưng chúng tôi không thể đặt mọi thứ trong một tài liệu vì lý do khác nhau (kích thước tài liệu hoặc nếu bạn đang sử dụng tài liệu tham khảo). Tôi nghĩ sau đó chúng ta có thể cần giao dịch.
dùng2488286

24

Kiểm tra này , bởi Tokutek. Họ phát triển một plugin cho Mongo hứa hẹn không chỉ giao dịch mà còn tăng hiệu suất.


@Giovanni Bitbler. Tokutek đã được Percona mua lại và trên đường dẫn bạn đưa ra, tôi không thấy bất kỳ thông tin nào cho bất kỳ thông tin nào xảy ra kể từ bài đăng. Bạn có biết những gì đã xảy ra với nỗ lực của họ? Tôi đã gửi email địa chỉ email trên trang đó để tìm hiểu.
Tyler Collier

Bạn cần gì cụ thể? Nếu bạn cần công nghệ Toku áp dụng cho MongoDB thử github.com/Tokutek/mongo , nếu bạn cần phiên bản mysql có thể họ thêm nó vào phiên bản tiêu chuẩn của họ về Mysql rằng họ thường cung cấp với
Giovanni Bitliner

Làm thế nào tôi có thể kết hợp tokutek với nodejs.
Manoj Sanjeewa

11

Đưa vấn đề: nếu tính toàn vẹn giao dịch là bắt buộc thì không nên sử dụng MongoDB mà chỉ sử dụng các thành phần trong hệ thống hỗ trợ giao dịch. Rất khó để xây dựng một cái gì đó trên đầu thành phần để cung cấp chức năng tương tự ACID cho các thành phần không tuân thủ ACID. Tùy thuộc vào từng giai đoạn riêng lẻ, việc phân tách các hành động thành các hành động giao dịch và phi giao dịch theo một cách nào đó có ý nghĩa ...


1
Tôi đoán bạn có nghĩa là NoQuery có thể được sử dụng như một cơ sở dữ liệu phụ với RDBMS cổ điển. Tôi không thích ý tưởng kết hợp NoQuery và SQL trong cùng một dự án. Nó làm tăng sự phức tạp và có thể giới thiệu một số vấn đề không tầm thường.
NagyI

1
Các giải pháp NoQuery hiếm khi được sử dụng một mình. Cửa hàng tài liệu (mongo và đi văng) có lẽ là hành vi duy nhất từ ​​quy tắc này.
Karoly Horvath

7

Bây giờ vấn đề với điều đó là gì? MongoDB chỉ có thể cập nhật nguyên tử trên một tài liệu. Trong luồng trước, có thể xảy ra một số loại lỗi xuất hiện và thông báo được lưu trữ trong cơ sở dữ liệu nhưng số dư của người dùng không bị giảm và / hoặc giao dịch không được ghi lại.

Đây không thực sự là một vấn đề. Lỗi bạn đề cập là lỗi logic (lỗi) hoặc lỗi IO (mạng, lỗi đĩa). Loại lỗi như vậy có thể khiến cả cửa hàng giao dịch và giao dịch ở trạng thái không nhất quán. Ví dụ: nếu nó đã gửi SMS nhưng trong khi lưu trữ lỗi tin nhắn xảy ra - nó không thể quay lại gửi SMS, điều đó có nghĩa là nó sẽ không được ghi lại, số dư người dùng sẽ không bị giảm, v.v.

Vấn đề thực sự ở đây là người dùng có thể tận dụng điều kiện cuộc đua và gửi nhiều tin nhắn hơn số dư của mình cho phép. Điều này cũng áp dụng cho RDBMS, trừ khi bạn gửi SMS trong giao dịch với khóa trường cân bằng (sẽ là một nút cổ chai lớn). Vì một giải pháp khả thi cho MongoDB sẽ được sử dụng findAndModifytrước tiên để giảm số dư và kiểm tra nó, nếu nó không cho phép gửi và hoàn trả số tiền (tăng nguyên tử). Nếu tích cực, tiếp tục gửi và trong trường hợp không hoàn trả số tiền. Bộ sưu tập lịch sử cân bằng cũng có thể được duy trì để giúp sửa / xác minh trường số dư.


Cảm ơn bạn cho câu trả lời tuyệt vời này! Tôi biết rằng nếu tôi sử dụng dữ liệu lưu trữ có khả năng giao dịch có thể bị hỏng do hệ thống SMS mà tôi không có quyền kiểm soát. Tuy nhiên với Mongo cũng có khả năng xảy ra lỗi dữ liệu trong nhà. Giả sử mã thay đổi số dư của người dùng bằng findAndModify, số dư bị âm nhưng trước khi tôi có thể sửa lỗi xảy ra lỗi và ứng dụng cần phải khởi động lại. Tôi đoán bạn có nghĩa là tôi nên thực hiện một cái gì đó tương tự như cam kết hai pha dựa trên bộ sưu tập giao dịch và kiểm tra sửa lỗi thường xuyên trên cơ sở dữ liệu.
NagyI

9
Không đúng sự thật, các cửa hàng giao dịch sẽ quay trở lại nếu bạn không thực hiện cam kết cuối cùng.
Karoly Horvath

9
Ngoài ra, bạn không gửi SMS và sau đó đăng nhập vào DB, điều đó hoàn toàn sai. Đầu tiên lưu trữ mọi thứ trong DB và thực hiện một cam kết cuối cùng, sau đó bạn có thể gửi tin nhắn. Tại thời điểm này, một cái gì đó vẫn có thể thất bại, vì vậy bạn cần một công việc định kỳ để kiểm tra xem tin nhắn đã thực sự được gửi chưa, nếu không hãy cố gắng gửi. Có lẽ một hàng đợi tin nhắn chuyên dụng sẽ tốt hơn cho việc này. Nhưng toàn bộ vấn đề là liệu bạn có thể gửi tin nhắn SMS theo cách giao dịch không ...
Karoly Horvath

@NagyI vâng, đó là những gì tôi muốn nói. Người ta phải đánh đổi lợi ích của các giao dịch để dễ dàng mở rộng. Về cơ bản ứng dụng phải mong đợi bất kỳ hai tài liệu trong các bộ sưu tập khác nhau có thể ở trạng thái không nhất quán và sẵn sàng để xử lý việc này. @yi_H nó sẽ quay trở lại nhưng trạng thái sẽ không còn thực tế nữa (thông tin về tin nhắn sẽ bị mất). Điều này không tốt hơn nhiều so với việc chỉ có một phần dữ liệu (như số dư giảm nhưng không có thông tin tin nhắn hoặc ngược lại).
pingw33n

Tôi hiểu rồi. Đây thực sự không phải là một hạn chế dễ dàng. Có lẽ tôi nên tìm hiểu thêm về cách các hệ thống RDBMS thực hiện các giao dịch. Bạn có thể giới thiệu một số loại tài liệu trực tuyến hoặc cuốn sách mà tôi có thể đọc về những thứ này?
NagyI

6

Dự án rất đơn giản, nhưng bạn phải hỗ trợ các giao dịch để thanh toán, điều này làm cho toàn bộ điều này trở nên khó khăn. Vì vậy, ví dụ, một hệ thống cổng thông tin phức tạp với hàng trăm bộ sưu tập (diễn đàn, trò chuyện, quảng cáo, v.v ...) về mặt nào đó đơn giản hơn, bởi vì nếu bạn mất một diễn đàn hoặc mục trò chuyện, không ai thực sự quan tâm. Nếu bạn, mặt khác, mất một giao dịch thanh toán là một vấn đề nghiêm trọng.

Vì vậy, nếu bạn thực sự muốn một dự án thử nghiệm cho MongoDB, hãy chọn một dự án đơn giản về mặt đó .


Cảm ơn bạn đã giải thích. Rất tiếc khi nghe vậy. Tôi thích sự đơn giản của NoQuery và việc sử dụng JSON. Chúng tôi đang tìm kiếm một giải pháp thay thế cho ORM nhưng có vẻ như chúng tôi phải gắn bó với nó trong một thời gian.
NagyI

Bạn có thể đưa ra bất kỳ lý do chính đáng nào tại sao MongoDB tốt hơn SQL cho nhiệm vụ này không? Dự án thí điểm nghe có vẻ hơi ngớ ngẩn.
Karoly Horvath

Tôi đã không nói rằng MongoDB tốt hơn SQL. Chúng tôi chỉ đơn giản muốn biết liệu nó có tốt hơn SQL + ORM không. Nhưng bây giờ nó trở nên rõ ràng hơn rằng họ không cạnh tranh trong các dự án loại này.
NagyI

6

Giao dịch vắng mặt trong MongoDB vì lý do hợp lệ. Đây là một trong những điều làm cho MongoDB nhanh hơn.

Trong trường hợp của bạn, nếu giao dịch là bắt buộc, mongo dường như không phù hợp.

Có thể là RDMBS + MongoDB, nhưng điều đó sẽ thêm phức tạp và sẽ khiến việc quản lý và hỗ trợ ứng dụng trở nên khó khăn hơn.


1
Hiện tại có một bản phân phối MongoDB được gọi là TokuMX sử dụng công nghệ fractal để cải thiện hiệu suất 50 lần và cung cấp hỗ trợ giao dịch ACID đầy đủ cùng một lúc: tokutek.com/tokumx-for-mongodb
OCDev

9
Làm thế nào một giao dịch có thể không phải là "phải". Ngay khi bạn cần 1 trường hợp đơn giản trong đó bạn cần cập nhật 2 bảng mongo thì đột nhiên không còn phù hợp nữa? Điều đó không để lại rất nhiều trường hợp sử dụng cả.
Mr_E

1
@Mr_E đồng ý, đó là lý do tại sao MongoDB thật ngu ngốc :)
Alexander Mills

6

Đây có lẽ là blog tốt nhất tôi tìm thấy liên quan đến việc thực hiện giao dịch như tính năng cho mongodb.!

Cờ đồng bộ hóa: tốt nhất cho việc sao chép dữ liệu từ tài liệu chính

Hàng đợi công việc: mục đích rất chung chung, giải quyết 95% các trường hợp. Hầu hết các hệ thống cần phải có ít nhất một hàng đợi công việc xung quanh nào!

Cam kết hai pha: kỹ thuật này đảm bảo rằng mỗi thực thể luôn có tất cả thông tin cần thiết để đạt đến trạng thái nhất quán

Nhật ký Hòa giải: kỹ thuật mạnh mẽ nhất, lý tưởng cho các hệ thống tài chính

Phiên bản: cung cấp sự cô lập và hỗ trợ các cấu trúc phức tạp

Đọc phần này để biết thêm: https://dzone.com/articles/how-im vây-robust- and


Vui lòng bao gồm các phần có liên quan của tài nguyên được liên kết cần thiết để trả lời câu hỏi trong câu trả lời của bạn. Như vậy, câu trả lời của bạn rất dễ bị thối liên kết (nghĩa là nếu trang web được liên kết bị hỏng hoặc thay đổi câu trả lời của bạn có khả năng vô dụng).
mech

Cảm ơn @mech đã gợi ý
Vaibhav

4

Điều này là muộn nhưng nghĩ rằng điều này sẽ giúp trong tương lai. Tôi sử dụng Redis để thực hiện một hàng đợi để giải quyết vấn đề này.

  • Yêu cầu:
    Hình ảnh bên dưới hiển thị 2 hành động cần thực hiện đồng thời nhưng giai đoạn 2 và giai đoạn 3 của hành động 1 cần kết thúc trước khi bắt đầu giai đoạn 2 của hành động 2 hoặc ngược lại (Một giai đoạn có thể là yêu cầu REST api, yêu cầu cơ sở dữ liệu hoặc thực thi mã javascript ... ). nhập mô tả hình ảnh ở đây

  • Cách hàng đợi giúp bạn
    Hàng đợi đảm bảo rằng mọi mã khối giữa lock()release()trong nhiều chức năng sẽ không chạy cùng một lúc, khiến chúng bị cô lập.

    function action1() {
      phase1();
      queue.lock("action_domain");
      phase2();
      phase3();
      queue.release("action_domain");
    }
    
    function action2() {
      phase1();
      queue.lock("action_domain");
      phase2();
      queue.release("action_domain");
    }
  • Làm thế nào để xây dựng một hàng đợi
    Tôi sẽ chỉ tập trung vào cách tránh phần conditon cuộc đua khi xây dựng một hàng đợi trên trang web phụ trợ. Nếu bạn không biết ý tưởng cơ bản của hàng đợi, hãy đến đây .
    Các mã dưới đây chỉ hiển thị các khái niệm, bạn cần thực hiện theo cách chính xác.

    function lock() {
      if(isRunning()) {
        addIsolateCodeToQueue(); //use callback, delegate, function pointer... depend on your language
      } else {
        setStateToRunning();
        pickOneAndExecute();
      }
    }
    
    function release() {
      setStateToRelease();
      pickOneAndExecute();
    }

Nhưng bạn cần tự isRunning() setStateToRelease() setStateToRunning()cô lập nó nếu không bạn sẽ phải đối mặt với tình trạng chủng tộc một lần nữa. Để làm điều này, tôi chọn Redis cho mục đích ACID và có thể mở rộng.
Redis tài liệu nói về giao dịch của nó:

Tất cả các lệnh trong một giao dịch được tuần tự hóa và được thực hiện tuần tự. Không bao giờ có thể xảy ra rằng một yêu cầu được đưa ra bởi một khách hàng khác được phục vụ ở giữa quá trình thực hiện giao dịch Redis. Điều này đảm bảo rằng các lệnh được thực thi như là một hoạt động đơn lẻ.

P / s:
Tôi sử dụng Redis vì dịch vụ của tôi đã sử dụng nó, bạn có thể sử dụng bất kỳ cách nào khác để hỗ trợ cách ly để làm điều đó.
Các action_domaintrong mã của tôi là ở trên khi bạn chỉ cần thực hiện 1 cuộc gọi bằng cách sử dụng một khối động 2 của người dùng A, không chặn người dùng khác. Ý tưởng được đặt một khóa duy nhất cho khóa của mỗi người dùng.


Bạn sẽ nhận được nhiều lượt upvote hơn nếu điểm của bạn đã cao hơn. Đó là cách mà hầu hết ở đây nghĩ. Câu trả lời của bạn rất hữu ích trong bối cảnh của câu hỏi. Tôi đã nâng đỡ bạn.
Mukus

3

Giao dịch hiện có sẵn trong MongoDB 4.0. Mẫu ở đây

// Runs the txnFunc and retries if TransientTransactionError encountered

function runTransactionWithRetry(txnFunc, session) {
    while (true) {
        try {
            txnFunc(session);  // performs transaction
            break;
        } catch (error) {
            // If transient error, retry the whole transaction
            if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError")  ) {
                print("TransientTransactionError, retrying transaction ...");
                continue;
            } else {
                throw error;
            }
        }
    }
}

// Retries commit if UnknownTransactionCommitResult encountered

function commitWithRetry(session) {
    while (true) {
        try {
            session.commitTransaction(); // Uses write concern set at transaction start.
            print("Transaction committed.");
            break;
        } catch (error) {
            // Can retry commit
            if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
                print("UnknownTransactionCommitResult, retrying commit operation ...");
                continue;
            } else {
                print("Error during commit ...");
                throw error;
            }
       }
    }
}

// Updates two collections in a transactions

function updateEmployeeInfo(session) {
    employeesCollection = session.getDatabase("hr").employees;
    eventsCollection = session.getDatabase("reporting").events;

    session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );

    try{
        employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
        eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
    } catch (error) {
        print("Caught exception during transaction, aborting.");
        session.abortTransaction();
        throw error;
    }

    commitWithRetry(session);
}

// Start a session.
session = db.getMongo().startSession( { mode: "primary" } );

try{
   runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
   // Do something with error
} finally {
   session.endSession();
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.