Lưu các sự kiện tần số cao vào cơ sở dữ liệu bị giới hạn kết nối


13

Chúng tôi đã có một tình huống mà tôi phải đối phó với một lượng lớn các sự kiện đến máy chủ của chúng tôi, trung bình khoảng 1000 sự kiện mỗi giây (cao điểm có thể là ~ 2000).

Vấn đề

Hệ thống của chúng tôi được lưu trữ trên Heroku và sử dụng DB Heroku Postgres tương đối đắt tiền , cho phép tối đa 500 kết nối DB. Chúng tôi sử dụng nhóm kết nối để kết nối từ máy chủ đến DB.

Các sự kiện đến nhanh hơn nhóm kết nối DB có thể xử lý

Vấn đề chúng ta gặp phải là các sự kiện đến nhanh hơn nhóm kết nối có thể xử lý. Vào thời điểm một kết nối đã kết thúc vòng kết nối mạng từ máy chủ đến DB, do đó, nó có thể được giải phóng trở lại nhóm, nhiều hơn ncác sự kiện bổ sung được đưa vào.

Cuối cùng, các sự kiện xếp chồng lên nhau, chờ đợi để được lưu và vì không có kết nối có sẵn trong nhóm, chúng hết thời gian và toàn bộ hệ thống được hiển thị không hoạt động.

Chúng tôi đã giải quyết tình huống khẩn cấp bằng cách phát ra các sự kiện tần số cao vi phạm với tốc độ chậm hơn từ khách hàng, nhưng chúng tôi vẫn muốn biết cách xử lý tình huống này trong trường hợp chúng tôi cần xử lý các sự kiện tần số cao đó.

Những ràng buộc

Các khách hàng khác có thể muốn đọc các sự kiện đồng thời

Các máy khách khác liên tục yêu cầu đọc tất cả các sự kiện bằng một khóa cụ thể, ngay cả khi chúng chưa được lưu trong DB.

Một khách hàng có thể truy vấn GET api/v1/events?clientId=1và nhận tất cả các sự kiện được gửi bởi khách hàng 1, ngay cả khi những sự kiện đó chưa được thực hiện lưu trong DB.

Có bất kỳ ví dụ "lớp học" nào về cách giải quyết vấn đề này không?

Phương pháp khả thi

Ghi danh các sự kiện trên máy chủ của chúng tôi

Chúng ta có thể liệt kê các sự kiện trên máy chủ (với hàng đợi có đồng thời tối đa là 400 để nhóm kết nối không hết).

Đây là ý tưởng tồi vì:

  • Nó sẽ ăn hết bộ nhớ máy chủ có sẵn. Các sự kiện được xếp chồng lên nhau sẽ tiêu tốn một lượng lớn RAM.
  • Máy chủ của chúng tôi khởi động lại cứ sau 24 giờ . Đây là một giới hạn cứng được áp đặt bởi Heroku. Máy chủ có thể khởi động lại trong khi các sự kiện được xử lý khiến chúng ta mất các sự kiện bị mê hoặc.
  • Nó giới thiệu trạng thái trên máy chủ, do đó làm tổn thương khả năng mở rộng. Nếu chúng tôi có thiết lập nhiều máy chủ và khách hàng muốn đọc tất cả các sự kiện đã lưu + đã lưu, chúng tôi sẽ không biết máy chủ nào có các sự kiện được yêu thích trực tiếp.

Sử dụng một hàng đợi tin nhắn riêng

Tôi giả sử chúng ta có thể sử dụng một hàng đợi tin nhắn, (như RabbitMQ ?), Nơi chúng ta bơm các tin nhắn trong đó và ở đầu bên kia có một máy chủ khác chỉ liên quan đến việc lưu các sự kiện trên DB.

Tôi không chắc rằng hàng đợi tin nhắn có cho phép truy vấn các sự kiện đã được xử lý hay không (vì vậy vẫn chưa được lưu) vì vậy nếu một khách hàng khác muốn đọc tin nhắn của một khách hàng khác, tôi có thể nhận các tin nhắn đã lưu từ DB và các tin nhắn đang chờ xử lý từ hàng đợi và ghép chúng lại với nhau để tôi có thể gửi chúng trở lại máy khách yêu cầu đọc.

Sử dụng nhiều cơ sở dữ liệu, mỗi cơ sở lưu một phần thông điệp với máy chủ điều phối DB trung tâm để quản lý chúng

Một giải pháp khác chúng tôi mặc dù là sử dụng nhiều cơ sở dữ liệu, với một "bộ điều phối DB / bộ cân bằng tải" trung tâm. Khi nhận được một sự kiện, điều phối viên này sẽ chọn một trong các cơ sở dữ liệu để viết tin nhắn. Điều này sẽ cho phép chúng tôi sử dụng nhiều cơ sở dữ liệu Heroku, do đó tăng giới hạn kết nối lên 500 x số lượng cơ sở dữ liệu.

Khi truy vấn đọc, điều phối viên này có thể đưa ra SELECTcác truy vấn cho từng cơ sở dữ liệu, hợp nhất tất cả các kết quả và gửi lại cho khách hàng đã yêu cầu đọc.

Đây là ý tưởng tồi vì:

  • Ý tưởng này nghe có vẻ như ... ahem .. quá kỹ thuật? Sẽ là một cơn ác mộng để quản lý là tốt (sao lưu, vv ..). Việc xây dựng và bảo trì rất phức tạp và trừ khi thực sự cần thiết, nó có vẻ như là vi phạm KISS .
  • Nó hy sinh tính nhất quán . Thực hiện các giao dịch trên nhiều DB là điều không nên nếu chúng ta thực hiện ý tưởng này.

3
Nút cổ chai của bạn ở đâu? Bạn đang đề cập đến nhóm kết nối của mình, nhưng điều đó chỉ ảnh hưởng đến sự song song, không phải tốc độ trên mỗi lần chèn. Nếu bạn có 500 kết nối và ví dụ 2000QPS, điều này sẽ hoạt động tốt nếu mỗi truy vấn hoàn thành trong vòng 250ms, đó là một khoảng thời gian ngắn. Tại sao trên 15ms? Cũng lưu ý rằng bằng cách sử dụng PaaS, bạn đang từ bỏ các cơ hội tối ưu hóa đáng kể, chẳng hạn như nhân rộng phần cứng cơ sở dữ liệu hoặc sử dụng bản sao đọc để giảm tải cho cơ sở dữ liệu chính. Heroku không xứng đáng trừ khi triển khai là vấn đề lớn nhất của bạn.
amon

@amon Nút cổ chai thực sự là nhóm kết nối. Tôi đã tự chạy ANALYZEcác truy vấn và chúng không phải là vấn đề. Tôi cũng đã xây dựng một nguyên mẫu để kiểm tra giả thuyết nhóm kết nối và xác minh rằng đây thực sự là vấn đề. Cơ sở dữ liệu và máy chủ tự sống trên các máy khác nhau do đó độ trễ. Ngoài ra, chúng tôi không muốn từ bỏ Heroku trừ khi thực sự cần thiết, không lo lắng về việc triển khai là một điểm cộng rất lớn cho chúng tôi.
Nik Kyriakides

1
Điều đó đang được nói, tôi hiểu rằng có những tối ưu vi mô mà tôi có thể làm sẽ giúp tôi giải quyết vấn đề hiện tại . Tôi tự hỏi nếu có một giải pháp kiến trúc có thể mở rộng cho vấn đề của tôi.
Nik Kyriakides

3
Làm thế nào chính xác bạn đã xác minh rằng nhóm kết nối là vấn đề? @amon là chính xác trong tính toán của mình. Hãy thử phát hành select nulltrên 500 kết nối. Tôi cá là bạn sẽ thấy rằng nhóm kết nối không phải là vấn đề ở đó.
usr

1
Nếu chọn null là có vấn đề thì có lẽ bạn đã đúng. Mặc dù nó sẽ rất thú vị khi dành tất cả thời gian đó. Không có mạng là chậm.
usr

Câu trả lời:


9

Luồng đầu vào

Không rõ liệu 1000 sự kiện / giây của bạn đại diện cho các đỉnh hoặc nếu đó là tải liên tục:

  • nếu đó là một đỉnh, bạn có thể sử dụng hàng đợi tin nhắn làm bộ đệm để truyền tải trên máy chủ DB trong một thời gian dài hơn;
  • nếu nó tải liên tục, hàng đợi tin nhắn là không đủ, bởi vì máy chủ DB sẽ không bao giờ có thể bắt kịp. Sau đó, bạn cần phải suy nghĩ về một cơ sở dữ liệu phân tán.

Giải pháp đề xuất

Theo trực giác, trong cả hai trường hợp, tôi sẽ đi theo luồng sự kiện dựa trên Kafka :

  • Tất cả các sự kiện được công bố một cách có hệ thống về một chủ đề kafka
  • Một người tiêu dùng sẽ đăng ký các sự kiện và lưu trữ chúng vào cơ sở dữ liệu.
  • Một bộ xử lý truy vấn sẽ xử lý các yêu cầu từ máy khách và truy vấn DB.

Điều này có khả năng mở rộng cao ở tất cả các cấp:

  • Nếu máy chủ DB là nút cổ chai, chỉ cần thêm một số người tiêu dùng. Mỗi người có thể đăng ký chủ đề và viết thư cho một máy chủ DB khác nhau. Tuy nhiên, nếu phân phối xảy ra ngẫu nhiên trên các máy chủ DB, bộ xử lý truy vấn sẽ không thể dự đoán máy chủ DB sẽ thực hiện và phải truy vấn một số máy chủ DB. Điều này có thể dẫn đến một nút cổ chai mới ở phía truy vấn.
  • Do đó, sơ đồ phân phối DB có thể được dự đoán bằng cách tổ chức luồng sự kiện thành một số chủ đề (ví dụ: sử dụng các nhóm khóa hoặc thuộc tính, để phân vùng DB theo logic có thể dự đoán được).
  • Nếu một máy chủ tin nhắn không đủ để xử lý một loạt các sự kiện đầu vào đang phát triển, bạn có thể thêm các phân vùng kafka để phân phối các chủ đề kafka trên một số máy chủ vật lý.

Cung cấp các sự kiện chưa được viết trong DB cho khách hàng

Bạn muốn khách hàng của mình có thể có quyền truy cập vào thông tin vẫn còn trong đường ống và chưa được ghi vào DB. Điều này là một chút tinh tế.

Tùy chọn 1: Sử dụng bộ đệm để bổ sung cho các truy vấn db

Tôi chưa phân tích sâu, nhưng ý tưởng đầu tiên xuất hiện trong đầu tôi là làm cho bộ xử lý truy vấn trở thành người tiêu dùng của các chủ đề kafka, nhưng trong một nhóm người tiêu dùng kafka khác . Bộ xử lý yêu cầu sau đó sẽ nhận tất cả các thông báo mà người viết DB sẽ nhận được, nhưng độc lập. Sau đó nó có thể giữ chúng trong một bộ đệm cục bộ. Các truy vấn sau đó sẽ chạy trên bộ đệm DB + (loại bỏ các bản sao).

Thiết kế sau đó sẽ trông như sau:

nhập mô tả hình ảnh ở đây

Khả năng mở rộng của lớp truy vấn này có thể đạt được bằng cách thêm nhiều bộ xử lý truy vấn (mỗi nhóm trong nhóm người tiêu dùng riêng của nó).

Tùy chọn 2: thiết kế API kép

Cách tiếp cận tốt hơn IMHO sẽ là cung cấp API kép (sử dụng cơ chế của nhóm người tiêu dùng riêng biệt):

  • API truy vấn để truy cập các sự kiện trong DB và / hoặc tạo phân tích
  • API phát trực tiếp chuyển tiếp tin nhắn trực tiếp từ chủ đề

Ưu điểm, là bạn để khách hàng quyết định điều gì là thú vị. Điều này có thể tránh việc bạn hợp nhất dữ liệu DB một cách có hệ thống với dữ liệu mới được thanh toán, khi khách hàng chỉ quan tâm đến các sự kiện mới đến. Nếu sự hợp nhất tinh tế giữa các sự kiện mới và lưu trữ là thực sự cần thiết, thì khách hàng sẽ phải tổ chức nó.

Biến thể

Tôi đã đề xuất kafka vì nó được thiết kế cho khối lượng rất lớn với các thông điệp liên tục để bạn có thể khởi động lại máy chủ nếu cần.

Bạn có thể xây dựng một kiến ​​trúc tương tự với RabbitMQ. Tuy nhiên nếu bạn cần hàng đợi liên tục, nó có thể làm giảm hiệu suất . Ngoài ra, theo như tôi biết, cách duy nhất để đạt được mức tiêu thụ song song của cùng một tin nhắn của một số độc giả (ví dụ: nhà văn + bộ đệm) với RabbitMQ là sao chép hàng đợi . Vì vậy, khả năng mở rộng cao hơn có thể có giá cao hơn.


Thuộc về sao; Bạn có ý nghĩa a distributed database (for example using a specialization of the server by group of keys)gì? Còn tại sao Kafka thay vì RabbitMQ? Có một lý do cụ thể cho việc chọn cái này hơn cái kia không?
Nik Kyriakides

@NicholasKyriakides Cảm ơn! 1) Tôi chỉ đơn giản nghĩ về một số máy chủ cơ sở dữ liệu độc lập nhưng với sơ đồ phân vùng rõ ràng (khóa, địa lý, v.v.) có thể được sử dụng để gửi hiệu quả các lệnh. 2) Theo trực giác , có thể do Kafka được thiết kế cho thông lượng rất cao với các thông điệp liên tục cần khởi động lại máy chủ của bạn?). Tôi không chắc rằng RabbitMQ là như linh hoạt cho các kịch bản phân phối, và hàng đợi dai dẳng làm giảm hiệu suất
Christophe

Đối với 1) Vì vậy, điều này khá giống với Use multiple databasesý tưởng của tôi nhưng bạn đang nói rằng tôi không nên chỉ ngẫu nhiên (hoặc quay vòng) phân phối các thông điệp đến từng cơ sở dữ liệu. Đúng?
Nik Kyriakides

Đúng. Suy nghĩ đầu tiên của tôi sẽ không được phân phối ngẫu nhiên bởi vì nó có thể làm tăng tải xử lý cho các truy vấn (hầu hết thời gian của cả hai DB). Bạn cũng có thể xem xét các công cụ DB phân tán (egIgnite?). Nhưng để đưa ra bất kỳ lựa chọn sáng suốt nào cũng cần có sự hiểu biết tốt về các mẫu sử dụng DB (có gì khác trong db, tần suất được truy vấn, loại truy vấn nào, có các ràng buộc giao dịch ngoài các sự kiện riêng lẻ, v.v ...).
Christophe

3
Chỉ muốn nói rằng mặc dù kafka có thể cho thông lượng rất cao, nhưng nó có thể vượt quá hầu hết nhu cầu của mọi người. Tôi thấy rằng giao dịch với kafka và API của nó là một sai lầm lớn đối với chúng tôi. RabbitMQ không hề
lép vế

11

Tôi đoán là bạn cần khám phá kỹ hơn một cách tiếp cận mà bạn đã từ chối

  • Ghi danh các sự kiện trên máy chủ của chúng tôi

Đề nghị của tôi sẽ là bắt đầu đọc qua các bài viết khác nhau được xuất bản về kiến trúc LMAX . Họ quản lý để làm cho khối lượng lớn làm việc cho trường hợp sử dụng của họ, và có thể làm cho sự đánh đổi của bạn trông giống như của họ.

Ngoài ra, bạn có thể muốn xem liệu bạn có thể đọc được cách đọc hay không - lý tưởng nhất là bạn muốn có thể mở rộng chúng một cách độc lập với bài viết. Điều đó có thể có nghĩa là xem xét CQRS (phân biệt trách nhiệm truy vấn lệnh).

Máy chủ có thể khởi động lại trong khi các sự kiện được xử lý khiến chúng ta mất các sự kiện bị mê hoặc.

Trong một hệ thống phân tán, tôi nghĩ bạn có thể khá tự tin rằng các tin nhắn sẽ bị mất. Bạn có thể giảm thiểu một số tác động của điều đó bằng cách thận trọng về các rào cản trình tự của bạn (ví dụ: đảm bảo rằng việc ghi vào lưu trữ lâu bền xảy ra - trước khi sự kiện được chia sẻ bên ngoài hệ thống).

  • Sử dụng nhiều cơ sở dữ liệu, mỗi cơ sở lưu một phần thông điệp với máy chủ điều phối DB trung tâm để quản lý chúng

Có lẽ - Tôi có nhiều khả năng nhìn vào ranh giới kinh doanh của bạn để xem liệu có những nơi tự nhiên để bảo vệ dữ liệu hay không.

Có trường hợp mất dữ liệu là một sự đánh đổi chấp nhận được?

Chà, tôi cho rằng có thể có, nhưng đó không phải là nơi tôi sẽ đến. Vấn đề là thiết kế nên được tích hợp vào nó sự mạnh mẽ cần thiết để tiến bộ khi đối mặt với việc mất tin nhắn.

Điều này thường trông giống như một mô hình dựa trên kéo với thông báo. Nhà cung cấp viết các tin nhắn vào một cửa hàng bền. Người tiêu dùng lấy các tin nhắn từ cửa hàng, theo dõi nhãn hiệu nước cao của chính nó. Thông báo đẩy được sử dụng như một thiết bị giảm độ trễ - nhưng nếu thông báo bị mất, tin nhắn vẫn được tải (cuối cùng) vì người tiêu dùng đang kéo theo lịch trình thông thường (sự khác biệt là nếu nhận được thông báo, việc kéo sẽ xảy ra sớm hơn ).

Xem tin nhắn đáng tin cậy mà không có giao dịch phân tán, bởi Udi Dahan (đã được Andy tham chiếu ) và Dữ liệu Polyglot của Greg Young.


In a distributed system, I think you can be pretty confident that messages are going to get lost. Có thật không? Có trường hợp mất dữ liệu là một sự đánh đổi chấp nhận được? Tôi đã có ấn tượng rằng mất dữ liệu = thất bại.
Nik Kyriakides

1
@NicholasKyriakides, thường không được chấp nhận, do đó OP đề xuất khả năng viết thư cho một cửa hàng lâu bền trước khi phát ra sự kiện. Kiểm tra bài viết nàyvideo này của Udi Dahan, nơi ông giải quyết vấn đề chi tiết hơn.
Andy

6

Nếu tôi hiểu chính xác luồng hiện tại là:

  1. Nhận và sự kiện (Tôi giả sử thông qua HTTP?)
  2. Yêu cầu kết nối từ hồ bơi.
  3. Chèn sự kiện vào DB
  4. Phát hành kết nối đến hồ bơi.

Nếu vậy tôi nghĩ rằng thay đổi đầu tiên đối với thiết kế sẽ là dừng việc xử lý ngay cả mã xử lý của bạn trả lại kết nối cho nhóm trên mỗi sự kiện. Thay vào đó, hãy tạo một nhóm các luồng / tiến trình chèn từ 1 đến 1 với số lượng kết nối DB. Mỗi cái này sẽ giữ một kết nối DB chuyên dụng.

Sử dụng một số loại hàng đợi đồng thời, sau đó bạn có các luồng này kéo các thông điệp từ hàng đợi đồng thời và chèn chúng. Về lý thuyết, họ không bao giờ cần phải trả lại kết nối cho nhóm hoặc yêu cầu một kết nối mới nhưng bạn có thể cần phải xây dựng để xử lý trong trường hợp kết nối bị hỏng. Có thể dễ nhất để giết luồng / tiến trình và bắt đầu một luồng mới.

Điều này sẽ loại bỏ hiệu quả chi phí kết nối hồ bơi. Tất nhiên, bạn sẽ cần có khả năng thực hiện các sự kiện đẩy ít nhất 1000 / kết nối mỗi giây trên mỗi kết nối. Bạn có thể muốn thử số lượng kết nối khác nhau vì có 500 kết nối hoạt động trên cùng một bảng có thể tạo ra sự tranh chấp trên DB nhưng đó là câu hỏi hoàn toàn khác nhau. Một điều khác cần xem xét là việc sử dụng các phần chèn hàng loạt, tức là mỗi luồng sẽ kéo một số tin nhắn và đẩy chúng cùng một lúc. Ngoài ra, tránh có nhiều kết nối cố cập nhật cùng một hàng.


5

Giả định

Tôi sẽ giả định rằng tải bạn mô tả là không đổi, vì đó là kịch bản khó giải quyết hơn.

Tôi cũng sẽ giả định rằng bạn có một số cách chạy kích hoạt, khối lượng công việc chạy dài bên ngoài quy trình ứng dụng web của bạn.

Giải pháp

Giả sử rằng bạn đã xác định chính xác nút cổ chai của mình - độ trễ giữa quy trình của bạn và cơ sở dữ liệu Postgres - đó là vấn đề chính cần giải quyết. Giải pháp cần tính đến sự hạn chế về tính nhất quán của bạn với các khách hàng khác muốn đọc các sự kiện càng sớm càng tốt sau khi họ nhận được.

Để giải quyết vấn đề độ trễ, bạn cần làm việc theo cách giảm thiểu mức độ trễ phát sinh cho mỗi sự kiện sẽ được lưu trữ. Đây là điều quan trọng bạn cần đạt được nếu bạn không sẵn sàng hoặc không thể thay đổi phần cứng . Do bạn đang sử dụng dịch vụ PaaS và không có quyền kiểm soát phần cứng hoặc mạng, cách duy nhất để giảm độ trễ cho mỗi sự kiện sẽ là với một số loại sự kiện được viết theo đợt.

Bạn sẽ cần lưu trữ một hàng các sự kiện cục bộ được xóa và ghi định kỳ vào db của bạn, một khi nó đạt đến một kích thước nhất định hoặc sau một khoảng thời gian trôi qua. Một quy trình sẽ cần theo dõi hàng đợi này để kích hoạt xả vào cửa hàng. Có rất nhiều ví dụ xung quanh về cách quản lý hàng đợi đồng thời được xóa theo định kỳ trong ngôn ngữ bạn chọn - Dưới đây là một ví dụ trong C # , từ bồn rửa theo đợt của thư viện ghi nhật ký Serilog nổi tiếng.

Câu trả lời SO này mô tả cách nhanh nhất để xóa dữ liệu trong Postgres - mặc dù nó sẽ yêu cầu lưu trữ hàng loạt của bạn hàng đợi trên đĩa và có khả năng sẽ có một vấn đề được giải quyết ở đó khi đĩa của bạn biến mất khi khởi động lại trong Heroku.

Hạn chế

Một câu trả lời khác đã đề cập đến CQRS , và đó là cách tiếp cận chính xác để giải quyết các ràng buộc. Bạn muốn hydrat hóa các mô hình đọc khi mỗi sự kiện được xử lý - một mẫu Người hòa giải có thể giúp gói gọn một sự kiện và phân phối nó cho nhiều người xử lý đang xử lý. Vì vậy, một trình xử lý có thể thêm sự kiện vào mô hình đọc của bạn trong bộ nhớ mà khách hàng có thể truy vấn và một trình xử lý khác có thể chịu trách nhiệm xếp hàng sự kiện cho việc ghi theo đợt cuối cùng của nó.

Lợi ích chính của CQRS là bạn tách rời các mô hình đọc và viết khái niệm của bạn - đó là một cách thú vị để nói bạn viết thành một mô hình và bạn đọc từ một mô hình hoàn toàn khác. Để có được lợi ích về khả năng mở rộng từ CQRS, bạn thường muốn đảm bảo mỗi mô hình được lưu trữ riêng theo cách tối ưu cho các kiểu sử dụng của nó. Trong trường hợp này, chúng tôi có thể sử dụng mô hình đọc tổng hợp - ví dụ: bộ đệm Redis hoặc đơn giản là trong bộ nhớ - để đảm bảo các lần đọc của chúng tôi nhanh và nhất quán, trong khi chúng tôi vẫn sử dụng cơ sở dữ liệu giao dịch để ghi dữ liệu của mình.


3

Các sự kiện đến nhanh hơn nhóm kết nối DB có thể xử lý

Đây là một vấn đề nếu mỗi quá trình cần một kết nối cơ sở dữ liệu. Hệ thống nên được thiết kế để bạn có một nhóm công nhân trong đó mỗi công nhân chỉ cần một kết nối cơ sở dữ liệu và mỗi công nhân có thể xử lý nhiều sự kiện.

Hàng đợi tin nhắn có thể được sử dụng với thiết kế đó, bạn cần (các) nhà sản xuất tin nhắn đẩy các sự kiện đến hàng đợi tin nhắn và công nhân (người tiêu dùng) xử lý các tin nhắn từ hàng đợi.

Các khách hàng khác có thể muốn đọc các sự kiện đồng thời

Ràng buộc này chỉ có thể nếu các sự kiện được lưu trữ trong cơ sở dữ liệu mà không xử lý (sự kiện thô). Nếu các sự kiện đang được xử lý trước khi được lưu trữ trong cơ sở dữ liệu, thì cách duy nhất để có được các sự kiện là từ cơ sở dữ liệu.

Nếu khách hàng chỉ muốn truy vấn các sự kiện thô thì tôi sẽ đề xuất sử dụng công cụ tìm kiếm như Tìm kiếm đàn hồi. Bạn thậm chí sẽ nhận được API truy vấn / tìm kiếm miễn phí.

Vì có vẻ như việc truy vấn các sự kiện trước khi chúng được lưu trong cơ sở dữ liệu rất quan trọng đối với bạn, một giải pháp đơn giản như Tìm kiếm đàn hồi sẽ hoạt động. Về cơ bản, bạn chỉ lưu trữ tất cả các sự kiện trong đó và không sao chép cùng một dữ liệu bằng cách sao chép chúng vào cơ sở dữ liệu.

Thu nhỏ quy mô Tìm kiếm rất dễ dàng, nhưng ngay cả với cấu hình cơ bản, nó vẫn có hiệu suất khá cao.

Khi bạn cần xử lý, quy trình của bạn có thể nhận các sự kiện từ ES, xử lý và lưu trữ chúng trong cơ sở dữ liệu. Tôi không biết mức hiệu suất bạn cần từ quá trình xử lý này, nhưng nó sẽ hoàn toàn tách biệt với truy vấn các sự kiện từ ES. Dù sao thì bạn cũng không nên có vấn đề về kết nối, vì bạn có thể có một số lượng nhân viên cố định và mỗi người có một kết nối cơ sở dữ liệu.


2

Các sự kiện 1k hoặc 2k (5KB) mỗi giây không phải là nhiều cho cơ sở dữ liệu nếu nó có một lược đồ và công cụ lưu trữ thích hợp. Theo đề xuất của @eddyce, một bậc thầy có một hoặc nhiều nô lệ có thể tách các truy vấn đọc khỏi cam kết ghi. Sử dụng ít kết nối DB hơn sẽ cung cấp cho bạn thông lượng tổng thể tốt hơn.

Các khách hàng khác có thể muốn đọc các sự kiện đồng thời

Đối với các yêu cầu này, họ cũng cần phải đọc từ db chính vì sẽ có độ trễ sao chép cho các nô lệ đọc.

Tôi đã sử dụng (Percona) MySQL với công cụ TokuDB để ghi khối lượng rất cao. Ngoài ra còn có công cụ MyRocks dựa trên LSMtrees tốt cho tải ghi. Đối với cả hai công cụ này và có khả năng là PostgreQuery, có các cài đặt để cách ly giao dịch cũng như cam kết hành vi đồng bộ hóa có thể làm tăng đáng kể khả năng ghi. Trước đây, chúng tôi chấp nhận mất tới 1 giây dữ liệu bị mất được báo cáo cho máy khách db như đã cam kết. Trong các trường hợp khác, có ổ SSD chạy bằng pin để tránh mất mát.

Amazon RDS Aurora trong hương vị MySQL được tuyên bố là có thông lượng ghi cao hơn 6 lần với sao chép chi phí bằng 0 (giống như nô lệ chia sẻ hệ thống tệp với chủ). Hương vị Aurora PostgreSQL cũng có một cơ chế sao chép tiên tiến khác.


TBH bất kỳ cơ sở dữ liệu được quản trị tốt trên phần cứng đủ sẽ có thể đối phó với tải này. Vấn đề của OP dường như không phải là hiệu suất cơ sở dữ liệu mà là độ trễ kết nối; Tôi đoán là Heroku với tư cách là nhà cung cấp PaaS đang bán cho họ một ví dụ Postgres ở một khu vực AWS khác.
amon

1

Tôi sẽ thả heroku lại với nhau, nghĩa là tôi sẽ bỏ một cách tiếp cận tập trung: nhiều bài viết đạt cực đại kết nối nhóm tối đa là một trong những lý do chính khiến các cụm db được phát minh, chủ yếu là do bạn không tải văn bản db (s) với các yêu cầu đọc có thể được thực hiện bởi các db khác trong cụm, tôi sẽ thử với cấu trúc liên kết chủ nô, hơn nữa - như ai đó đã đề cập, có cài đặt db của riêng bạn sẽ có thể điều chỉnh toàn bộ hệ thống để đảm bảo thời gian lan truyền truy vấn sẽ được xử lý chính xác.

Chúc may mắn

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.