Cách sử dụng các bộ chứa để làm cho dữ liệu chuỗi thời gian của bạn hoạt động nhanh hơn và thông minh hơn trong bài viết Building with Patterns của tuần này trên blog MongoDB. https. //t. co/X4rWBMxJSj
— MongoDB [@MongoDB] ngày 31 tháng 1 năm 2019Một chuỗi thời gian được thực hiện bằng các phép đo kín đáo trong các khoảng thời gian. Mẫu chuỗi thời gian là mẫu tối ưu hóa ghi được thực hiện để đảm bảo thông lượng hiệu suất ghi tối đa cho ứng dụng phân tích điển hình lưu trữ dữ liệu theo đơn vị thời gian riêng biệt. Ví dụ có thể bao gồm đếm số lượt xem trang trong một giây hoặc nhiệt độ mỗi phút. Đối với lược đồ này, chúng ta sẽ thảo luận về chuỗi thời gian trong ngữ cảnh của
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
6Quan sát lược đồ
- Lược đồ chuỗi thời gian dựa trên các bản cập nhật tại chỗ, hiệu quả, phù hợp với cách thức hoạt động của công cụ lưu trữ
7. Tuy nhiên, điều này không hiệu quả khi sử dụng công cụ lưu trữvar col = db.getSisterDB["timeseries"].pageViews; var secondInMinute = 2; var updateStatment = {$inc: {}}; updateStatment["$inc"]["seconds." + secondInMinute] = 1; col.update[{ page: "/index.htm", timestamp: ISODate["2014-01-01T10:01:00Z"] }, updateStatment, true]
0 do thiếu hỗ trợ cập nhật tại chỗvar col = db.getSisterDB["timeseries"].pageViews; var secondInMinute = 2; var updateStatment = {$inc: {}}; updateStatment["$inc"]["seconds." + secondInMinute] = 1; col.update[{ page: "/index.htm", timestamp: ISODate["2014-01-01T10:01:00Z"] }, updateStatment, true]
Lược đồ
Thuộc tính lược đồ Mô tả được tối ưu hóa cho hiệu suất ghi Preallocation Lợi ích từ Preallocation trên MMAPĐể tối đa hóa thông lượng ghi của chúng tôi trong một chuỗi thời gian, chúng tôi đang đưa ra các giả định rằng chúng tôi quan tâm đến các nhóm thời gian kín đáo. Điều đó có nghĩa là, bản thân một lần xem trang riêng lẻ không hấp dẫn đối với ứng dụng. Chỉ số lượt xem trang, trong một giây, phút, giờ, ngày cụ thể hoặc trong một phạm vi ngày và giờ mới được quan tâm. Điều này có nghĩa là đơn vị thời gian nhỏ nhất mà chúng tôi muốn cho ví dụ này, là một phút
Tính đến điều đó, hãy lập mô hình một
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
1 để giữ tất cả các lượt xem trang của chúng ta trong một phút cụ thể{
"page": "/index.htm",
"timestamp": ISODate["2014-01-01T10:01:00Z"],
"totalViews": 0,
"seconds": {
"0": 0
}
}
ví dụ 1. Một chuỗi thời gian xô
Chia nhỏ cánh đồng
Schema AttributesDescriptionpageTrang web chúng tôi đang đo lường dấu thời gian Số phút thực tế mà bộ chứa là fortotalViewsTổng số lần xem trang trong phút này giâySố lần xem trang cho một giây cụ thể trong phútTài liệu
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
1 không chỉ thể hiện toàn bộ số lượt xem trang trong một phút cụ thể mà còn chứa phân tích về số lượt xem trang mỗi giây trong phút đóhoạt động
Cập nhật số lần xem trang trong một nhóm
Hãy mô phỏng những gì xảy ra trong một ứng dụng đang đếm lượt xem trang cho một trang cụ thể. Chúng tôi sẽ mô phỏng cập nhật một nhóm, cho một lần xem trang cụ thể trong giây thứ 2 của nhóm
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
3var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
ví dụ 2. Cập nhật một thùng
Phần đầu tiên của
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
4 thiết lập giá trị var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
5 để tăng trường trong trường var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
6 có tên là var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
7, tương ứng với giây đã trôi qua thứ cấp trong khoảng thời gian nhóm của chúng tôiNếu trường không tồn tại MongoDB, sẽ đặt nó thành một. Nếu không, nó sẽ tăng giá trị hiện tại với một. Lưu ý tham số cuối cùng của câu lệnh cập nhật. Điều này yêu cầu MongoDB thực hiện một
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
8 hướng dẫn MongoDB tạo một tài liệu mới nếu không có tài liệu nào phù hợp với bộ chọn var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
9Truy xuất một Bucket cụ thể
Nếu chúng tôi muốn truy xuất một nhóm đo thời gian cụ thể trong một phút cụ thể, chúng tôi có thể truy xuất nó rất dễ dàng bằng cách sử dụng trường
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
20 như được hiển thị bên dướivar col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
2ví dụ 3. Truy xuất một nhóm cụ thể
Thao tác này sẽ truy xuất nhóm mà
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
20 khớp với nhóm thời gian var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
3Nhóm đo lường phân bổ trước
Để cải thiện hiệu suất khi ghi, chúng ta có thể phân bổ trước các nhóm để tránh phải di chuyển tài liệu trong bộ nhớ và trên đĩa. Mỗi tài liệu nhóm có kích thước cuối cùng cố định đã biết. Nếu chúng tôi sử dụng một mẫu để tạo các thùng trống, chúng tôi có thể tận dụng các bản cập nhật tại chỗ, giảm thiểu dung lượng đĩa IO cần thiết để thu thập
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
23Hãy xem cách chúng ta có thể phân bổ trước các nhóm cho cả giờ đo lường. Hàm ví dụ bên dưới
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
24, lấy một bộ sưu tập, tên trang web và dấu thời gian biểu thị một giờ cụ thểvar col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
8Ví dụ 4. Phân bổ trước các nhóm cho một giờ cụ thể
Hãy sử dụng phương pháp phân bổ trước này để chạy thử bằng cách phân bổ trước các thùng trị giá một giờ
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
9Ví dụ 5. Gọi phương thức preAllocate cho một giờ cụ thể
Hãy xác minh rằng việc phân bổ trước các nhóm diễn ra chính xác bằng cách đếm số mục nhập nhóm được tạo cho một giờ cụ thể
{
"page": "/index.htm",
"timestamp": ISODate["2014-01-01T10:01:00Z"],
"totalViews": 0,
"seconds": {
"0": 0
}
}
0Ví dụ 6. Truy xuất số lượng tài liệu được tạo bởi phương thức preAllocateHour
Như chúng tôi mong đợi, số lượng được trả về là
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
25 mục nhậpchỉ mục
Vì chúng tôi sẽ truy xuất các nhóm dấu thời gian theo tên trang và dấu thời gian của chúng, nên các chỉ mục cần thiết duy nhất cho tính hiệu quả là trên các trường
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
26 và var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
20{
"page": "/index.htm",
"timestamp": ISODate["2014-01-01T10:01:00Z"],
"totalViews": 0,
"seconds": {
"0": 0
}
}
4Ví dụ 7. Tạo chỉ mục dấu thời gian
Điều này sẽ đảm bảo mọi truy vấn phạm vi trên trường
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
20 sẽ có thể tận dụng chỉ mục để có hiệu suất truy vấn tốt hơnmở rộng quy mô
Đọc phụ
Các lần đọc thứ cấp có thể hữu ích khi báo cáo về dữ liệu, vì bất kỳ báo cáo chạy dài nào về chúng sẽ gây ra tác động tối thiểu đến thông lượng ghi
sharding
Việc chọn một khóa phân đoạn cho một chuỗi thời gian sẽ ảnh hưởng đến cách ghi và đọc dữ liệu
Trong trường hợp ví dụ phân tích trang web, chúng tôi muốn tóm tắt dữ liệu theo trang. Nếu việc ghi cho một trang web cụ thể được trải ra giữa tất cả các phân đoạn, chúng tôi yêu cầu các truy vấn phân tán/thu thập để tóm tắt chính xác dữ liệu trong một khoảng thời gian cụ thể
Chúng tôi muốn một khóa phân đoạn sẽ nhóm tất cả các phép đo cho một trang web cụ thể trên một phân đoạn cụ thể nhưng sẽ trải rộng các trang trên tất cả các phân đoạn để tối đa hóa thông lượng ghi
Chúng tôi có thể đạt được điều này bằng cách tạo một khóa phân đoạn phức hợp chứa tên trang web cũng như ngày tháng.
{
"page": "/index.htm",
"timestamp": ISODate["2014-01-01T10:01:00Z"],
"totalViews": 0,
"seconds": {
"0": 0
}
}
6Ví dụ 8. Chìa khóa phân mảnh hợp chất
Lợi ích của việc sử dụng khóa phân đoạn này là chúng tôi vẫn có thể tổng hợp tất cả các giá trị cho một trang cụ thể trên một phân đoạn mà không cần thực hiện truy vấn thu thập phân tán
Hiệu suất
Khám phá đơn giản về hiệu suất trên một máy duy nhất với MongoDb 3. 0 cho thấy sự khác biệt giữa
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
7 và var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
0 đối với mô phỏng hẹp sử dụng khung mô phỏng lược đồ var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
81Kịch bản
https. //github. com/christkv/mongodb-schema-simulator/blob/master/examples/scripts/single_or_replset/timeseries/exercise_time_series. js
MongoDb chạy cục bộ trên MacBook Pro Retina 2015 với ssd và 16 gb ram. Mô phỏng chạy với các tham số sau đối với một phiên bản
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
82 duy nhất trong var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
83Tham sốGiá trịquy trình4nhómKích thước mỗi quy trình50loạituyến tínhĐộ phân giải tính bằng mili giây1000Số lần chạy25Số người dùng cập nhật chuỗi thời gian mỗi lần lặp1000Chiến lược thực thilát thời gianMMAP
Công cụ
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
7 được chạy bằng cài đặt mặc định trên var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
85kết quả kịch bản chuỗi thời gian
StatisticsValueRuntime30. 253 giâyTrung bình1. 06 mili giây Độ lệch chuẩn1. 588 mili giây75 phần trăm1. 246 mili giây95 phần trăm1. 502 mili giây99 phần trăm1. 815 mili giâyMinimum0. 448 mili giâyMaximum57. 48 mili giâyLưu ý rằng
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
86 người dùng mỗi giây ảnh hưởng khá nhiều đến mức tối thiểu và tối đa cũng như thời gian truy vấn trung bìnhCó DâyHổ
Công cụ
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
0 được chạy bằng cài đặt mặc định trên var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
85kết quả kịch bản siêu dữ liệu
StatisticsValueRuntime30. 08 giâyMean1. 108 mili giây Độ lệch chuẩn0. 401 mili giây75 phần trăm1. 341 mili giây95 phần trăm1. 871 mili giây99 phần trăm2. 477 mili giâyMinimum0. 513 mili giâyMaximum5. 481 mili giâyNhư mong đợi, không có nhiều sự khác biệt giữa công cụ lưu trữ
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
7 và var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
0 khi đó là khối lượng công việc chỉ đọcghi chú
Tài liệu được phân bổ trước giúp MongoDB giảm thiểu việc di chuyển tài liệu trong bộ nhớ, giảm IO của đĩa và phân mảnh thấp hơn trên đĩa và trong bộ nhớ. Điều này đặc biệt đúng đối với công cụ lưu trữ
var col = db.getSisterDB["timeseries"].pageViews;
var secondInMinute = 2;
var updateStatment = {$inc: {}};
updateStatment["$inc"]["seconds." + secondInMinute] = 1;
col.update[{
page: "/index.htm",
timestamp: ISODate["2014-01-01T10:01:00Z"]
}, updateStatment, true]
7