Rumah > hujung hadapan web > tutorial js > Mengendalikan Data Berkongsi dalam Sistem Teragih: Penyelaman Mendalam ke dalam Gabungan, Penyiaran dan Pengoptimuman Pertanyaan

Mengendalikan Data Berkongsi dalam Sistem Teragih: Penyelaman Mendalam ke dalam Gabungan, Penyiaran dan Pengoptimuman Pertanyaan

Patricia Arquette
Lepaskan: 2024-12-23 13:50:18
asal
976 orang telah melayarinya

Handling Sharded Data in Distributed Systems: A Deep Dive into Joins, Broadcasts, and Query Optimization

Dalam pangkalan data teragih moden, keperluan untuk menskalakan data secara mendatar telah membawa kepada penggunaan meluas sharding. Walaupun sharding membantu mengurus set data yang besar merentas berbilang nod, ia memperkenalkan cabaran, terutamanya apabila melakukan menyertai dan memastikan pengambilan data yang cekap. Dalam artikel ini, kami meneroka pelbagai konsep dan teknik yang menangani cabaran ini, terutamanya memfokuskan pada sambungan siaran, penjajaran kunci pecahan dan enjin pertanyaan teragih seperti Presto dan BigQuery. Selain itu, kami menunjukkan cara menangani masalah ini dalam aplikasi dunia nyata menggunakan Node.js dan Express.


Contoh Perkongsian dalam Node.js dengan Express.js

Begini cara anda boleh melaksanakan sharding dalam PostgreSQL menggunakan Node.js dan Express.js.

Contoh Perkongsian PostgreSQL

Menggunakan Citus atau serpihan logik manual dengan Node.js:

Contoh dengan Perkongsian Logik

  1. Sediakan Jadual untuk Serpihan:
    Gunakan jadual untuk serpihan (data_pengguna pada shard1 dan data_pengguna pada shard2).

  2. Buat Express.js API:
    Edarkan pertanyaan berdasarkan kunci serpihan (cth., user_id).

   const express = require('express');
   const { Pool } = require('pg');

   const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' });
   const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' });

   const app = express();
   app.use(express.json());

   const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2);

   app.post('/user', async (req, res) => {
       const { userId, data } = req.body;
       const pool = getShardPool(userId);
       try {
           await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]);
           res.status(200).send('User added successfully');
       } catch (err) {
           console.error(err);
           res.status(500).send('Error inserting user');
       }
   });

   app.get('/user/:userId', async (req, res) => {
       const userId = parseInt(req.params.userId, 10);
       const pool = getShardPool(userId);
       try {
           const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]);
           res.status(200).json(result.rows);
       } catch (err) {
           console.error(err);
           res.status(500).send('Error retrieving user');
       }
   });

   app.listen(3000, () => console.log('Server running on port 3000'));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

1. Perkongsian dalam Pangkalan Data Teragih

Sharding ialah proses membahagikan data secara mendatar merentas berbilang contoh pangkalan data, atau serpihan, untuk meningkatkan prestasi, kebolehskalaan dan ketersediaan. Perkongsian selalunya diperlukan apabila satu tika pangkalan data tidak dapat mengendalikan jumlah data atau trafik.

Strategi Perkongsian:

  • Perkongsian berasaskan Julat: Data diedarkan merentas serpihan berdasarkan julat kunci, cth., membahagikan pesanan mengikut tarikh_pesanan.
  • Perkongsian berasaskan cincang: Data dicincang oleh kunci serpihan (cth., id_pengguna) untuk mengagihkan data secara sama rata merentas serpihan.
  • Perkongsian berasaskan direktori: Direktori pusat menjejaki tempat data berada dalam sistem.

Walau bagaimanapun, apabila jadual berkaitan dipecahkan pada kekunci yang berbeza, atau apabila jadual memerlukan penyambungan dengan jadual lain merentas berbilang serpihan, prestasi boleh merosot kerana keperluan untuk operasi pengumpul-serakan. Di sinilah pemahaman siaran bergabung dan penjajaran kunci serpihan menjadi penting.


2. Cabaran dengan Gabungan dalam Sistem Berkongsi

Apabila data berada dalam serpihan yang berbeza, melakukan cantuman antara serpihan tersebut boleh menjadi rumit. Berikut ialah pecahan cabaran biasa:

1. Shard Key Misalignment:

Dalam banyak sistem, jadual dipecahkan pada kekunci yang berbeza. Contohnya:

  • Jadual pengguna mungkin dipecahkan oleh user_id.
  • Jadual pesanan mungkin dipecahkan mengikut wilayah.

Apabila melakukan gabungan (cth., orders.user_id = users.user_id), sistem perlu mengambil data daripada berbilang serpihan kerana rekod yang berkaitan mungkin tidak berada dalam serpihan yang sama.

2. Scatter-Gather Joins:

Dalam gabungan scatter-gather, sistem mesti:

  • Hantar permintaan kepada semua serpihan yang menyimpan data yang berkaitan.
  • Agregat hasil merentas serpihan. Ini boleh merendahkan prestasi dengan ketara, terutamanya apabila data tersebar pada banyak serpihan.

3. Gabungan Siaran:

Satu sambungan siaran berlaku apabila salah satu jadual yang dicantumkan cukup kecil untuk disiarkan ke semua serpihan. Dalam kes ini:

  • Jadual kecil (mis., pengguna) direplikasi merentasi semua nod di mana jadual yang lebih besar dan berpecah (mis., pesanan) berada.
  • Setiap nod kemudiannya boleh menyertai data tempatannya dengan data yang disiarkan, mengelakkan keperluan untuk komunikasi silang serpihan.

3. Menggunakan Enjin Pertanyaan Teragih untuk Data Berkongsi

Enjin pertanyaan teragih seperti Presto dan BigQuery direka bentuk untuk mengendalikan data berpecah dan menyertai pertanyaan dengan cekap merentas sistem teragih.

Presto/Trino:

Presto ialah enjin pertanyaan SQL teragih yang direka untuk menanyakan set data yang besar merentas sumber data heterogen (cth., pangkalan data hubungan, pangkalan data NoSQL, tasik data). Presto melakukan gabungan merentas sumber data yang diedarkan dan boleh mengoptimumkan pertanyaan dengan meminimumkan pergerakan data antara nod.

Contoh Kes Penggunaan: Menyertai Data Berkongsi dengan Presto

Dalam senario di mana pesanan dipecahkan mengikut wilayah dan pengguna dipecahkan oleh user_id, Presto boleh melakukan gabungan merentas serpihan yang berbeza menggunakan model pelaksanaan yang diedarkan.

Pertanyaan:

   const express = require('express');
   const { Pool } = require('pg');

   const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' });
   const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' });

   const app = express();
   app.use(express.json());

   const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2);

   app.post('/user', async (req, res) => {
       const { userId, data } = req.body;
       const pool = getShardPool(userId);
       try {
           await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]);
           res.status(200).send('User added successfully');
       } catch (err) {
           console.error(err);
           res.status(500).send('Error inserting user');
       }
   });

   app.get('/user/:userId', async (req, res) => {
       const userId = parseInt(req.params.userId, 10);
       const pool = getShardPool(userId);
       try {
           const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]);
           res.status(200).json(result.rows);
       } catch (err) {
           console.error(err);
           res.status(500).send('Error retrieving user');
       }
   });

   app.listen(3000, () => console.log('Server running on port 3000'));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Presto akan:

  1. Gunakan scatter-gather untuk mengambil rekod pengguna yang berkaitan.
  2. Sertai data merentas nod.

Google BigQuery:

BigQuery ialah gudang data tanpa pelayan yang diurus sepenuhnya, yang cemerlang dalam menjalankan pertanyaan analisis berskala besar. Walaupun BigQuery mengasingkan butiran sharding, ia secara automatik membahagikan dan mengedarkan data merentas banyak nod untuk pertanyaan yang dioptimumkan. Ia boleh mengendalikan set data yang besar dengan mudah dan amat berkesan untuk pertanyaan analitikal yang mana data dibahagikan mengikut masa atau dimensi lain.

Contoh Kes Penggunaan: Menyertai Jadual Sharded dalam BigQuery
   const express = require('express');
   const { Pool } = require('pg');

   const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' });
   const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' });

   const app = express();
   app.use(express.json());

   const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2);

   app.post('/user', async (req, res) => {
       const { userId, data } = req.body;
       const pool = getShardPool(userId);
       try {
           await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]);
           res.status(200).send('User added successfully');
       } catch (err) {
           console.error(err);
           res.status(500).send('Error inserting user');
       }
   });

   app.get('/user/:userId', async (req, res) => {
       const userId = parseInt(req.params.userId, 10);
       const pool = getShardPool(userId);
       try {
           const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]);
           res.status(200).json(result.rows);
       } catch (err) {
           console.error(err);
           res.status(500).send('Error retrieving user');
       }
   });

   app.listen(3000, () => console.log('Server running on port 3000'));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

BigQuery secara automatik mengendalikan pembahagian dan pengedaran, meminimumkan keperluan untuk pembahagian manual.


4. Mengendalikan Penyelewengan Kunci Shard dalam Aplikasi Node.js

Apabila berurusan dengan data yang dipecahkan dalam aplikasi Node.js, isu seperti kekunci serpihan yang tidak sejajar dan keperluan untuk penyatuan-pengumpulan sering timbul. Begini cara anda boleh mengharungi cabaran ini menggunakan Node.js dan Express.

Mengendalikan Penyertaan Siaran dalam Node.js

Jika gabungan memerlukan penyiaran jadual kecil (mis., pengguna) merentas semua serpihan, anda boleh melaksanakan gabungan dalam lapisan aplikasi dengan mengambil jadual kecil sekali dan menggunakannya untuk bergabung dengan data daripada jadual berpecah.

SELECT o.order_id, u.user_name
FROM orders o
JOIN users u
ON o.user_id = u.user_id;
Salin selepas log masuk

Mengendalikan Pertanyaan Scatter-Gather dalam Node.js

Untuk pertanyaan yang melibatkan cantuman scatter-gather (cth., apabila kekunci shard tidak sejajar), anda perlu menanyakan semua serpihan dan mengagregatkan hasil dalam lapisan aplikasi anda.

SELECT o.order_id, u.user_name
FROM `project.dataset.orders` o
JOIN `project.dataset.users` u
ON o.user_id = u.user_id
WHERE o.order_date BETWEEN '2024-01-01' AND '2024-12-31';
Salin selepas log masuk

5. Amalan Terbaik untuk Pengoptimuman Pertanyaan dengan Data Berkongsi

Apabila berurusan dengan data yang dipecahkan dan melakukan gabungan, pertimbangkan amalan terbaik berikut:

  1. Jajarkan Kekunci Shard: Apabila boleh, pastikan jadual berkaitan menggunakan kekunci shard yang sama. Ini meminimumkan keperluan untuk cantuman rentas serpihan dan meningkatkan prestasi.

  2. Nyahnormalisasi: Dalam senario yang kerap disertai, pertimbangkan untuk menyahnormalkan data anda. Sebagai contoh, anda boleh menyimpan maklumat pengguna terus dalam jadual siaran, mengurangkan keperluan untuk menyertai.

  3. Gunakan Broadcast Joins untuk Meja Kecil: Jika salah satu jadual cukup kecil, siarkan ke semua nod untuk mengelakkan pertanyaan serakan-kumpul.

  4. Data Pra-Sertai: Untuk data yang kerap diakses, pertimbangkan untuk pra-menyertai dan menyimpan hasil dalam paparan nyata atau cache.

  5. Memanfaatkan Enjin Pertanyaan Teragih: Untuk pertanyaan analitikal yang kompleks, gunakan sistem seperti Presto atau BigQuery yang mengendalikan gabungan dan pengoptimuman yang diedarkan secara automatik.


6. Amalan Terbaik untuk Penomboran Berasaskan Kursor dengan Data Berkongsi

Dalam sistem teragih dengan sharding sedemikian, penomboran berasaskan kursor perlu dikendalikan dengan berhati-hati, terutamanya kerana data tersebar merentasi berbilang serpihan. Kuncinya ialah:

  1. Pisah pertanyaan: Tanya setiap serpihan secara berasingan untuk data yang berkaitan.
  2. Kendalikan penomboran dalam ketulan: Tentukan cara membuat penomboran merentas data serpihan (sama ada pada siaran atau pengguna), dan kumpulkan hasil yang berkaitan.
  3. Sertai di peringkat aplikasi: Ambil hasil daripada setiap serpihan, sertai data dalam ingatan, dan kemudian gunakan logik kursor untuk halaman seterusnya.

Mari kita lihat bagaimana kita boleh melaksanakan perkara ini dengan Node.js dan Express, dengan mengambil kira bahawa data berada pada serpihan yang berbeza dan memerlukan gabungan pasca ambil pada peringkat aplikasi.

Cara Mengendalikan Penomboran dan Cantuman dengan Jadual Sharded

Anggap kita ada:

  • siaran jadual dipecahkan oleh user_id.
  • pengguna jadual dipecahkan oleh user_id.

Kami ingin mendapatkan semula siaran penomboran untuk pengguna tertentu, tetapi memandangkan pengguna dan siaran berada pada serpihan yang berbeza, kami perlu membahagikan pertanyaan, mengendalikan penomboran dan kemudian melakukan gabungan pada peringkat aplikasi.

Pendekatan:

  1. Pertanyakan Serpihan Berkaitan:

    • Mula-mula, anda perlu menanyakan jadual siaran merentas serpihan untuk mengambil siaran.
    • Selepas mengambil siaran yang berkaitan, gunakan user_id daripada siaran untuk menanyakan jadual pengguna (sekali lagi, merentas serpihan).
  2. Strategi Penomboran:

    • Penomboran pada siaran: Anda boleh menggunakan created_at, post_id atau medan unik lain untuk menomborkan jadual siaran.
    • Penomboran pada pengguna: Anda mungkin perlu mengambil data pengguna secara berasingan atau menggunakan user_id sebagai kursor untuk membuat penomboran melalui pengguna.
  3. Sertai Peringkat Aplikasi:

    • Selepas mendapatkan semula data daripada serpihan yang berkaitan (untuk kedua-dua siaran dan pengguna), sertai mereka di peringkat aplikasi.
  4. Mengendalikan Kursor:

    • Selepas mengambil halaman pertama, gunakan create_at terakhir atau post_id (daripada siaran) sebagai kursor untuk pertanyaan seterusnya.

Contoh Pelaksanaan

1. Siaran Pertanyaan Merentasi Serpihan

Di sini kami akan melaksanakan pertanyaan merentas serpihan siaran yang berbeza, menapis menggunakan kursor (cth., created_at atau post_id).

2. Pertanyaan Pengguna Merentasi Serpihan Menggunakan Data Pos

Sebaik sahaja kami mempunyai post_id dan user_id yang berkaitan daripada pertanyaan pertama, kami akan mengambil data pengguna daripada serpihan yang berkaitan.

   const express = require('express');
   const { Pool } = require('pg');

   const poolShard1 = new Pool({ connectionString: 'postgresql://localhost/shard1' });
   const poolShard2 = new Pool({ connectionString: 'postgresql://localhost/shard2' });

   const app = express();
   app.use(express.json());

   const getShardPool = (userId) => (userId % 2 === 0 ? poolShard1 : poolShard2);

   app.post('/user', async (req, res) => {
       const { userId, data } = req.body;
       const pool = getShardPool(userId);
       try {
           await pool.query('INSERT INTO user_data (user_id, data) VALUES (, )', [userId, data]);
           res.status(200).send('User added successfully');
       } catch (err) {
           console.error(err);
           res.status(500).send('Error inserting user');
       }
   });

   app.get('/user/:userId', async (req, res) => {
       const userId = parseInt(req.params.userId, 10);
       const pool = getShardPool(userId);
       try {
           const result = await pool.query('SELECT * FROM user_data WHERE user_id = ', [userId]);
           res.status(200).json(result.rows);
       } catch (err) {
           console.error(err);
           res.status(500).send('Error retrieving user');
       }
   });

   app.listen(3000, () => console.log('Server running on port 3000'));
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Butiran Utama:

  1. Penomboran pada siaran: Kursor adalah berdasarkan medan create_at atau medan unik lain dalam siaran, yang digunakan untuk membuat penomboran melalui hasil.
  2. Query Shards Independent: Memandangkan siaran dan pengguna dipecahkan pada kunci yang berbeza, kami menanyakan setiap shard secara bebas, mengumpulkan data daripada semua shards sebelum melakukan gabungan pada peringkat aplikasi.
  3. Pengendalian Kursor: Selepas mendapatkan semula keputusan, kami menggunakan terakhir dicipta_pada (atau post_id) daripada siaran untuk menjana kursor untuk halaman seterusnya.
  4. Sertai di Peringkat Aplikasi: Selepas mengambil data daripada serpihan yang berkaitan, kami menyertai siaran dengan data pengguna berdasarkan user_id dalam ingatan.

Kesimpulan

Menguruskan data berpecah dalam sistem yang diedarkan memberikan cabaran yang unik, terutamanya dalam hal melaksanakan gabungan yang cekap. Memahami teknik seperti sambungan siaran, gabungan scatter-gather dan memanfaatkan enjin pertanyaan teragih boleh meningkatkan prestasi pertanyaan dengan ketara. Selain itu, dalam pertanyaan peringkat aplikasi, adalah penting untuk mempertimbangkan penjajaran kunci beling, nyahnormalisasi dan strategi pertanyaan yang dioptimumkan. Dengan mengikuti amalan terbaik ini dan menggunakan alatan yang betul, pembangun boleh memastikan bahawa aplikasi mereka mengendalikan data berpecah dengan berkesan dan mengekalkan prestasi pada skala.

Atas ialah kandungan terperinci Mengendalikan Data Berkongsi dalam Sistem Teragih: Penyelaman Mendalam ke dalam Gabungan, Penyiaran dan Pengoptimuman Pertanyaan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan