Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Cơ Sở Dữ Liệu

Tối ưu MongoDB: Kỹ thuật chứng minh Minimize Storage Waste

Appboy là marketing automation platform hàng đầu thế giới cho mobile apps. Chúng tôi collect billions data points mỗi tháng bằng cách track user behavior trong mobile apps của khách hàng và cho phép target users cho emails, push notifications, in-app messages dựa trên behavior hoặc demographics. MongoDB power most database stack, host dozens of shards across multiple clusters tại ObjectRocket.

Một common performance optimization strategy với MongoDB là dùng short field names trong documents. Thay vì document như này…

{first_name: "Jon", last_name: "Hyman"}

…Dùng shorter field names để document trông như…

{fn: "Jon", ln: "Hyman"}

Vì MongoDB không có concept columns hoặc predefined schemas, structure này advantageous vì field names duplicated trên every document. Nếu một triệu documents mỗi cái có field "first_name", bạn store string đó một triệu lần. Dẫn đến more space per document, ultimately impacts bao nhiêu documents fit in memory và ở large scale, có thể slightly impact performance, vì MongoDB phải map documents into memory khi read.

Ngoài collect event data, Appboy cũng cho customers store "custom attributes" trên mỗi user. Ví dụ: sports app muốn store "Favorite Player", magazine app store "Annual Subscriber". Appboy có document cho mỗi end user, store custom attributes cùng fields như first/last name. Để save space và improve performance, shorten field names của everything store trên document. Với fields biết trước (first name, email, gender, etc.) tự alias (ví dụ "fn" = "first name"), nhưng không predict được names của custom attributes customers sẽ record. Nếu customer đặt custom attribute "supercalifragilisticexpialidocious", không muốn store đó trên all documents.

Để solve, tokenize custom attribute field names dùng "name store". Effectively, là document trong MongoDB map values như "Favorite Player" thành unique, predictable, very short string. Generate map này chỉ dùng MongoDB atomic operators.

Name store document schema cực basic: one document per customer, chỉ có one array field "list". Ý tưởng: array chứa all values cho custom attributes và index của given string là token. Để translate "Favorite Player" thành short predictable field name, check "list" xem nó ở đâu trong array. Nếu không có, issue atomic push add element to end array (db.custom_attribute_name_stores.update({_id : X, list: {$ne : "Favorite Player"}}, {$push: {list: "Favorite Player"}})), reload document và determine index. Ideally dùng $addToSet, nhưng $addToSet không guarantee ordering, trong khi $push documented append to end by default.

Lúc này, translate "Favorite Player" thành integer value. Giá trị là 1. User document trông như:

{ fn: "Jon", ln: "Hyman", custom: { 1: "LeBron James" } }

Field names short và tidy! Side effect tuyệt vời: không lo customers dùng characters MongoDB không support without escaping, như dollar signs hoặc periods.

Bạn nghĩ MongoDB cảnh báo against constantly growing documents và name store document có thể grow unbounded. In practice, extended implementation để store more than one document per customer. Cho phép put reasonable cap trên array elements trước khi generate new document. Best part: vẫn làm all this atomically chỉ dùng MongoDB! Achieve bằng cách add field "leastvalue" vào mỗi document. "leastvalue" field represent số elements added vào previous documents trước khi document này created. Nếu thấy document với "leastvalue" 100 và "list" ["Season Ticket Holder", "Favorite Player"], token value cho "Favorite Player" là 101 (zero-based indexing). Example này chỉ store 100 values trong "list" array trước khi tạo new document. Khi insert, modify push slightly operate trên document với highest "leastvalue" value, và ensure "list.99" không exist (nothing at index 99). Nếu element đã exist at index đó, push operation không làm gì. Lúc đó biết cần tạo new name store document với "least_value" = total elements exist across all documents. Dùng atomic $findAndModify, create new document nếu not exist, fetch back và retry $push.

Nếu customer có hơn vài custom attributes, read back all name store documents translate values to tokens expensive về bandwidth và processing. Tuy nhiên, vì token value của given field luôn same sau khi computed, cache tokens để speed up translation.

Áp dụng "name store token" paradigm ở various parts của application để cut down field name sizes vẫn dùng flexible schema. Cũng helpful cho values. Giả sử radio station app store custom attribute là array top 50 performing artists user listens to. Thay vì array 50 strings, tokenize radio station names và store array 50 integers trên user. Query users like certain artist now involve two token lookups: one cho field name, one cho value. Vì cache translation value to token, dùng multi-get trong cache layer maintain single round-trip to cache khi translate any number of values.

Optimization này add indirection và complexity, nhưng khi store hundreds of millions users như Appboy, worthwhile optimization. Đã save hundreds of gigabytes expensive SSD space qua trick này.

Muốn learn more? Tôi sẽ discuss devops tại Appboy trong Rackspace Solve NYC Conference Sept 18th tại Cipriani.