Ang GitHub ay higit pa sa isang platform para sa pagho-host ng mga repositoryo—ito ay isang lubos na nasusukat na ipinamamahaging sistema na nagpoproseso ng milyun-milyong transaksyon araw-araw. Mula sa paghawak ng mga kahilingan sa git push hanggang sa mahusay na pag-compute ng mga pagkakaiba sa file, umaasa ang GitHub sa matatag na mga algorithm at arkitektura upang matiyak ang mataas na pagganap at pagiging maaasahan.
Tinutuklasan ng artikulong ito kung paano pinoproseso ng GitHub ang napakaraming data, sinusukat upang pangasiwaan ang milyun-milyong transaksyon, at gumagamit ng mga diff algorithm upang masubaybayan ang mga pagbabago sa file nang mahusay. Kasama rin sa artikulo ang mga detalyadong pagpapatupad ng JavaScript ng mga pangunahing algorithm na ginagamit sa mga version control system.
Dapat harapin ng mga modernong bersyon ng control system ang ilang pangunahing hamon:
Ang mga prinsipyong ito ay hindi eksklusibo sa GitHub. Ang mga katulad na arkitektura at algorithm ay ginagamit sa GitLab, Bitbucket, at iba pang mga platform na nakikitungo sa kontrol ng bersyon sa sukat.
Kapag sinusubaybayan ang mga pagbabago sa isang file, ang GitHub (at ang Git mismo) ay gumagamit ng mga diff algorithm upang kalkulahin ang pinakamababang bilang ng mga pag-edit na kinakailangan upang baguhin ang isang bersyon ng isang file sa isa pa. Ang isang malawakang ginagamit na algorithm para dito ay ang Myers' Diff Algorithm.
Nahanap ng algorithm ng Myers ang pinakamaikling pagkakasunud-sunod ng mga pagpapasok at pagtanggal na kinakailangan upang ma-convert ang isang file sa isa pa. Gumagana ito sa pamamagitan ng pag-ulit sa pamamagitan ng posibleng mga distansya sa pag-edit (d) at pag-compute ng mga posibleng pagbabago sa "diagonal" sa edit graph.
/** * Computes the minimum edit distance between two arrays using Myers' Diff Algorithm. * @param {Array} a - The original array (eg, characters of a file) * @param {Array} b - The modified array * @returns {number} The minimum number of edit operations required */ function myersDiff(a, b) { const N = a.length; const M = b.length; const maxD = N + M; let v = { 1: 0 }; for (let d = 0; d <= maxD; d++) { for (let k = -d; k <= d; k += 2) { let x; if (k === -d || (k !== d && (v[k - 1] || 0) < (v[k + 1] || 0))) { x = v[k + 1] || 0; } else { x = (v[k - 1] || 0) + 1; } let y = x - k; while (x < N && y < M && a[x] === b[y]) { x++; y++; } v[k] = x; if (x >= N && y >= M) { return d; } } } return maxD; } // Example usage: const oldVersion = Array.from("Hello World"); const newVersion = Array.from("Hello GitHub World"); const operations = myersDiff(oldVersion, newVersion); console.log(`Minimum number of edits: ${operations}`);
Breakdown ng code:
Initialization: Ang algorithm ay nagpapasimula ng array v upang mag-imbak ng maximum na x value para sa bawat diagonal sa edit graph.
Umikot sa posibleng mga distansya sa pag-edit (d): Umuulit sa bawat posibleng bilang ng mga pag-edit na kailangan.
Pag-compute ng pinakamainam na landas: Tinutukoy kung ilalagay o tatanggalin batay sa mga halaga ng v[k].
Hakbang na "Greedy match": Gumagalaw nang pahilis hangga't tumutugma ang mga character, na binabawasan ang mga hindi kinakailangang operasyon.
Upang mahawakan ang milyun-milyong transaksyon, gumagamit ang GitHub ng multi-layered na arkitektura. Narito kung paano dumadaloy ang isang karaniwang transaksyon:
Ang arkitektura na ito ay nagbibigay-daan sa GitHub na mag-scale nang mahusay, na tinitiyak na walang isang bahagi ang magiging bottleneck
Pinoproseso ng GitHub ang mga transaksyon nang asynchronous upang mahawakan ang mataas na trapiko. Ginagaya ng sumusunod na JavaScript code ang parallel processing ng mga transaksyon gamit ang Promises.
/** * Simulates a transaction in a version control system. */ class Transaction { constructor(id, action, payload) { this.id = id; this.action = action; this.payload = payload; } } /** * Simulates processing a transaction step-by-step. * @param {Transaction} tx - The transaction to process * @returns {Promise<string>} The result of processing */ function processTransaction(tx) { return new Promise((resolve) => { console.log(`Processing transaction ${tx.id}: ${tx.action}`); setTimeout(() => { console.log(`Indexing ${tx.id}...`); setTimeout(() => { console.log(`Computing diff for ${tx.id}...`); setTimeout(() => { console.log(`Updating database for ${tx.id}...`); resolve("success"); }, 100); }, 50); }, 100); }); } /** * Simulates processing multiple transactions in parallel. */ async function processTransactions() { const transactions = [ new Transaction("tx001", "commit", "Modified file A"), new Transaction("tx002", "commit", "Fixed bug in file B"), new Transaction("tx003", "merge", "Merged branches"), ]; const promises = transactions.map(async (tx) => { const result = await processTransaction(tx); console.log(`Transaction ${tx.id} result: ${result}`); }); await Promise.all(promises); console.log("All transactions processed."); } // Run transaction processing processTransactions();
Mga pangunahing takeaway mula sa code na ito:
Ang kakayahan ng GitHub na magproseso ng milyun-milyong transaksyon bawat araw ay nakasalalay sa kumbinasyon ng:
Ang mga diskarteng ito ay hindi eksklusibo sa GitHub—malawakang ginagamit ang mga ito sa GitLab, Bitbucket, at malalaking sistema ng pagpoproseso ng data. Ang pag-unawa sa mga prinsipyong ito ay nakakatulong sa mga developer na bumuo ng mahusay, nasusukat na mga application para sa paghawak ng mataas na dami ng mga transaksyon.