MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Kinerja MongoDB:Menjalankan Operasi Pengurangan Peta MongoDB di Sekunder

Pengurangan peta mungkin adalah operasi agregasi paling serbaguna yang didukung MongoDB.

Map-Reduce adalah model pemrograman populer yang berasal dari Google untuk memproses dan menggabungkan sejumlah besar data secara paralel. Diskusi mendetail tentang Map-Reduce berada di luar cakupan artikel ini, tetapi pada dasarnya ini adalah proses agregasi multi-langkah. Dua langkah yang paling penting adalah tahap peta (memproses setiap dokumen dan mengeluarkan hasil) dan tahap pengurangan (mengumpulkan hasil yang dipancarkan selama tahap peta).

MongoDB mendukung tiga jenis operasi agregasi:Map-Reduce, aggregation pipeline, dan perintah agregasi tujuan tunggal. Anda dapat menggunakan dokumen perbandingan MongoDB ini untuk melihat mana yang sesuai dengan kebutuhan Anda.https://scalegrid.io/blog/mongodb-performance-running-mongodb-map-reduce-operations-on-secondaries/

Dalam posting terakhir saya, kami melihat, dengan contoh, cara menjalankan pipa Agregasi di sekunder. Dalam postingan ini, kita akan memandu menjalankan tugas Pengurangan Peta di replika sekunder MongoDB.

Pengurangan Peta MongoDB

MongoDB mendukung menjalankan pekerjaan Map-Reduce di server database. Ini menawarkan fleksibilitas untuk menulis tugas agregasi kompleks yang tidak mudah dilakukan melalui saluran agregasi. MongoDB memungkinkan Anda menulis peta khusus dan mengurangi fungsi dalam Javascript yang dapat diteruskan ke database melalui Mongo shell atau klien lain. Pada kumpulan data yang besar dan terus berkembang, seseorang bahkan dapat mempertimbangkan untuk menjalankan tugas Pengurangan Peta inkremental untuk menghindari pemrosesan data lama setiap saat.

Secara historis, peta dan metode pengurangan digunakan untuk dieksekusi dalam konteks utas tunggal. Namun, batasan itu telah dihapus di versi 2.4.

Mengapa menjalankan tugas Pengurangan Peta di Sekunder?

Seperti pekerjaan agregasi lainnya, Map-Reduce juga merupakan pekerjaan 'batch' intensif sumber daya sehingga sangat cocok untuk dijalankan pada replika hanya-baca. Peringatan dalam melakukannya adalah:

1) Seharusnya tidak apa-apa menggunakan data yang sedikit basi. Atau Anda dapat mengubah masalah penulisan untuk memastikan replika selalu sinkron dengan yang utama. Opsi kedua ini mengasumsikan bahwa pukulan pada kinerja tulis dapat diterima.

2) Output dari pekerjaan Map-Reduce tidak boleh ditulis ke koleksi lain dalam database melainkan dikembalikan ke aplikasi (yaitu tidak ada penulisan ke database).

Mari kita lihat bagaimana melakukannya melalui contoh, baik dari shell mongo dan driver Java.

Pengurangan Peta pada Kumpulan Replika

Kumpulan Data

Sebagai ilustrasi, kami akan menggunakan kumpulan data yang agak sederhana:Data transaksi harian yang dibuang dari pengecer. Contoh entri terlihat seperti:

RS-replica-0:PRIMARY> use test
switched to db test
RS-replica-0:PRIMARY> show tables
txns
RS-replica-0:PRIMARY> db.txns.findOne()
{
    "_id" : ObjectId("584a3b71cdc1cb061957289b"),
    "custid" : "cust_66",
    "txnval" : 100,
    "items" : [{"sku": sku1", "qty": 1, "pr": 100}, ...],
...
}

Dalam contoh kami, kami akan menghitung total pengeluaran pelanggan tertentu pada hari itu. Jadi, berdasarkan skema kami, metode peta dan pengurangan akan terlihat seperti:

var mapFunction = function() { emit(this.custid, this.txnval); } // Emit the custid and txn value from each record
var reduceFunction = function(key, values) { return Array.sum(values); } // Sum all the txn values for a given custid

Dengan skema yang sudah dibuat, mari kita lihat aksi Pengurangan Peta.

MongoDB Shell

Untuk memastikan bahwa pekerjaan Pengurangan Peta dijalankan di sekunder, preferensi baca harus diatur ke sekunder . Seperti yang kami katakan di atas, agar Map-Reduce dapat berjalan di sekunder, output dari hasilnya harus inline (Faktanya, itu adalah satu-satunya nilai keluar yang diizinkan di sekunder). Mari kita lihat cara kerjanya.

$ mongo -u admin -p pwd --authenticationDatabase admin --host RS-replica-0/server-1.servers.example.com:27017,server-2.servers.example.com:27017
MongoDB shell version: 3.2.10
connecting to: RS-replica-0/server-1.servers.example.com:27017,server-2.servers.example.com:27017/test
2016-12-09T08:15:19.347+0000 I NETWORK  [thread1] Starting new replica set monitor for server-1.servers.example.com:27017,server-2.servers.example.com:27017
2016-12-09T08:15:19.349+0000 I NETWORK  [ReplicaSetMonitorWatcher] starting
RS-replica-0:PRIMARY> db.setSlaveOk()
RS-replica-0:PRIMARY> db.getMongo().setReadPref('secondary')
RS-replica-0:PRIMARY> db.getMongo().getReadPrefMode()
secondary
RS-replica-0:PRIMARY> var mapFunc = function() { emit(this.custid, this.txnval); }
RS-replica-0:PRIMARY> var reduceFunc = function(key, values) { return Array.sum(values); }
RS-replica-0:PRIMARY> db.txns.mapReduce(mapFunc, reduceFunc, {out: { inline: 1 }})
{
    "results" : [
        {
            "_id" : "cust_0",
            "value" : 72734
        },
        {
            "_id" : "cust_1",
            "value" : 67737
        },
...
    ]
    "timeMillis" : 215,
    "counts" : {
        "input" : 10000,
        "emit" : 10000,
        "reduce" : 909,
        "output" : 101
    },
    "ok" : 1

}

Mengintip log di sekunder mengonfirmasi bahwa pekerjaan memang berjalan di sekunder.

...
2016-12-09T08:17:24.842+0000 D COMMAND  [conn344] mr ns: test.txns
2016-12-09T08:17:24.843+0000 I COMMAND  [conn344] command test.$cmd command: listCollections { listCollections: 1, filter: { name: "txns" }, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:150 locks:{ Global: { acquireCount: { r: 4 } }, Database: { acquireCount: { r: 1, R: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_query 0ms
2016-12-09T08:17:24.865+0000 I COMMAND  [conn344] query test.system.js planSummary: EOF ntoreturn:0 ntoskip:0 keysExamined:0 docsExamined:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:0 nreturned:0 reslen:20 locks:{ Global: { acquireCount: { r: 6 } }, Database: { acquireCount: { r: 2, R: 1 } }, Collection: { acquireCount: { r: 2 } } } 0ms
2016-12-09T08:17:25.063+0000 I COMMAND  [conn344] command test.txns command: mapReduce { mapreduce: "txns", map: function () { emit(this.custid, this.txnval); }, reduce: function (key, values) { return Array.sum(values); }, out: { inline: 1.0 } } planSummary: COUNT keyUpdates:0 writeConflicts:0 numYields:78 reslen:4233 locks:{ Global: { acquireCount: { r: 366 } }, Database: { acquireCount: { r: 3, R: 180 } }, Collection: { acquireCount: { r: 3 } } } protocol:op_command 220ms
...

Jawa

Sekarang mari kita coba menjalankan pekerjaan Map-Reduce pada replika baca dari aplikasi Java. Pada driver MongoDB Java, menyetel Preferensi baca akan berhasil. Outputnya sebaris secara default sehingga tidak ada parameter tambahan yang perlu diteruskan. Berikut ini contoh menggunakan driver versi 3.2.2:

public class MapReduceExample {

    private static final String MONGO_END_POINT = "mongodb://admin:[email protected]:27017,server-2.servers.example.com:27017/admin?replicaSet=RS-replica-0";
    private static final String COL_NAME = "txns";
    private static final String DEF_DB = "test";

    public MapReduceExample() { }

    public static void main(String[] args) {
        MapReduceExample writer = new MapReduceExample();
        writer.mapReduce();
    }

    public static final String mapfunction = "function() { emit(this.custid, this.txnval); }";
    public static final String reducefunction = "function(key, values) { return Array.sum(values); }";

    private void mapReduce() {
        printer("Initializing...");
        Builder options = MongoClientOptions.builder().readPreference(ReadPreference.secondary());
        MongoClientURI uri = new MongoClientURI(MONGO_END_POINT, options);
        MongoClient client = new MongoClient(uri);
        MongoDatabase database = client.getDatabase(DEF_DB);
        MongoCollection collection = database.getCollection(COL_NAME);
        MapReduceIterable iterable = collection.mapReduce(mapfunction, reducefunction); // inline by default
        MongoCursor cursor = iterable.iterator();
        while (cursor.hasNext()) {
           Document result = cursor.next();
           printer("Customer: " + result.getString("_id") + ", Total Txn value: " + result.getDouble("value"));
        }
        printer("Done...");
    }
...
}

Seperti yang terlihat dari log, pekerjaan berjalan di sekunder:

...
2016-12-09T08:32:31.419+0000 D COMMAND  [conn371] mr ns: test.txns
2016-12-09T08:32:31.420+0000 I COMMAND  [conn371] command test.$cmd command: listCollections { listCollections: 1, filter: { name: "txns" }, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:150 locks:{ Global: { acquireCount: { r: 4 } }, Database: { acquireCount: { r: 1, R: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_query 0ms
2016-12-09T08:32:31.444+0000 I COMMAND  [conn371] query test.system.js planSummary: EOF ntoreturn:0 ntoskip:0 keysExamined:0 docsExamined:0 cursorExhausted:1 keyUpdates:0 writeConflicts:0 numYields:0 nreturned:0 reslen:20 locks:{ Global: { acquireCount: { r: 6 } }, Database: { acquireCount: { r: 2, R: 1 } }, Collection: { acquireCount: { r: 2 } } } 0ms
2016-12-09T08:32:31.890+0000 I COMMAND  [conn371] command test.txns command: mapReduce { mapreduce: "txns", map: function() { emit(this.custid, this.txnval); }, reduce: function(key, values) { return Array.sum(values); }, out: { inline: 1 }, query: null, sort: null, finalize: null, scope: null, verbose: true } planSummary: COUNT keyUpdates:0 writeConflicts:0 numYields:156 reslen:4331 locks:{ Global: { acquireCount: { r: 722 } }, Database: { acquireCount: { r: 3, R: 358 } }, Collection: { acquireCount: { r: 3 } } } protocol:op_query 470ms
...

Pengurangan Peta MongoDB pada kluster Sharded

MongoDB mendukung Map-Reduce pada sharded clusters, baik ketika koleksi sharded adalah input dan ketika itu adalah output dari pekerjaan Map-Reduce. Namun, MongoDB saat ini tidak mendukung menjalankan pekerjaan pengurangan peta pada sekunder dari cluster yang di-shard. Jadi meskipun opsi keluar disetel ke sebaris , tugas Pengurangan Peta akan selalu berjalan pada pendahuluan kluster yang di-sharded. Masalah ini sedang dilacak melalui bug JIRA ini.

Sintaks menjalankan tugas Pengurangan Peta pada kluster sharded sama dengan sintaks pada set replika. Jadi contoh yang diberikan pada bagian di atas berlaku. Jika contoh Java di atas dijalankan pada sharded cluster, pesan log muncul di primer yang menunjukkan bahwa perintah dijalankan di sana.

...
2016-11-24T08:46:30.828+0000 I COMMAND  [conn357] command test.$cmd command: mapreduce.shardedfinish { mapreduce.shardedfinish: { mapreduce: "txns", map: function() { emit(this.custid, this.txnval); }, reduce: function(key, values) { return Array.sum(values); }, out: { in
line: 1 }, query: null, sort: null, finalize: null, scope: null, verbose: true, $queryOptions: { $readPreference: { mode: "secondary" } } }, inputDB: "test", shardedOutputCollection: "tmp.mrs.txns_1479977190_0", shards: { Shard-0/primary.shard0.example.com:27017,secondary.shard0.example.com:27017: { result: "tmp.mrs.txns_1479977190_0", timeMillis: 123, timing: { mapTime: 51, emitLoop: 116, reduceTime: 9, mode: "mixed", total: 123 }, counts: { input: 9474, emit: 9474, reduce: 909, output: 101 }, ok: 1.0, $gleS
tats: { lastOpTime: Timestamp 1479977190000|103, electionId: ObjectId('7fffffff0000000000000001') } }, Shard-1/primary.shard1.example.com:27017,secondary.shard1.example.com:27017: { result: "tmp.mrs.txns_1479977190_0", timeMillis: 71, timing:
 { mapTime: 8, emitLoop: 63, reduceTime: 4, mode: "mixed", total: 71 }, counts: { input: 1526, emit: 1526, reduce: 197, output: 101 }, ok: 1.0, $gleStats: { lastOpTime: Timestamp 1479977190000|103, electionId: ObjectId('7fffffff0000000000000001') } } }, shardCounts: { Sha
rd-0/primary.shard0.example.com:27017,secondary.shard0.example.com:27017: { input: 9474, emit: 9474, reduce: 909, output: 101 }, Shard-1/primary.shard1.example.com:27017,secondary.shard1.example.com:27017: { inpu
t: 1526, emit: 1526, reduce: 197, output: 101 } }, counts: { emit: 11000, input: 11000, output: 202, reduce: 1106 } } keyUpdates:0 writeConflicts:0 numYields:0 reslen:4368 locks:{ Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 1 } }, Collection: { acqu
ireCount: { r: 1 } } } protocol:op_command 115ms
2016-11-24T08:46:30.830+0000 I COMMAND  [conn46] CMD: drop test.tmp.mrs.txns_1479977190_0
...

Kunjungi halaman produk MongoDB kami untuk mencari tahu tentang daftar fitur lengkap kami.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Tidak dapat terhubung ke mongodb menggunakan ip mesin

  2. MongoDB dan C#:Pencarian case-insensitive

  3. IDE kueri untuk MongoDB?

  4. Mendapatkan agregasi yang berbeda dari bidang array di seluruh indeks

  5. MongoError:Opsi 'kursor' diperlukan, kecuali untuk agregat dengan argumen penjelasan