LVM සහ Matryoshka අතර පොදු වන්නේ කුමක්ද?

සුභ දවසක්.
md RAID + LVM භාවිතයෙන් KVM සඳහා දත්ත ගබඩා කිරීමේ පද්ධතියක් ගොඩනැගීමේ මගේ ප්‍රායෝගික අත්දැකීම ප්‍රජාව සමඟ බෙදා ගැනීමට මම කැමැත්තෙමි.

වැඩසටහනට ඇතුළත් වනු ඇත:

  • NVMe SSD වෙතින් md RAID 1 ගොඩනැගීම.
  • SATA SSD සහ සාමාන්‍ය ධාවක වලින් md RAID 6 එකලස් කිරීම.
  • SSD RAID 1/6 මත TRIM/DISCARD ක්‍රියාකාරිත්වයේ විශේෂාංග.
  • පොදු තැටි කට්ටලයක් මත ඇරඹිය හැකි md RAID 1/6 අරාවක් නිර්මාණය කිරීම.
  • BIOS තුළ NVMe සහාය නොමැති විට NVMe RAID 1 මත පද්ධතිය ස්ථාපනය කිරීම.
  • LVM හැඹිලි සහ LVM තුනී භාවිතා කිරීම.
  • BTRFS ස්නැප්ෂොට් භාවිතා කිරීම සහ උපස්ථය සඳහා යැවීම/ලැබීම.
  • BTRFS විලාස උපස්ථ සඳහා LVM තුනී ස්නැප්ෂොට් සහ thin_delta භාවිතා කිරීම.

ඔබ කැමති නම්, කරුණාකර cat බලන්න.

අයදුම් පත්රය

මෙම ලිපියෙන් ද්‍රව්‍ය/උදාහරණ/කේතය/ඉඟි/දත්ත භාවිතා කිරීමේ හෝ භාවිතා නොකිරීමේ ප්‍රතිවිපාක සම්බන්ධයෙන් කතුවරයා කිසිදු වගකීමක් දරන්නේ නැත. මෙම ද්රව්ය කියවීමෙන් හෝ ඕනෑම ආකාරයකින් භාවිතා කිරීමෙන්, මෙම ක්රියාවන්ගේ සියලු ප්රතිවිපාක සඳහා ඔබ වගකීම භාර ගනී. විය හැකි ප්රතිවිපාක ඇතුළත් වේ:

  • හැපෙනසුළු-බැදපු NVMe SSDs.
  • සම්පුර්ණයෙන්ම භාවිතා කරන ලද පටිගත කිරීමේ සම්පත සහ SSD ධාවකයන්ගේ අසාර්ථකත්වය.
  • උපස්ථ පිටපත් ඇතුළුව සියලුම ධාවකවල සියලුම දත්ත සම්පූර්ණයෙන්ම නැතිවීම.
  • දෝෂ සහිත පරිගණක දෘඩාංග.
  • කාලය, ස්නායු හා මුදල් නාස්ති කිරීම.
  • ඉහත ලැයිස්තුගත කර නොමැති වෙනත් ඕනෑම ප්රතිවිපාක.

යකඩ

ලබා ගත හැකි වූයේ:

Z2013 චිප්සෙට් සමඟින් 87 පමණ සිට මවු පුවරුව, Intel Core i7 / Haswell සමඟින් සම්පූර්ණයි.

  • ප්‍රොසෙසරය හරය 4ක්, නූල් 8ක්
  • 32 GB DDR3 RAM
  • 1 x 16 හෝ 2 x 8 PCIe 3.0
  • 1 x 4 + 1 x 1 PCIe 2.0
  • 6 x 6 GBps SATA 3 සම්බන්ධක

SAS ඇඩැප්ටරය LSI SAS9211-8I IT / HBA මාදිලියට දැල්වීය. RAID-සක්‍රීය ස්ථිරාංග හිතාමතාම HBA ස්ථිරාංග සමඟ ප්‍රතිස්ථාපනය කර ඇත:

  1. ඔබට ඕනෑම වේලාවක මෙම ඇඩප්ටරය ඉවතට විසි කර ඔබට හමු වූ වෙනත් එකක් සමඟ එය ප්‍රතිස්ථාපනය කළ හැකිය.
  2. TRIM/Discard සාමාන්‍යයෙන් තැටි මත ක්‍රියා කරයි, මන්ද... RAID ස්ථිරාංග තුළ මෙම විධාන කිසිසේත්ම සහය නොදක්වන අතර, HBA, සාමාන්‍යයෙන්, බසය හරහා සම්ප්‍රේෂණය වන විධානයන් ගැන තැකීමක් නොකරයි.

දෘඪ තැටි - HGST Travelstar 8K7 කෑලි 1000ක් 1 ආකාර සාධකයක 2.5 TB ධාරිතාවක් සහිත, ලැප්ටොප් සඳහා. මෙම ධාවකයන් කලින් RAID 6 අරාවක විය. නව ක්‍රමය තුළ ඔවුන්ටද ප්‍රයෝජනයක් ලැබෙනු ඇත. දේශීය උපස්ථ ගබඩා කිරීමට.

අතිරේකව එකතු කර ඇත:

6 කෑලි SATA SSD ආකෘතිය Samsung 860 QVO 2TB. මෙම SSD වලට විශාල පරිමාවක් අවශ්‍ය විය, SLC හැඹිලියක් තිබීම, විශ්වසනීයත්වය සහ අඩු මිලක් අවශ්‍ය විය. ඉවතලීම/ශුන්‍යය සඳහා සහය අවශ්‍ය විය, එය dmesg හි පේළිය මගින් පරීක්ෂා කෙරේ:

kernel: ata1.00: Enabling discard_zeroes_data

NVMe SSD මාදිලියේ Samsung SSD 2 EVO 970GB කෑලි 500ක්.

මෙම SSD සඳහා, ඔබේ අවශ්‍යතා සඳහා අහඹු කියවීමේ/ලිවීමේ වේගය සහ සම්පත් ධාරිතාව වැදගත් වේ. ඔවුන් සඳහා රේඩියේටර්. අනිවාර්යයෙන්. නියත වශයෙන්ම. එසේ නොමැති නම්, පළමු RAID සමමුහුර්තකරණය තුළ හැපෙනසුළු වන තෙක් ඒවා ෆ්රයි.

8 x NVMe SSD සඳහා StarTech PEX2M2E2 ඇඩැප්ටරය PCIe 3.0 8x slot තුළ ස්ථාපනය කර ඇත. මෙය නැවතත්, HBA එකක් පමණි, නමුත් NVMe සඳහා. එය බිල්ට් PCIe ස්විචයක් තිබීම හේතුවෙන් මවු පුවරුවෙන් PCIe bifurcation සහාය අවශ්‍ය නොවන නිසා එය ලාභ ඇඩප්ටරවලින් වෙනස් වේ. එය x1 PCIe 1.0 slot එකක් වුවද, PCIe සමඟ පැරණිතම පද්ධතියේ පවා ක්‍රියා කරයි. ස්වාභාවිකවම, සුදුසු වේගයකින්. එහි RAID නොමැත. බෝඩ් එකෙහි බිල්ට් BIOS නොමැත. එබැවින්, ඔබේ පද්ධතිය NVMe සමඟ ආරම්භ කිරීමට ඉන්ද්‍රජාලික ලෙස ඉගෙන නොගනු ඇත, මෙම උපාංගයට ස්තූතිවන්ත වන පරිදි NVMe RAID වඩා අඩුය.

මෙම සංරචකය තනිකරම පද්ධතියේ එක් නොමිලේ 8x PCIe 3.0 තිබීම නිසා පමණක් වන අතර, නොමිලේ තව් 2 ක් තිබේ නම්, එය පහසුවෙන් සත දෙකක් PEX4M2E1 හෝ ඇනලොග් වලින් ප්‍රතිස්ථාපනය කළ හැකිය, එය ඕනෑම තැනක 600 ක මිලකට මිලදී ගත හැකිය. රූබල්.

SSD/HDD හැර, සියලු දත්ත සංරක්ෂණය කරමින් සමස්ත පද්ධතියම සම්පූර්ණයෙන්ම ප්‍රතිස්ථාපනය කිරීමට හැකිවන පරිදි, සියලු ආකාරයේ දෘඪාංග හෝ බිල්ට් චිප්සෙට්/BIOS RAID ප්‍රතික්ෂේප කිරීම හිතාමතාම සිදු කරන ලදී. ඉතා මැනවින්, සම්පූර්ණයෙන්ම නව/වෙනස් දෘඪාංග වෙත ගමන් කරන විට ස්ථාපිත මෙහෙයුම් පද්ධතිය පවා සුරැකිය හැක. ප්රධාන දෙය නම් SATA සහ PCIe වරායන් තිබීමයි. එය සජීවී සංයුක්ත තැටියක් හෝ ආරම්භ කළ හැකි ෆ්ලෑෂ් ධාවකයක් වැනිය, ඉතා වේගවත් සහ ටිකක් විශාලයි.

සැහැල්ලුඑසේ නොමැතිනම්, සිදුවන්නේ කුමක්දැයි ඔබ දන්නවා - සමහර විට ඔබ රැගෙන යාමට මුළු අරාවම ඉක්මනින් රැගෙන යා යුතුය. නමුත් මට දත්ත නැති කර ගැනීමට අවශ්‍ය නැත. මෙය සිදු කිරීම සඳහා, සියලුම සඳහන් කළ මාධ්‍යයන් සම්මත නඩුවේ 5.25 බොක්කෙහි විනිවිදක මත පහසුවෙන් පිහිටා ඇත.

හොඳයි, සහ, ඇත්ත වශයෙන්ම, ලිනක්ස් හි SSD හැඹිලියේ විවිධ ක්රම සමඟ අත්හදා බැලීම සඳහා.

දෘඪාංග වැටලීම් නීරසයි. එය සක්රිය කරන්න. එය එක්කෝ වැඩ කරයි, නැතහොත් නැත. සහ mdadm සමඟ සෑම විටම විකල්ප තිබේ.

මෘදුකාංග

මීට පෙර, EOL වලට ආසන්න දෘඩාංග මත Debian 8 Jessie ස්ථාපනය කර ඇත. RAID 6 එකලස් කරන ලද්දේ LVM සමඟ යුගල කර ඇති ඉහත සඳහන් HDD වලින්. එය kvm/libvirt හි අතථ්‍ය යන්ත්‍ර ධාවනය කළේය.

නිසා අතේ ගෙන යා හැකි ඇරඹුම් SATA/NVMe ෆ්ලෑෂ් ඩ්‍රයිව් නිර්මාණය කිරීමේදී කතුවරයාට සුදුසු පළපුරුද්දක් ඇති අතර, සුපුරුදු උචිත අච්චුව බිඳ නොදැමීම සඳහා, උබුන්ටු 18.04 ඉලක්ක පද්ධතිය ලෙස තෝරාගෙන ඇති අතර, එය දැනටමත් ප්‍රමාණවත් ලෙස ස්ථාවර කර ඇත, නමුත් තවමත් වසර 3 ක් ඇත. අනාගතයේදී සහාය.

සඳහන් කළ පද්ධතිය තුළ අපට අවශ්‍ය සියලුම දෘඪාංග ධාවක අඩංගු වේ. අපට කිසිදු තෙවන පාර්ශවීය මෘදුකාංගයක් හෝ ධාවක අවශ්‍ය නොවේ.

ස්ථාපනය සඳහා සූදානම් වීම

පද්ධතිය ස්ථාපනය කිරීමට අපට උබුන්ටු ඩෙස්ක්ටොප් රූපය අවශ්‍ය වේ. සේවාදායක පද්ධතියට යම් ආකාරයක ප්‍රබල ස්ථාපකයක් ඇත, එමඟින් UEFI පද්ධති කොටස එක් තැටි මතට තල්ලු කිරීමෙන් අක්‍රිය කළ නොහැකි අධික ස්වාධීනත්වයක් පෙන්නුම් කරයි, සියලු අලංකාරය නරක් වේ. ඒ අනුව, එය UEFI මාදිලියේ පමණක් ස්ථාපනය කර ඇත. විකල්ප කිසිවක් ඉදිරිපත් නොකරයි.

අපි මේ ගැන සතුටු නැහැ.

ඇයි?අවාසනාවකට, UEFI ඇරඹුම් ඇරඹුම් මෘදුකාංග RAID සමඟ අතිශයින් දුර්වල ලෙස අනුකූල වේ, මන්ද... UEFI ESP කොටස සඳහා කිසිවෙකු අපට වෙන් කිරීම් ලබා නොදේ. USB පෝට් එකක ෆ්ලෑෂ් ඩ්‍රයිව් එකක ESP කොටස තැබීමට යෝජනා කරන වට්ටෝරු අන්තර්ජාලයේ ඇත, නමුත් මෙය අසාර්ථක අවස්ථාවකි. UEFI BIOS හට මෙම කොටස දැකීම වලක්වනු නොලබන මෙටා-දත්ත අනුවාදය 1 සමඟ mdadm RAID 0.9 මෘදුකාංග භාවිතා කරන වට්ටෝරු තිබේ, නමුත් BIOS හෝ වෙනත් දෘඪාංග OS එකක් ESP වෙත යමක් ලියා එය වෙනත් එකක් සමඟ සමමුහුර්ත කිරීමට අමතක වන ප්‍රීතිමත් මොහොත දක්වා මෙය ජීවත් වේ. දර්පණ.

මීට අමතරව, UEFI ඇරඹුම NVRAM මත රඳා පවතී, එය තැටි සමඟ නව පද්ධතියට ගමන් නොකරනු ඇත, මන්ද මවු පුවරුවේ කොටසකි.

ඉතින්, අපි අලුත් රෝදයක් ප්‍රතිනිර්මාණය කරන්නේ නැහැ. UEFI-අනුකූල පද්ධති මත CSM හි සාඩම්බර නාමය දරන, දැන් Legacy/BIOS boot ලෙස හඳුන්වන, සූදානම් කළ, කාලය පරීක්ෂා කළ සීයාගේ බයිසිකලයක් අප සතුව දැනටමත් ඇත. අපි එය රාක්කයෙන් ඉවතට ගෙන ලිහිසි කර ටයර් පොම්ප කර තෙත් රෙද්දකින් පිස දමමු.

Ubuntu හි ඩෙස්ක්ටොප් අනුවාදයද Legacy bootloader සමඟ නිසි ලෙස ස්ථාපනය කළ නොහැක, නමුත් මෙහි, ඔවුන් පවසන පරිදි, අවම වශයෙන් විකල්ප තිබේ.

එබැවින්, අපි දෘඩාංග එකතු කර උබුන්ටු සජීවී ආරම්භ කළ හැකි ෆ්ලෑෂ් ධාවකයෙන් පද්ධතිය පටවන්නෙමු. අපට පැකේජ බාගැනීමට අවශ්‍ය වනු ඇත, එබැවින් අපි ඔබ වෙනුවෙන් වැඩ කරන ජාලය සකසන්නෙමු. එය ක්‍රියා නොකරන්නේ නම්, ඔබට අවශ්‍ය පැකේජ කල්තියා ෆ්ලෑෂ් ඩ්‍රයිව් එකකට පැටවිය හැකිය.

අපි ඩෙස්ක්ටොප් පරිසරයට ගොස්, ටර්මිනල් ඉමුලේටරය දියත් කර, අපි යන්නෙමු:

#sudo bash

කෙසේද…?ඉහත පේළිය සුඩෝ ගැන හොලිවාර් සඳහා කැනොනිකල් ප්‍රේරකයයි. සී බීоවැඩි අවස්ථා පැමිණේ සහоවැඩි වගකීමක්. ප්‍රශ්නය වන්නේ එය ඔබටම ගත හැකිද යන්නයි. බොහෝ අය සිතන්නේ මේ ආකාරයෙන් sudo භාවිතා කිරීම අවම වශයෙන් පරිස්සම් නොවන බවයි. කෙසේ වුවද:

#apt-get install mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc

ඇයි ZFS නැත්තේ...?අපි අපේ පරිගණකයේ මෘදුකාංග ස්ථාපනය කරන විට, අපි අත්‍යවශ්‍යයෙන්ම අපගේ දෘඩාංග මෙම මෘදුකාංගයේ සංවර්ධකයින්ට ධාවනය කිරීමට ලබා දෙන්නෙමු.
මෙම මෘදුකාංගය අපගේ දත්තවල ආරක්‍ෂාව සමඟ විශ්වාස කරන විට, අපි මෙම දත්ත ප්‍රතිසාධනය කිරීමට යන වියදමට සමාන ණයක් ලබා ගනිමු, එය කවදා හෝ අපට ගෙවිය යුතුය.

මෙම දෘෂ්ටි කෝණයෙන්, ZFS යනු ෆෙරාරි වන අතර, mdadm+lvm යනු බයිසිකලයක් වැනි ය.

විෂයානුබද්ධව, කතුවරයා ෆෙරාරි වෙනුවට නාඳුනන පුද්ගලයින්ට ණයට බයිසිකලයක් දීමට කැමැත්තක් දක්වයි. එහිදී, නිකුතුවේ මිල වැඩි නොවේ. අයිතිවාසිකම් අවශ්ය නොවේ. මාර්ග නීති වලට වඩා සරලයි. වාහන නැවැත්වීම නොමිලේ. රට හරහා ගමන් කිරීමේ හැකියාව වඩා හොඳය. ඔබට සෑම විටම බයිසිකලයකට කකුල් සවි කළ හැකි අතර, ඔබේම දෑතින් බයිසිකලයක් අලුත්වැඩියා කළ හැකිය.

ඇයි එහෙනම් BTRFS...?මෙහෙයුම් පද්ධතිය ආරම්භ කිරීම සඳහා, අපට කොටුවෙන් පිටත Legacy/BIOS GRUB තුළ සහය දක්වන ගොනු පද්ධතියක් අවශ්‍ය වන අතර, ඒ සමඟම සජීවී ඡායාරූප සඳහා සහය දක්වයි. අපි එය /boot කොටස සඳහා භාවිතා කරමු. මීට අමතරව, කතුවරයා / (root) සඳහා මෙම FS භාවිතා කිරීමට කැමැත්තක් දක්වයි, වෙනත් ඕනෑම මෘදුකාංගයක් සඳහා ඔබට LVM මත වෙනම කොටස් සාදා ඒවා අවශ්‍ය නාමාවලි තුළ සවි කළ හැකි බව සටහන් කිරීමට අමතක නොකරයි.

අපි මෙම FS මත අතථ්‍ය යන්ත්‍රවල හෝ දත්ත සමුදායේ කිසිදු රූපයක් ගබඩා නොකරමු.
මෙම FS භාවිතා කරනුයේ එය ක්‍රියාවිරහිත නොකර පද්ධතියේ ස්නැප්ෂොට් සෑදීමට පමණක් වන අතර පසුව send/recieve භාවිතයෙන් මෙම ස්නැප්ෂොට් උපස්ථ තැටියකට මාරු කරයි.

ඊට අමතරව, කතුවරයා සාමාන්‍යයෙන් කැමති වන්නේ අවම මෘදුකාංගයක් සෘජුවම දෘඪාංග මත තබා ගැනීමට සහ IOMMU හරහා KVM වෙත GPU සහ PCI-USB ධාරක පාලකයන් යොමු කිරීම වැනි දේවල් භාවිතා කරමින් අතථ්‍ය යන්ත්‍රවල අනෙකුත් සියලුම මෘදුකාංග ධාවනය කිරීමටයි.

දෘඪාංගයේ ඉතිරිව ඇත්තේ දත්ත ගබඩා කිරීම, අථත්යකරණය සහ උපස්ථය පමණි.

ඔබ ZFS වඩාත් විශ්වාස කරන්නේ නම්, ප්‍රතිපත්තිමය වශයෙන්, නිශ්චිත යෙදුම සඳහා ඒවා එකිනෙකට හුවමාරු කළ හැකිය.

කෙසේ වෙතත්, කර්තෘ හිතාමතාම ZFS, BRTFS සහ LVM සතුව ඇති බිල්ට්-ඉන් දර්පණ/RAID සහ අතිරික්ත විශේෂාංග නොසලකා හරියි.

අමතර තර්කයක් ලෙස, BTRFS හට සසම්භාවී ලිවීම් අනුක්‍රමික ඒවා බවට පත් කිරීමේ හැකියාව ඇත, එය HDD මත ස්නැප්ෂොට්/බැකප් සමමුහුර්ත කිරීමේ වේගය කෙරෙහි අතිශයින් ධනාත්මක බලපෑමක් ඇති කරයි.

අපි සියලු උපාංග නැවත පරිලෝකනය කරමු:

#udevadm control --reload-rules && udevadm trigger

අපි වටපිට බලමු:

#lsscsi && nvme list
[0:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sda
[1:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdb
[2:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdc
[3:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdd
[4:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sde
[5:0:0:0] disk ATA Samsung SSD 860 2B6Q /dev/sdf
[6:0:0:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdg
[6:0:1:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdh
[6:0:2:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdi
[6:0:3:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdj
[6:0:4:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdk
[6:0:5:0] disk ATA HGST HTS721010A9 A3B0 /dev/sdl
[6:0:6:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdm
[6:0:7:0] disk ATA HGST HTS721010A9 A3J0 /dev/sdn
Node SN Model Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 S466NXXXXXXX15L Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7
/dev/nvme1n1 S5H7NXXXXXXX48N Samsung SSD 970 EVO 500GB 1 0,00 GB / 500,11 GB 512 B + 0 B 2B2QEXE7

තැටි පිරිසැලසුම

NVMe SSD

නමුත් අපි ඒවා කිසිම ආකාරයකින් සලකුණු නොකරමු. සියල්ලටම වඩා, අපගේ BIOS මෙම ධාවකයන් නොපෙනේ. එබැවින්, ඔවුන් සම්පූර්ණයෙන්ම මෘදුකාංග RAID වෙත යනු ඇත. අපි එහි අංශ සාදන්නේවත් නැත. ඔබට "කැනන්" හෝ "ප්‍රධාන වශයෙන්" අනුගමනය කිරීමට අවශ්‍ය නම්, HDD වැනි විශාල කොටසක් සාදන්න.

SATA HDD

මෙහි විශේෂ දෙයක් නිර්මාණය කිරීමට අවශ්ය නැත. අපි සෑම දෙයක් සඳහාම එක් අංශයක් සාදන්නෙමු. BIOS විසින් මෙම තැටි දකින අතර ඒවායින් ආරම්භ කිරීමට පවා උත්සාහ කළ හැකි නිසා අපි කොටසක් සාදන්නෙමු. පද්ධතියට හදිසියේම මෙය කළ හැකි වන පරිදි අපි පසුව මෙම තැටිවල GRUB ස්ථාපනය කරන්නෙමු.

#cat >hdd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sdg
unit: sectors

/dev/sdg1 : start= 2048, size= 1953523120, type=fd, bootable
EOF
#sfdisk /dev/sdg < hdd.part
#sfdisk /dev/sdh < hdd.part
#sfdisk /dev/sdi < hdd.part
#sfdisk /dev/sdj < hdd.part
#sfdisk /dev/sdk < hdd.part
#sfdisk /dev/sdl < hdd.part
#sfdisk /dev/sdm < hdd.part
#sfdisk /dev/sdn < hdd.part

SATA SSD

මෙහිදී අපට රසවත් දේවල් සිදු වේ.

පළමුව, අපගේ ධාවක ප්‍රමාණය 2 TB වේ. මෙය MBR සඳහා පිළිගත හැකි පරාසය තුළ පවතී, එය අප භාවිතා කරනු ඇත. අවශ්ය නම්, GPT සමඟ ප්රතිස්ථාපනය කළ හැකිය. GPT තැටිවල MBR-අනුකූල පද්ධති පළමු ටෙරාබයිට් 4 තුළ පිහිටා තිබේ නම්, පළමු කොටස් 2 බැලීමට ඉඩ සලසන අනුකූලතා ස්ථරයක් ඇත. ප්රධාන දෙය නම් මෙම තැටිවල boot කොටස සහ bios_grub කොටස ආරම්භයේ තිබිය යුතුය. මෙය ඔබට GPT Legacy/BIOS ධාවකයන්ගෙන් ආරම්භ කිරීමට පවා ඉඩ සලසයි.

නමුත් මෙය අපගේ නඩුව නොවේ.

මෙහිදී අපි කොටස් දෙකක් සාදන්නෙමු. පළමු එක 1 GB ප්‍රමාණයෙන් යුක්ත වන අතර RAID 1 /boot සඳහා භාවිතා වේ.

දෙවැන්න RAID 6 සඳහා භාවිතා කරන අතර ධාවකයේ අවසානයේ කුඩා වෙන් නොකළ ප්රදේශයක් හැර ඉතිරි සියලු නිදහස් ඉඩ ලබා ගනී.

මෙම සලකුණු නොකළ ප්රදේශය කුමක්ද?ජාලයේ මූලාශ්‍රවලට අනුව, අපගේ SATA SSD සතුව ගිගාබයිට් 6 සිට 78 දක්වා ප්‍රමාණයෙන් ගතිකව පුළුල් කළ හැකි SLC හැඹිලියක් ඇත. ධාවකයේ දත්ත පත්රිකාවේ "ගිගාබයිට්" සහ "ගිබිබයිට්" අතර වෙනස නිසා අපි "නොමිලේ" 6 ගිගාබයිට් ලබා ගනිමු. ඉතිරි ගිගාබයිට් 72 වෙන් කරනු ලබන්නේ භාවිතයට නොගත් අවකාශයෙනි.

මෙහිදී අප සතුව SLC හැඹිලියක් ඇති බව සැලකිල්ලට ගත යුතු අතර, අවකාශය 4 bit MLC ආකාරයෙන් අල්ලාගෙන ඇත. අපට ඵලදායී ලෙස අදහස් වන්නේ සෑම ගිගාබයිට් 4ක නිදහස් ඉඩක් සඳහාම අපට ලැබෙන්නේ SLC හැඹිලිය ගිගාබයිට් 1ක් පමණක් බවයි.

ගිගාබයිට් 72 ක් 4 න් ගුණ කර ගිගාබයිට් 288 ක් ලබා ගන්න. ධාවකයන්ට SLC හැඹිලිය සම්පූර්ණයෙන් භාවිතා කිරීමට ඉඩ දීම සඳහා අපි සලකුණු නොකරන නිදහස් ඉඩ මෙයයි.

මේ අනුව, අපි සම්පූර්ණ ධාවකයන් හයකින් SLC හැඹිලි ගිගාබයිට් 312 දක්වා ඵලදායී ලෙස ලබා ගනිමු. සියලුම ධාවක වලින්, 2 ක් RAID හි අතිරික්තය සඳහා භාවිතා කරනු ඇත.

මෙම හැඹිලි ප්‍රමාණය සැබෑ ජීවිතයේ දී ඉතා කලාතුරකින් ලිවීමක් හැඹිලියට නොයන තත්වයක් හමුවීමට ඉඩ සලසයි. QLC මතකයේ ඇති කණගාටුදායකම අඩුපාඩුව සඳහා මෙය ඉතා හොඳින් වන්දි ලබා දෙයි - හැඹිලිය මගහැර දත්ත ලියන විට ඉතා අඩු ලිවීමේ වේගය. ඔබගේ පැටවීම් මෙයට අනුරූප නොවේ නම්, දත්ත පත්‍රිකාවේ ඇති TBW සැලකිල්ලට ගනිමින් ඔබේ SSD එවැනි බරක් යටතේ කොපමණ කාලයක් පවතිනු ඇත්දැයි හොඳින් සිතා බලන ලෙස මම නිර්දේශ කරමි.

#cat >ssd.part << EOF
label: dos
label-id: 0x00000000
device: /dev/sda
unit: sectors

/dev/sda1 : start= 2048, size= 2097152, type=fd, bootable
/dev/sda2 : start= 2099200, size= 3300950016, type=fd
EOF
#sfdisk /dev/sda < ssd.part
#sfdisk /dev/sdb < ssd.part
#sfdisk /dev/sdc < ssd.part
#sfdisk /dev/sdd < ssd.part
#sfdisk /dev/sde < ssd.part
#sfdisk /dev/sdf < ssd.part

Arrays නිර්මාණය කිරීම

පළමුව, අපි යන්ත්රය නැවත නම් කළ යුතුයි. මෙය අවශ්‍ය වන්නේ ධාරක නාමය mdadm තුළ කොතැනක හෝ අරාවේ නමේ කොටසක් වන අතර යම් ස්ථානයකට බලපාන බැවිනි. ඇත්ත වශයෙන්ම, arrays පසුව නැවත නම් කළ හැක, නමුත් මෙය අනවශ්ය පියවරකි.

#mcedit /etc/hostname
#mcedit /etc/hosts
#hostname
vdesk0

NVMe SSD

#mdadm --create --verbose --assume-clean /dev/md0 --level=1 --raid-devices=2 /dev/nvme[0-1]n1

ඇයි - උපකල්පනය-පිරිසිදු...?අරා ආරම්භ කිරීම වැළැක්වීමට. RAID මට්ටම් 1 සහ 6 සඳහා මෙය වලංගු වේ. එය නව අරාවක් නම් ආරම්භ කිරීමකින් තොරව සෑම දෙයක්ම වැඩ කළ හැකිය. එපමනක් නොව, නිර්මාණය මත SSD අරාව ආරම්භ කිරීම TBW සම්පත් නාස්තියකි. එකලස් කරන ලද SSD අරා "ආරම්භ කිරීම" සඳහා අපි හැකි සෑම විටම TRIM/DISCARD භාවිතා කරමු.

SSD අරා සඳහා, RAID 1 DISCARD කොටුවෙන් පිටත සහාය දක්වයි.

SSD RAID 6 DISCARD අරා සඳහා, ඔබ එය කර්නල් මොඩියුල පරාමිතීන් තුළ සක්රිය කළ යුතුය.

මෙය කළ යුත්තේ මෙම පද්ධතියේ 4/5/6 මට්ටමේ array වල භාවිතා වන සියලුම SSDs discard_zeroes_data සඳහා ක්‍රියාකාරී සහායක් ඇත්නම් පමණි. සමහර විට ඔබට මෙම ශ්‍රිතයට සහය දක්වන බව කර්නලයට පවසන අමුතු ධාවකයන් හමු වේ, නමුත් ඇත්ත වශයෙන්ම එය එහි නොමැත, නැතහොත් ශ්‍රිතය සැමවිටම ක්‍රියා නොකරයි. මේ මොහොතේ, සහාය සෑම තැනකම පාහේ පවතී, කෙසේ වෙතත්, දෝෂ සහිත පැරණි ධාවකයන් සහ ස්ථිරාංග ඇත. මෙම හේතුව නිසා, RAID 6 සඳහා පෙරනිමියෙන් DISCARD සහාය අක්‍රිය කර ඇත.

අවධානය යොමු කරන්න, පහත දැක්වෙන විධානය "ශුන්‍ය" සමඟ අරාව "ආරම්භ කිරීම" මගින් NVMe ධාවකවල සියලුම දත්ත විනාශ කරයි.

#blkdiscard /dev/md0

යම් දෙයක් වැරදී ගියහොත්, පියවරක් සඳහන් කිරීමට උත්සාහ කරන්න.

#blkdiscard --step 65536 /dev/md0

SATA SSD

#mdadm --create --verbose --assume-clean /dev/md1 --level=1 --raid-devices=6 /dev/sd[a-f]1
#blkdiscard /dev/md1
#mdadm --create --verbose --assume-clean /dev/md2 --chunk-size=512 --level=6 --raid-devices=6 /dev/sd[a-f]2

ඇයි ඔච්චර ලොකු...?කුට්ටි ප්‍රමාණය වැඩි කිරීම කුට්ටි ප්‍රමාණය ඇතුළුව කුට්ටිවල අහඹු කියවීමේ වේගය කෙරෙහි ධනාත්මක බලපෑමක් ඇති කරයි. මෙය සිදු වන්නේ සුදුසු ප්‍රමාණයේ හෝ කුඩා ප්‍රමාණයේ එක් මෙහෙයුමක් සම්පූර්ණයෙන්ම තනි උපාංගයකින් සම්පූර්ණ කළ හැකි බැවිනි. එබැවින්, සියලුම උපාංග වලින් IOPS සාරාංශ කර ඇත. සංඛ්යා ලේඛනවලට අනුව, IO හි 99% 512K නොඉක්මවයි.

ලිවීමකට RAID 6 IOPS හැම විටම එක් ධාවකයක IOPS වලට වඩා අඩු හෝ සමාන වේ. අහඹු ලෙස කියවන විට, IOPS එක් ධාවකයකට වඩා කිහිප ගුණයකින් වැඩි විය හැකි අතර, මෙහි බ්ලොක් ප්‍රමාණය ප්‍රධාන වැදගත්කමක් දරයි.
RAID 6 අතුරු නිර්මාණයේ නරක පරාමිතියක් ප්‍රශස්ත කිරීමට උත්සාහ කිරීමේ කාරණය කතුවරයා නොදකින අතර ඒ වෙනුවට RAID 6 හොඳ දේ ප්‍රශස්ත කරයි.
NVMe හැඹිලියක් සහ තුනී ප්‍රතිපාදන උපක්‍රම සමඟින් RAID 6 හි දුර්වල අහඹු ලිවීම සඳහා අපි වන්දි ගෙවන්නෙමු.

අපි තවමත් RAID 6 සඳහා DISCARD සක්‍රීය කර නැත. එබැවින් අපි දැනට මෙම අරාව "ආරම්භක" නොකරමු. OS ස්ථාපනය කිරීමෙන් පසුව අපි මෙය පසුව කරන්නෙමු.

SATA HDD

#mdadm --create --verbose --assume-clean /dev/md3 --chunk-size=512 --level=6 --raid-devices=8 /dev/sd[g-n]1

NVMe RAID මත LVM

වේගය සඳහා, අපට මූල ගොනු පද්ධතිය NVMe RAID 1 මත තැබීමට අවශ්‍ය වේ, එය /dev/md0 වේ.
කෙසේ වෙතත්, swap, metadata සහ LVM-cache සහ LVM-thin පාරදත්ත වැනි අනෙකුත් අවශ්‍යතා සඳහා අපට තවමත් මෙම වේගවත් අරාව අවශ්‍ය වනු ඇත, එබැවින් අපි මෙම අරාව මත LVM VG නිර්මාණය කරමු.

#pvcreate /dev/md0
#vgcreate root /dev/md0

අපි root ගොනු පද්ධතිය සඳහා කොටසක් සාදා ගනිමු.

#lvcreate -L 128G --name root root

RAM එකේ ප්‍රමාණය අනුව swapping සඳහා පාටිෂන් එකක් හදමු.

#lvcreate -L 32G --name swap root

OS ස්ථාපනය

සමස්තයක් වශයෙන්, පද්ධතිය ස්ථාපනය කිරීමට අවශ්ය සියල්ල අප සතුව ඇත.

උබුන්ටු සජීවී පරිසරයෙන් පද්ධති ස්ථාපන විශාරද දියත් කරන්න. සාමාන්ය ස්ථාපනය. ස්ථාපනය සඳහා තැටි තෝරාගැනීමේ අදියරේදී පමණක්, ඔබ පහත සඳහන් දෑ සඳහන් කළ යුතුය:

  • /dev/md1, - mount point /boot, FS - BTRFS
  • /dev/root/root (aka /dev/mapper/root-root), - mount point / (root), FS - BTRFS
  • /dev/root/swap (aka /dev/mapper/root-swap), - swap කොටස ලෙස භාවිතා කරන්න
  • /dev/sda මත bootloader ස්ථාපනය කරන්න

ඔබ BTRFS root ගොනු පද්ධතිය ලෙස තෝරාගත් විට, ස්ථාපකය විසින් ස්වයංක්‍රීයව BTRFS වෙළුම් දෙකක් / (root) සඳහා "@" සහ /home සඳහා "@home" නමින් සාදනු ඇත.

අපි ස්ථාපනය ආරම්භ කරමු ...

ඇරඹුම් කාරකය ස්ථාපනය කිරීමේදී දෝෂයක් පෙන්නුම් කරන මාදිලි සංවාද කොටුවකින් ස්ථාපනය අවසන් වේ. අවාසනාවන්ත ලෙස, ඔබට සම්මත මාධ්‍ය භාවිතයෙන් මෙම සංවාදයෙන් පිටවී ස්ථාපනය කරගෙන යාමට නොහැකි වනු ඇත. අපි පද්ධතියෙන් ඉවත් වී නැවත ලොග් වී පිරිසිදු උබුන්ටු සජීවී ඩෙස්ක්ටොප් එකකින් අවසන් වේ. ටර්මිනලය විවෘත කර නැවත:

#sudo bash

ස්ථාපනය දිගටම කරගෙන යාමට chroot පරිසරයක් සාදන්න:

#mkdir /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@ /dev/mapper/root-root /mnt/chroot
#mount -o defaults,space_cache,noatime,nodiratime,discard,subvol=@home /dev/mapper/root-root /mnt/chroot/home
#mount -o defaults,space_cache,noatime,nodiratime,discard /dev/md1 /mnt/chroot/boot
#mount --bind /proc /mnt/chroot/proc
#mount --bind /sys /mnt/chroot/sys
#mount --bind /dev /mnt/chroot/dev

අපි chroot හි ජාලය සහ සත්කාරක නාමය වින්‍යාස කරමු:

#cat /etc/hostname >/mnt/chroot/etc/hostname
#cat /etc/hosts >/mnt/chroot/etc/hosts
#cat /etc/resolv.conf >/mnt/chroot/etc/resolv.conf

අපි chroot පරිසරයට යමු:

#chroot /mnt/chroot

පළමුවෙන්ම, අපි පැකේජ ලබා දෙන්නෙමු:

apt-get install --reinstall mdadm lvm2 thin-provisioning-tools btrfs-tools util-linux lsscsi nvme-cli mc debsums hdparm

අසම්පූර්ණ පද්ධති ස්ථාපනය හේතුවෙන් වංක ලෙස ස්ථාපනය කර ඇති සියලුම පැකේජ පරීක්ෂා කර නිවැරදි කරමු:

#CORRUPTED_PACKAGES=$(debsums -s 2>&1 | awk '{print $6}' | uniq)
#apt-get install --reinstall $CORRUPTED_PACKAGES

යමක් සාර්ථක නොවන්නේ නම්, ඔබට පළමුව /etc/apt/sources.list සංස්කරණය කිරීමට අවශ්‍ය විය හැක

TRIM/DISCARD සක්‍රීය කිරීමට RAID 6 මොඩියුලය සඳහා පරාමිති සකස් කරමු:

#cat >/etc/modprobe.d/raid456.conf << EOF
options raid456 devices_handle_discard_safely=1
EOF

අපි අපේ අරාව ටිකක් වෙනස් කරමු:

#cat >/etc/udev/rules.d/60-md.rules << EOF
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/stripe_cache_size", ATTR{md/stripe_cache_size}="32768"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_min", ATTR{md/sync_speed_min}="48000"
SUBSYSTEM=="block", KERNEL=="md*", ACTION=="change", TEST=="md/sync_speed_max", ATTR{md/sync_speed_max}="300000"
EOF
#cat >/etc/udev/rules.d/62-hdparm.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/hdparm -B 254 /dev/%k"
EOF
#cat >/etc/udev/rules.d/63-blockdev.rules << EOF
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", RUN+="/sbin/blockdev --setra 1024 /dev/%k"
SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="md*", RUN+="/sbin/blockdev --setra 0 /dev/%k"
EOF

මොකක්ද ඒ..?අපි පහත සඳහන් දේ කරන udev නීති මාලාවක් සාදා ඇත:

  • RAID 2020 සඳහා බ්ලොක් හැඹිලි ප්‍රමාණය 6 සඳහා ප්‍රමාණවත් වන ලෙස සකසන්න. පෙරනිමි අගය, ලිනක්ස් නිර්මාණය කිරීමෙන් පසු වෙනස් වී නැති අතර දිගු කාලයක් ප්‍රමාණවත් නොවී ඇති බව පෙනේ.
  • අරා චෙක්පත්/සමමුහුර්ත කිරීමේ කාලසීමාව සඳහා අවම වශයෙන් IO වෙන්කරවා ගන්න. මෙය ඔබගේ අරා පැටවීම යටතේ සදාකාලික සමමුහුර්ත තත්වයක සිරවීම වැළැක්වීමයි.
  • චෙක්පත්/අරා සමමුහුර්ත කිරීමේදී උපරිම IO සීමා කරන්න. SSD RAID සමමුහුර්ත කිරීම/පරීක්ෂා කිරීම ඔබගේ ධාවකයන් හැපෙනසුළු බවට පත් නොකිරීමට මෙය අවශ්‍ය වේ. මෙය විශේෂයෙන්ම NVMe සඳහා සත්‍ය වේ. (රේඩියේටරය ගැන මතකද? මම විහිළුවක් කළේ නැහැ.)
  • තැටි APM හරහා ස්පින්ඩල් භ්‍රමණය (HDD) නැවැත්වීම තහනම් කිරීම සහ තැටි පාලක සඳහා නින්දේ කාල සීමාව පැය 7 දක්වා සකසන්න. ඔබගේ ධාවකයන්ට එය කළ හැකි නම් ඔබට APM සම්පූර්ණයෙන්ම අක්‍රිය කළ හැක (-B 255). පෙරනිමි අගය සමඟ, ධාවකයන් තත්පර පහකට පසුව නතර වේ. එවිට OS හට තැටි හැඹිලිය නැවත සැකසීමට අවශ්‍ය වේ, තැටි නැවත කැරකෙනු ඇත, සහ සියල්ල නැවත ආරම්භ වනු ඇත. තැටි වල සීමිත උපරිම ස්පින්ඩල් භ්‍රමණ සංඛ්‍යාවක් ඇත. එවැනි සරල පෙරනිමි චක්‍රයක් වසර කිහිපයකින් ඔබේ තැටි පහසුවෙන් විනාශ කළ හැකිය. සියලුම තැටි මෙයින් පීඩා විඳින්නේ නැත, නමුත් අපගේ ඒවා “ලැප්ටොප්” ඒවා වන අතර සුදුසු පෙරනිමි සැකසුම් ඇති අතර එමඟින් RAID කුඩා MAID එකක් ලෙස පෙනේ.
  • තැටි මත කියවීමට පෙර ස්ථාපනය කරන්න (භ්‍රමණය වන) මෙගාබයිට් 1ක් - අඛණ්ඩ බ්ලොක් දෙකක්/කුට්ටියක් RAID 6
  • අරා මතම කියවීම අබල කරන්න.

අපි /etc/fstab සංස්කරණය කරමු:

#cat >/etc/fstab << EOF
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
# file-system mount-point type options dump pass
/dev/mapper/root-root / btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@ 0 1
UUID=$(blkid -o value -s UUID /dev/md1) /boot btrfs defaults,space_cache,noatime,nodiratime,discard 0 2
/dev/mapper/root-root /home btrfs defaults,space_cache,noatime,nodiratime,discard,subvol=@home 0 2
/dev/mapper/root-swap none swap sw 0 0
EOF

ඇයි ඒ..?අපි UUID මගින් /boot කොටස සොයන්නෙමු. අරාව නම් කිරීම න්‍යායාත්මකව වෙනස් විය හැක.

අපි /dev/mapper/vg-lv අංකනය තුළ LVM නම් වලින් ඉතිරි කොටස් සොයන්නෙමු, මන්ද ඔවුන් ඉතා සුවිශේෂී ලෙස කොටස් හඳුනා ගනී.

අපි LVM සඳහා UUID භාවිතා නොකරන්නේ මන්ද LVM වෙළුම් වල UUID සහ ඒවායේ ස්නැප්ෂොට් එක සමාන විය හැක.Mount /dev/mapper/root-root.. දෙවරක්?ඔව්. හරියටම. BTRFS හි විශේෂාංගය. මෙම ගොනු පද්ධතිය විවිධ subvols සමඟ කිහිප වතාවක් සවි කළ හැක.

මෙම විශේෂාංගය නිසාම, සක්‍රිය BTRFS වෙළුම් වල LVM ස්නැප්ෂොට් කිසිවිටෙක නිර්මාණය නොකරන ලෙස මම නිර්දේශ කරමි. ඔබ නැවත ආරම්භ කරන විට ඔබට පුදුමයක් ඇති විය හැක.

අපි mdadm වින්‍යාසය නැවත උත්පාදනය කරමු:

#/usr/share/mdadm/mkconf | sed 's/#DEVICE/DEVICE/g' >/etc/mdadm/mdadm.conf

අපි LVM සැකසුම් සකස් කරමු:

#cat >>/etc/lvm/lvmlocal.conf << EOF

activation {
thin_pool_autoextend_threshold=90
thin_pool_autoextend_percent=5
}
allocation {
cache_pool_max_chunks=2097152
}
devices {
global_filter=["r|^/dev/.*_corig$|","r|^/dev/.*_cdata$|","r|^/dev/.*_cmeta$|","r|^/dev/.*gpv$|","r|^/dev/images/.*$|","r|^/dev/mapper/images.*$|","r|^/dev/backup/.*$|","r|^/dev/mapper/backup.*$|"] issue_discards=1
}
EOF

මොකක්ද ඒ..?අපි අල්ලාගෙන සිටින ඉඩෙන් 90% කට පරිමාවෙන් 5% ට ළඟා වූ පසු LVM තුනී තටාක ස්වයංක්‍රීයව පුළුල් කිරීම සබල කර ඇත.

අපි LVM හැඹිලි සඳහා උපරිම කෑෂ් බ්ලොක් ගණන වැඩි කර ඇත.

LVM වෙළුම් (PV) සෙවීමෙන් අපි LVM වලක්වා ඇත:

  • LVM හැඹිලි (cdata) අඩංගු උපාංග
  • LVM හැඹිලිය භාවිතයෙන් හැඹිලිගත කරන ලද උපාංග, හැඹිලිය මග හරිමින් ( _කොරිග්). මෙම අවස්ථාවේදී, හැඹිලිගත උපාංගය තවමත් හැඹිලිය හරහා පරිලෝකනය කරනු ලැබේ (හුදෙක් )
  • LVM හැඹිලි පාරදත්ත (cmeta) අඩංගු උපාංග
  • නාම රූප සහිත VG හි ඇති සියලුම උපාංග. මෙහිදී අපට අතථ්‍ය යන්ත්‍රවල තැටි රූප ඇති අතර, ආගන්තුක මෙහෙයුම් පද්ධතියට අයත් වෙළුම් සක්‍රිය කිරීමට ධාරකයේ LVM අපට අවශ්‍ය නොවේ.
  • උපස්ථ නාමය සහිත VG හි සියලුම උපාංග. මෙහිදී අපට අතථ්‍ය යන්ත්‍ර රූපවල උපස්ථ පිටපත් ලැබෙනු ඇත.
  • "gpv" (ආගන්තුක භෞතික පරිමාව) සමඟ නම අවසන් වන සියලුම උපාංග

අපි LVM VG හි නිදහස් ඉඩ නිදහස් කරන විට ඉවතලන සහාය සබල කර ඇත. ප්රවේසම් වන්න. මෙය SSD මත LVs මකා දැමීම සෑහෙන කාලයක් ගත කරයි. මෙය විශේෂයෙන්ම SSD RAID 6 සඳහා අදාළ වේ. කෙසේ වෙතත්, සැලැස්මට අනුව, අපි සිහින් ප්රතිපාදන භාවිතා කරනු ඇත, එබැවින් මෙය අපට කිසිසේත් බාධාවක් නොවනු ඇත.

අපි initramfs රූපය යාවත්කාලීන කරමු:

#update-initramfs -u -k all

grub ස්ථාපනය කර වින්‍යාස කරන්න:

#apt-get install grub-pc
#apt-get purge os-prober
#dpkg-reconfigure grub-pc

තෝරා ගැනීමට කුමන තැටිද?sd* සිටින සියල්ලන්. පද්ධතියට ඕනෑම වැඩ කරන SATA ධාවකයකින් හෝ SSD වෙතින් ආරම්භ කිරීමට හැකි විය යුතුය.

ඇයි os-prober දැම්මේ..?අධික ස්වාධීනත්වය සහ සෙල්ලක්කාර අත් සඳහා.

RAID වලින් එකක් පිරිහුණු තත්වයක තිබේ නම් එය නිවැරදිව ක්‍රියා නොකරයි. එය මෙම දෘඪාංගයේ ක්‍රියාත්මක වන අතථ්‍ය යන්ත්‍රවල භාවිතා කරන කොටස් මත OS සෙවීමට උත්සාහ කරයි.

ඔබට එය අවශ්ය නම්, ඔබට එය අත්හැරිය හැකිය, නමුත් ඉහත සියල්ල මතක තබා ගන්න. අන්තර්ජාලය හරහා නපුරු අත් ඉවත් කිරීම සඳහා වට්ටෝරු සෙවීමට මම නිර්දේශ කරමි.

මේ සමඟ අපි මූලික ස්ථාපනය සම්පූර්ණ කර ඇත. අලුතින් ස්ථාපනය කර ඇති OS වෙත නැවත ආරම්භ කිරීමට කාලයයි. ආරම්භ කළ හැකි සජීවී CD/USB ඉවත් කිරීමට අමතක නොකරන්න.

#exit
#reboot

ඇරඹුම් උපාංගය ලෙස SATA SSD වලින් ඕනෑම එකක් තෝරන්න.

SATA SSD මත LVM

මෙම අවස්ථාවේදී, අපි දැනටමත් නව OS වෙත ආරම්භ කර, ජාලය වින්‍යාස කර, සුදුසු, ටර්මිනල් ඉමුලේටරය විවෘත කර දියත් කර ඇත:

#sudo bash

අපි දිගටම කරගෙන යමු.

SATA SSD වෙතින් අරාව "ආරම්භ කරන්න":

#blkdiscard /dev/md2

එය ක්‍රියා නොකරන්නේ නම්, උත්සාහ කරන්න:

#blkdiscard --step 65536 /dev/md2
SATA SSD මත LVM VG සාදන්න:

#pvcreate /dev/md2
#vgcreate data /dev/md2

ඇයි තව VG..?ඇත්ත වශයෙන්ම, අපි දැනටමත් root නමින් VG ඇත. ඇයි හැම දෙයක්ම එක VG එකට එකතු නොකරන්නේ?

VG එකක PV කිහිපයක් තිබේ නම්, VG නිවැරදිව ක්‍රියාත්මක වීමට නම්, සියලුම PVs තිබිය යුතුය (මාර්ගගතව). ව්යතිරේකය LVM RAID වේ, එය අප හිතාමතාම භාවිතා නොකරයි.

අපට ඇත්තටම අවශ්‍ය වන්නේ කිසියම් RAID 6 අරාවක අසමත් වීමක් (දත්ත අලාභයක් කියවන්න) නම්, මෙහෙයුම් පද්ධතිය සාමාන්‍යයෙන් ආරම්භ වී ගැටළුව විසඳීමට අපට අවස්ථාව ලබා දීමයි.

මෙය සිදු කිරීම සඳහා, වියුක්ත කිරීමේ පළමු මට්ටමේ දී අපි එක් එක් වර්ගයේ භෞතික "මාධ්ය" වෙනම VG බවට හුදකලා කරන්නෙමු.

විද්‍යාත්මකව කිවහොත්, විවිධ RAID අරා විවිධ "විශ්වසනීය වසම්" වලට අයත් වේ. ඔවුන් එක් VG එකකට තද කිරීමෙන් ඔබ ඔවුන් සඳහා අතිරේක පොදු අසාර්ථකත්වයක් ඇති නොකළ යුතුය.

"දෘඪාංග" මට්ටමේ LVM තිබීම විවිධ RAID අරා විවිධ ආකාරවලින් ඒකාබද්ධ කිරීමෙන් අත්තනෝමතික ලෙස කෑලි කපා ගැනීමට අපට ඉඩ සලසයි. උදාහරණයක් ලෙස - ධාවනය කරන්න ඒ සමගම bcache + LVM තුනී, bcache + BTRFS, LVM හැඹිලි + LVM තුනී, හැඹිලි සහිත සංකීර්ණ ZFS වින්‍යාසය, හෝ ඒ සියල්ල සැසඳීමට උත්සාහ කිරීමට වෙනත් අපාය මිශ්‍රණයක්.

"දෘඪාංග" මට්ටමින්, අපි හොඳ පැරණි "ඝන" LVM වෙළුම් හැර වෙනත් කිසිවක් භාවිතා නොකරමු. මෙම රීතියට ව්යතිරේකය උපස්ථ කොටස විය හැකිය.

මම හිතන්නේ මේ මොහොත වන විට, බොහෝ පාඨකයන් දැනටමත් කූඩු බෝනික්කා ගැන යමක් සැක කිරීමට පටන් ගෙන ඇත.

SATA HDD මත LVM

#pvcreate /dev/md3
#vgcreate backup /dev/md3

ආයෙත් අලුත් VG..?දත්ත උපස්ථ කිරීම සඳහා අප භාවිතා කරන තැටි අරාව අසමත් වුවහොත්, අපගේ මෙහෙයුම් පද්ධතිය සාමාන්‍ය පරිදි උපස්ථ නොවන දත්ත වෙත ප්‍රවේශය පවත්වා ගනිමින් සාමාන්‍ය පරිදි ක්‍රියා කරයි. එබැවින්, VG සක්රිය කිරීමේ ගැටළු මඟහරවා ගැනීම සඳහා, අපි වෙනම VG නිර්මාණය කරමු.

LVM හැඹිලිය පිහිටුවීම

එය හැඹිලි උපාංගයක් ලෙස භාවිතා කිරීමට NVMe RAID 1 මත LV එකක් නිර්මාණය කරමු.

#lvcreate -L 70871154688B --name cache root

ඇයි ඔච්චර පොඩිද...?කාරණය වන්නේ අපගේ NVMe SSD වලද SLC හැඹිලියක් තිබීමයි. "නිදහස්" ගිගාබයිට් 4 ක් සහ ගිගාබයිට් 18 ක ගතිකයක් 3-bit MLC හි ඇති නිදහස් ඉඩ නිසා. මෙම හැඹිලිය අවසන් වූ පසු, NVMe SSD හැඹිලි සහිත අපගේ SATA SSD වඩා වේගවත් නොවනු ඇත. ඇත්ත වශයෙන්ම, මෙම හේතුව නිසා, අපට LVM හැඹිලි කොටස NVMe ධාවකයේ SLC හැඹිලියේ ප්‍රමාණය මෙන් දෙගුණයකට වඩා විශාල කිරීම තේරුමක් නැත. භාවිතා කරන NVMe ධාවක සඳහා, කතුවරයා ගිගාබයිට් 32-64 හැඹිලි සෑදීම සාධාරණ ලෙස සලකයි.

ගිගාබයිට් 64ක හැඹිලි, හැඹිලි පාරදත්ත සහ පාර-දත්ත උපස්ථය සංවිධානය කිරීමට ලබා දී ඇති කොටස් ප්‍රමාණය අවශ්‍ය වේ.

මීට අමතරව, අපිරිසිදු පද්ධතිය වසා දැමීමෙන් පසුව, LVM විසින් සම්පූර්ණ හැඹිලිය අපිරිසිදු ලෙස සලකුණු කර නැවත සමමුහුර්ත කරන බව මම සටහන් කරමි. එපමනක් නොව, පද්ධතිය නැවත පණගන්වන තෙක් මෙම උපාංගයේ lvchange භාවිතා කරන සෑම අවස්ථාවකම මෙය නැවත නැවතත් සිදු වේ. එබැවින්, සුදුසු ස්ක්‍රිප්ට් භාවිතයෙන් හැඹිලිය වහාම ප්‍රතිනිර්මාණය කරන ලෙස මම නිර්දේශ කරමි.

එය හැඹිලිගත උපාංගයක් ලෙස භාවිතා කිරීමට SATA RAID 6 මත LV එකක් නිර්මාණය කරමු.

#lvcreate -L 3298543271936B --name cache data

ඇයි ටෙරාබයිට් තුනක් විතරක්..?එබැවින්, අවශ්‍ය නම්, ඔබට වෙනත් අවශ්‍යතා සඳහා SATA SSD RAID 6 භාවිතා කළ හැකිය. පද්ධතිය නතර නොකර පියාසර කරන විට හැඹිලිගත අවකාශයේ ප්‍රමාණය ගතිකව වැඩි කළ හැක. මෙය සිදු කිරීම සඳහා, ඔබට හැඹිලිය තාවකාලිකව නතර කර නැවත සක්‍රිය කළ යුතුය, නමුත් LVM-හැඹිලියේ ඇති සුවිශේෂී වාසිය නම්, උදාහරණයක් ලෙස, bcache මෙය පියාසර කළ හැකි වීමයි.

හැඹිලි කිරීම සඳහා නව VG එකක් නිර්මාණය කරමු.

#pvcreate /dev/root/cache
#pvcreate /dev/data/cache
#vgcreate cache /dev/root/cache /dev/data/cache

හැඹිලිගත උපාංගය මත LV නිර්මාණය කරමු.

#lvcreate -L 3298539077632B --name cachedata cache /dev/data/cache

මෙහිදී අපි වහාම /dev/data/cache හි ඇති සියලුම නිදහස් ඉඩ ලබා ගත්තෙමු, එවිට අවශ්‍ය අනෙකුත් සියලුම කොටස් වහාම /dev/root/cache මත නිර්මාණය විය. ඔබ වැරදි ස්ථානයක යමක් නිර්මාණය කර ඇත්නම්, ඔබට එය pvmove භාවිතයෙන් ගෙන යා හැක.

අපි හැඹිලිය සාදා සක්රිය කරමු:

#lvcreate -y -L 64G -n cache cache /dev/root/cache
#lvcreate -y -L 1G -n cachemeta cache /dev/root/cache
#lvconvert -y --type cache-pool --cachemode writeback --chunksize 64k --poolmetadata cache/cachemeta cache/cache
#lvconvert -y --type cache --cachepool cache/cache cache/cachedata

ඇයි මේ වගේ කුට්ටි..?ප්‍රායෝගික අත්හදා බැලීම් හරහා, LVM හැඹිලි බ්ලොක් එකේ ප්‍රමාණය LVM තුනී බ්ලොක් එකේ ප්‍රමාණයට සමපාත වුවහොත් හොඳම ප්‍රතිඵලය ලබා ගත හැකි බව සොයා ගැනීමට කතුවරයාට හැකි විය. එපමනක් නොව, කුඩා ප්රමාණය, වඩා හොඳ වින්යාසය සසම්භාවී පටිගත කිරීමක් සිදු කරයි.

64k යනු LVM තුනී සඳහා අවසර දී ඇති අවම බ්ලොක් ප්‍රමාණයයි.

පරිස්සමෙන් ලියන්න..!ඔව්. මෙම වර්ගයේ හැඹිලිය හැඹිලිගත උපාංගයට ලිවීමේ සමමුහුර්තකරණය ප්‍රමාද කරයි. මෙයින් අදහස් කරන්නේ හැඹිලිය නැති වුවහොත්, ඔබට හැඹිලිගත උපාංගයේ දත්ත අහිමි විය හැකි බවයි. පසුව, මෙම අවදානම සඳහා වන්දි ගෙවීමට NVMe RAID 1 ට අමතරව ගත හැකි ක්‍රියාමාර්ග මොනවාදැයි කතුවරයා ඔබට කියනු ඇත.

RAID 6 හි දුර්වල අහඹු ලිවීමේ කාර්ය සාධනය සඳහා වන්දි ගෙවීම සඳහා මෙම හැඹිලි වර්ගය හිතාමතාම තෝරා ගන්නා ලදී.

අපට ලැබුණු දේ පරීක්ෂා කර බලමු:

#lvs -a -o lv_name,lv_size,devices --units B cache
LV LSize Devices
[cache] 68719476736B cache_cdata(0)
[cache_cdata] 68719476736B /dev/root/cache(0)
[cache_cmeta] 1073741824B /dev/root/cache(16384)
cachedata 3298539077632B cachedata_corig(0)
[cachedata_corig] 3298539077632B /dev/data/cache(0)
[lvol0_pmspare] 1073741824B /dev/root/cache(16640)

/dev/data/cache මත පිහිටා තිබිය යුත්තේ [cachedata_corig] පමණි. යමක් වැරදී ඇත්නම්, pvmove භාවිතා කරන්න.

ඔබට එක් විධානයකින් අවශ්‍ය නම් හැඹිලිය අක්‍රිය කළ හැකිය:

#lvconvert -y --uncache cache/cachedata

මෙය මාර්ගගතව සිදු කෙරේ. LVM විසින් හැඹිලිය තැටියට සමමුහුර්ත කර, එය ඉවත් කර, cachedata_corig නැවත හැඹිලි දත්ත ලෙස නම් කරනු ඇත.

LVM තුනී සකසමින්

LVM තුනී පාරදත්ත සඳහා අපට අවශ්‍ය ඉඩ ප්‍රමාණය දළ වශයෙන් තක්සේරු කරමු:

#thin_metadata_size --block-size=64k --pool-size=6terabytes --max-thins=100000 -u bytes
thin_metadata_size - 3385794560 bytes estimated metadata area size for "--block-size=64kibibytes --pool-size=6terabytes --max-thins=100000"

ගිගාබයිට් 4 දක්වා වටය: 4294967296B

LVM PV පාරදත්ත සඳහා දෙකකින් ගුණ කර 4194304B එකතු කරන්න: 8594128896B
LVM තුනී පාරදත්ත සහ ඒවායේ උපස්ථ පිටපත තැබීමට NVMe RAID 1 හි වෙනම කොටසක් සාදන්න:

#lvcreate -L 8594128896B --name images root

කුමක් සඳහා ද..?මෙහිදී ප්‍රශ්නය මතු විය හැක: LVM තුනී පාරදත්ත තවමත් NVMe මත හැඹිලිගත වී ඉක්මනින් ක්‍රියා කරන්නේ නම් එය වෙන වෙනම තබන්නේ ඇයි?

මෙහි වේගය වැදගත් වුවද එය ප්‍රධාන හේතුවට වඩා බොහෝ දුරස් වේ. කාරණය නම් හැඹිලිය අසාර්ථක වීමේ ලක්ෂ්‍යයකි. එයට යමක් සිදු විය හැකි අතර, LVM තුනී පාරදත්ත හැඹිලිගත කර ඇත්නම්, එය සියල්ල සම්පූර්ණයෙන්ම නැති වීමට හේතු වේ. සම්පූර්ණ පාර-දත්ත නොමැතිව, තුනී වෙළුම් එකලස් කිරීම පාහේ කළ නොහැක්කකි.

පාර-දත්ත වෙනම හැඹිලිගත නොවන නමුත් වේගවත් පරිමාවකට ගෙන යාමෙන්, හැඹිලි නැතිවීම හෝ දූෂණය වීමකදී පාර-දත්තවල ආරක්ෂාව අපි සහතික කරමු. මෙම අවස්ථාවෙහිදී, හැඹිලි අලාභයෙන් සිදුවන සියලුම හානිය තුනී පරිමාවන් තුළ ස්ථානගත කරනු ලැබේ, එමඟින් විශාලත්වයේ ඇණවුම් මගින් ප්‍රතිසාධන ක්‍රියාවලිය සරල කරනු ඇත. ඉහළ සම්භාවිතාවක් සහිතව, මෙම හානි FS ලඝු-සටහන් භාවිතයෙන් ප්‍රතිසාධනය කරනු ලැබේ.

තවද, මීට පෙර තුනී පරිමාවක ඡායාරූපයක් ගෙන තිබේ නම්, පසුව හැඹිලිය අවම වශයෙන් එක් වරක් සම්පූර්ණයෙන් සමමුහුර්ත කර ඇත්නම්, එවිට, LVM තුනී අභ්‍යන්තර සැලසුම හේතුවෙන්, හැඹිලි නැතිවීමකදී ස්නැප්ෂොට් එකේ අඛණ්ඩතාව සහතික කෙරේ. .

තුනී ප්‍රතිපාදන සඳහා වගකිව යුතු නව VG එකක් නිර්මාණය කරමු:

#pvcreate /dev/root/images
#pvcreate /dev/cache/cachedata
#vgcreate images /dev/root/images /dev/cache/cachedata

අපි තටාකයක් නිර්මාණය කරමු:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T images/thin-pool
ඇයි -Z වයිමෙම මාදිලිය ඇත්ත වශයෙන්ම අදහස් කරන දෙයට අමතරව - අවකාශය නැවත බෙදා හැරීමේදී එක් අතථ්‍ය යන්ත්‍රයකින් දත්ත වෙනත් අතථ්‍ය යන්ත්‍රයකට කාන්දු වීම වැළැක්වීමට - 64k ට වඩා කුඩා කොටස්වල අහඹු ලිවීමේ වේගය වැඩි කිරීමට ශුන්‍ය කිරීම අතිරේකව භාවිතා වේ. සිහින් පරිමාවේ කලින් වෙන් නොකළ ප්‍රදේශයකට 64k ට වඩා අඩු ඕනෑම ලිවීමක් හැඹිලිය තුළ 64K දාර-පෙළගැසී ඇත. මෙය හැඹිලිගත උපාංගය මග හරිමින්, හැඹිලිය හරහා සම්පූර්ණයෙන්ම මෙහෙයුම සිදු කිරීමට ඉඩ සලසයි.

අපි LVs අනුරූප PVs වෙත ගෙන යමු:

#pvmove -n images/thin-pool_tdata /dev/root/images /dev/cache/cachedata
#pvmove -n images/lvol0_pmspare /dev/cache/cachedata /dev/root/images
#pvmove -n images/thin-pool_tmeta /dev/cache/cachedata /dev/root/images

අපි පරීක්ෂා කරමු:

#lvs -a -o lv_name,lv_size,devices --units B images
LV LSize Devices
[lvol0_pmspare] 4294967296B /dev/root/images(0)
thin-pool 274877906944B thin-pool_tdata(0)
[thin-pool_tdata] 274877906944B /dev/cache/cachedata(0)
[thin-pool_tmeta] 4294967296B /dev/root/images(1024)

පරීක්ෂණ සඳහා තුනී පරිමාවක් නිර්මාණය කරමු:

#lvcreate -V 64G --thin-pool thin-pool --name test images

පරීක්ෂණ සහ අධීක්ෂණය සඳහා අපි පැකේජ ස්ථාපනය කරන්නෙමු:

#apt-get install sysstat fio

ඔබට අපගේ ගබඩා වින්‍යාසයේ හැසිරීම තත්‍ය කාලීනව නිරීක්ෂණය කළ හැකි ආකාරය මෙයයි:

#watch 'lvs --rows --reportformat basic --quiet -ocache_dirty_blocks,cache_settings cache/cachedata && (lvdisplay cache/cachedata | grep Cache) && (sar -p -d 2 1 | grep -E "sd|nvme|DEV|md1|md2|md3|md0" | grep -v Average | sort)'

අපට අපගේ වින්‍යාසය පරීක්ෂා කළ හැකි ආකාරය මෙයයි:

#fio --loops=1 --size=64G --runtime=4 --filename=/dev/images/test --stonewall --ioengine=libaio --direct=1
--name=4kQD32read --bs=4k --iodepth=32 --rw=randread
--name=8kQD32read --bs=8k --iodepth=32 --rw=randread
--name=16kQD32read --bs=16k --iodepth=32 --rw=randread
--name=32KQD32read --bs=32k --iodepth=32 --rw=randread
--name=64KQD32read --bs=64k --iodepth=32 --rw=randread
--name=128KQD32read --bs=128k --iodepth=32 --rw=randread
--name=256KQD32read --bs=256k --iodepth=32 --rw=randread
--name=512KQD32read --bs=512k --iodepth=32 --rw=randread
--name=4Kread --bs=4k --rw=read
--name=8Kread --bs=8k --rw=read
--name=16Kread --bs=16k --rw=read
--name=32Kread --bs=32k --rw=read
--name=64Kread --bs=64k --rw=read
--name=128Kread --bs=128k --rw=read
--name=256Kread --bs=256k --rw=read
--name=512Kread --bs=512k --rw=read
--name=Seqread --bs=1m --rw=read
--name=Longread --bs=8m --rw=read
--name=Longwrite --bs=8m --rw=write
--name=Seqwrite --bs=1m --rw=write
--name=512Kwrite --bs=512k --rw=write
--name=256write --bs=256k --rw=write
--name=128write --bs=128k --rw=write
--name=64write --bs=64k --rw=write
--name=32write --bs=32k --rw=write
--name=16write --bs=16k --rw=write
--name=8write --bs=8k --rw=write
--name=4write --bs=4k --rw=write
--name=512KQD32write --bs=512k --iodepth=32 --rw=randwrite
--name=256KQD32write --bs=256k --iodepth=32 --rw=randwrite
--name=128KQD32write --bs=128k --iodepth=32 --rw=randwrite
--name=64KQD32write --bs=64k --iodepth=32 --rw=randwrite
--name=32KQD32write --bs=32k --iodepth=32 --rw=randwrite
--name=16KQD32write --bs=16k --iodepth=32 --rw=randwrite
--name=8KQD32write --bs=8k --iodepth=32 --rw=randwrite
--name=4kQD32write --bs=4k --iodepth=32 --rw=randwrite
| grep -E 'read|write|test' | grep -v ioengine

පරිස්සමෙන්! සම්පත්!මෙම කේතය විවිධ පරීක්ෂණ 36ක් ක්‍රියාත්මක කරනු ඇත, සෑම එකක්ම තත්පර 4ක් ක්‍රියාත්මක වේ. පරීක්ෂණවලින් අඩක් පටිගත කිරීම සඳහා වේ. ඔබට තත්පර 4 කින් NVMe හි බොහෝ දේ පටිගත කළ හැකිය. තත්පරයකට ගිගාබයිට් 3ක් දක්වා. එබැවින්, සෑම ලිඛිත පරීක්ෂණයකටම ඔබෙන් SSD සම්පත ගිගාබයිට් 216 ක් දක්වා ආහාරයට ගත හැකිය.

කියවීම සහ ලිවීම මිශ්‍රද?ඔව්. කියවීමේ සහ ලිවීමේ පරීක්ෂණ වෙන වෙනම ධාවනය කිරීම අර්ථවත් කරයි. එපමණක් නොව, කලින් සාදන ලද ලිවීමක් කියවීමට බලපාන්නේ නැති පරිදි සියලුම හැඹිලි සමමුහුර්ත කර ඇති බව සහතික කිරීම අර්ථවත් කරයි.

පළමු දියත් කිරීමේදී ප්‍රතිඵල බොහෝ සෙයින් වෙනස් වනු ඇත, පසුව හැඹිලිය සහ තුනී පරිමාව පිරෙන විට, සහ අවසාන දියත් කිරීමේදී පිරවූ හැඹිලි සමමුහුර්ත කිරීමට පද්ධතිය සමත් වූයේද යන්න මත පදනම්ව.

වෙනත් දේ අතර, ස්නැප්ෂොට් එකක් ගත් දැනටමත් සම්පූර්ණ තුනී පරිමාවකින් වේගය මැනීමට මම නිර්දේශ කරමි. විශේෂයෙන්ම හැඹිලිය තවමත් සම්පූර්ණයෙන් පිරී නොමැති විට, පළමු ස්නැප්ෂොට් නිර්මාණය කළ වහාම අහඹු ලිවීම් තියුනු ලෙස වේගවත් වන ආකාරය නිරීක්ෂණය කිරීමට කතුවරයාට අවස්ථාව ලැබුණි. මෙය සිදුවන්නේ කොපි-ඔන්-රයිට් රයිට් සෙමෙන්ටික්ස්, හැඹිලි පෙළගැස්ම සහ තුනී පරිමා බ්ලොක්, සහ RAID 6 වෙත අහඹු ලෙස ලිවීමක් RAID 6 වෙතින් අහඹු ලෙස කියවීමක් බවට පත් වීම සහ පසුව හැඹිලියට ලිවීම හේතුවෙනි. අපගේ වින්‍යාසය තුළ, RAID 6 වෙතින් අහඹු කියවීම ලිවීමට වඩා 6 ගුණයක් (අරාවේ SATA SSD ගණන) වේගවත් වේ. නිසා CW සඳහා කුට්ටි තුනී තටාකයකින් අනුක්‍රමිකව වෙන් කරනු ලැබේ, පසුව පටිගත කිරීම බොහෝ දුරට අනුක්‍රමික බවට පත්වේ.

මෙම විශේෂාංග දෙකම ඔබේ වාසිය සඳහා භාවිතා කළ හැකිය.

හැඹිලි "සමාහිත" ස්නැප්ෂොට්

හැඹිලි හානි/අලාභයකදී දත්ත නැතිවීමේ අවදානම අවම කිරීම සඳහා, මෙම අවස්ථාවෙහිදී ඒවායේ අඛණ්ඩතාව සහතික කිරීම සඳහා ස්නැප්ෂොට් භ්‍රමණය කිරීමේ පුරුද්ද හඳුන්වා දීමට කතුවරයා යෝජනා කරයි.

පළමුව, තුනී පරිමා පාර-දත්ත ගබඩා නොකළ උපාංගයක් මත පවතින බැවින්, පාර-දත්ත ස්ථාවර වන අතර දත්ත අවහිර කිරීම් තුළ සිදුවිය හැකි පාඩු හුදකලා වනු ඇත.

පහත ස්නැප්ෂොට් භ්‍රමණ චක්‍රය හැඹිලි නැති වූ විට ස්නැප්ෂොට් ඇතුළත දත්තවල අඛණ්ඩතාව සහතික කරයි:

  1. <name> යන නම සහිත සෑම තුනී වෙළුමක් සඳහාම, <name>.cached යන නම සහිත ස්නැප්ෂොට් එකක් සාදන්න.
  2. සංක්‍රමණ සීමාව සාධාරණ ඉහළ අගයකට සකසමු: #lvchange --quiet --cachesettings "migration_threshold=16384" cache/cachedata
  3. ලූපයේදී අපි හැඹිලියේ ඇති අපිරිසිදු කුට්ටි ගණන පරීක්ෂා කරමු: #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' අපි බිංදුව ලබා ගන්නා තුරු. ශුන්‍යය බොහෝ වේලාවක් අස්ථානගත වී ඇත්නම්, එය තාවකාලිකව හැඹිලිය ලිවීමේ ප්‍රකාරයට මාරු කිරීමෙන් සෑදිය හැක. කෙසේ වෙතත්, අපගේ SATA සහ NVMe SSD අරාවල වේග ලක්ෂණ මෙන්ම ඒවායේ TBW සම්පත සැලකිල්ලට ගනිමින්, ඔබට හැඹිලි මාදිලිය වෙනස් නොකර ඉක්මනින් මොහොත අල්ලා ගැනීමට හැකි වනු ඇත, නැතහොත් ඔබේ දෘඪාංගය එහි සම්පූර්ණ සම්පත සම්පූර්ණයෙන්ම විනාශ කරනු ඇත. දින කිහිපයක්. සම්පත් සීමාවන් හේතුවෙන්, පද්ධතියට, ප්‍රතිපත්තිමය වශයෙන්, 100% ට වඩා අඩුවෙන් ලිවීමට නොහැකි වේ. අපගේ NVMe SSD 100% ට අඩු ලිවීම් භාරය සම්පත සම්පූර්ණයෙන්ම අවසන් කරයි දින 3-4 යි. SATA SSD පවතිනු ඇත්තේ දෙගුණයක් පමණි. එමනිසා, බොහෝ බර කියවීමට යන බව අපි උපකල්පනය කරමු, සහ ලිවීම සඳහා සාමාන්යයෙන් අඩු බරක් සමඟ ඒකාබද්ධව අතිශය ඉහළ ක්රියාකාරිත්වයේ සාපේක්ෂව කෙටි කාලීන පිපිරීම් ඇත.
  4. අපි බිංදුවක් අල්ලා ගත් (හෝ සෑදූ) වහාම, අපි <name>.cached <name>.committed ලෙස නැවත නම් කරමු. පැරණි <name>.committed එක මකා ඇත.
  5. විකල්පයක් ලෙස, හැඹිලිය 100% පිරී තිබේ නම්, එය ස්ක්‍රිප්ට් එකකින් ප්‍රතිනිර්මාණය කළ හැකි අතර එමඟින් එය ඉවත් කළ හැකිය. අර්ධ හිස් හැඹිලියක් සමඟ, පද්ධතිය ලිවීමේදී වඩා වේගයෙන් ක්රියා කරයි.
  6. සංක්‍රමණ සීමාව බිංදුවට සකසන්න: #lvchange --quiet --cachesettings "migration_threshold=0" cache/cachedata මෙමගින් හැඹිලිය ප්‍රධාන මාධ්‍යයට සමමුහුර්ත වීම තාවකාලිකව වලක්වනු ඇත.
  7. හැඹිලියේ බොහෝ වෙනස්කම් එකතු වන තෙක් අපි බලා සිටිමු #lvs --rows --reportformat basic --quiet -ocache_dirty_blocks cache/cachedata | awk '{print $2}' නැතහොත් ටයිමරය ක්‍රියා විරහිත වේ.
  8. අපි නැවත නැවත කියනවා.

සංක්‍රමණ සීමාව සමඟ දුෂ්කරතා ඇයි...?කාරණය වන්නේ සැබෑ ප්රායෝගිකව, "අහඹු" පටිගත කිරීමක් ඇත්ත වශයෙන්ම සම්පූර්ණයෙන්ම අහඹු නොවේ. අපි කිලෝබයිට් 4 ක ප්‍රමාණයේ අංශයකට යමක් ලිව්වොත්, ඊළඟ මිනිත්තු දෙකේදී එම හෝ අසල්වැසි (+- 32K) අංශයකට වාර්තාවක් සෑදීමේ ඉහළ සම්භාවිතාවක් ඇත.

සංක්‍රමණ සීමාව බිංදුවට සැකසීමෙන්, අපි SATA SSD මත ලිවීමේ සමමුහුර්තකරණය කල් දමා හැඹිලියේ එක් 64K බ්ලොක් එකකට වෙනස්කම් කිහිපයක් එකතු කරමු. මෙය SATA SSD හි සම්පත සැලකිය යුතු ලෙස ඉතිරි කරයි.

කෝ කෝඩ් එක..?අවාසනාවකට මෙන්, කතුවරයා තමා 100% ස්වයං-ඉගැන්වූ සහ “ගූගල්” මත පදනම් වූ සංවර්ධනය පුහුණු කරන නිසා ඔහු බාෂ් ස්ක්‍රිප්ට් සංවර්ධනයට ප්‍රමාණවත් තරම් දක්ෂ නොවන බව සලකයි, එබැවින් ඔහුගේ අත්වලින් පිටවන භයානක කේතය කිසිවෙකු විසින් භාවිතා නොකළ යුතු බව ඔහු විශ්වාස කරයි. වෙනත්

මෙම ක්ෂේත්‍රයේ වෘත්තිකයන්ට අවශ්‍ය නම්, ඉහත විස්තර කර ඇති සියලුම තර්ක ස්වාධීනව නිරූපණය කිරීමටත්, සමහර විට, කතුවරයා කිරීමට උත්සාහ කළ පරිදි, එය systemd සේවාවක් ලෙස අලංකාර ලෙස සැලසුම් කිරීමටත් හැකි වනු ඇතැයි මම සිතමි.

එවැනි සරල ස්නැප්ෂොට් භ්‍රමණ යෝජනා ක්‍රමයක් මඟින් අපට SATA SSD හි එක් ඡායාරූපයක් නිරන්තරයෙන් සමමුහුර්ත කිරීමට පමණක් නොව, සිහින්_ඩෙල්ටා උපයෝගීතාව භාවිතා කරමින්, එය නිර්මාණය කිරීමෙන් පසු වෙනස් වූ කුට්ටි මොනවාදැයි සොයා ගැනීමටත්, එමඟින් හානිය ස්ථානගත කිරීමටත් අපට ඉඩ සලසයි. ප්‍රධාන වෙළුම්, ප්‍රතිසාධනය බෙහෙවින් සරල කරයි.

libvirt/KVM හි TRIM/DISCARD

නිසා දත්ත ගබඩාව KVM ධාවනය වන libvirt සඳහා භාවිතා කරනු ඇත, එවිට අපගේ VM වලට නිදහස් ඉඩ ලබා ගැනීමට පමණක් නොව, තවදුරටත් අවශ්‍ය නොවන දේ නිදහස් කිරීමටද ඉගැන්වීම හොඳ අදහසකි.

මෙය සිදු කරනු ලබන්නේ අතථ්‍ය තැටි මත TRIM/DISCARD සහාය අනුකරණය කිරීමෙනි. මෙය සිදු කිරීම සඳහා, ඔබ විසින් පාලක වර්ගය virtio-scsi වෙත වෙනස් කර xml සංස්කරණය කළ යුතුය.

#virsh edit vmname
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='writethrough' io='threads' discard='unmap'/>
<source dev='/dev/images/vmname'/>
<backingStore/>
<target dev='sda' bus='scsi'/>
<alias name='scsi0-0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>

<controller type='scsi' index='0' model='virtio-scsi'>
<alias name='scsi0'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</controller>

ආගන්තුක OS වෙතින් වන එවැනි ඉවතලන LVM මගින් නිවැරදිව සකසන ලද අතර, හැඹිලිය තුළ සහ තුනී සංචිතය තුළ කුට්ටි නිවැරදිව නිදහස් කරනු ලැබේ. අපගේ නඩුවේදී, මෙය ප්‍රධාන වශයෙන් සිදුවන්නේ ප්‍රමාද වූ ආකාරයෙන්, ඊළඟ ස්නැප්ෂොට් එක මකා දැමීමේදීය.

BTRFS උපස්ථය

සමඟ සූදානම් කළ ස්ක්‍රිප්ට් භාවිතා කරන්න අන්ත අවවාදය සහ තමන්ගේම අවදානමකින්. කතුවරයා මෙම කේතය තමා විසින්ම සහ තමාටම පමණක් ලියා ඇත. බොහෝ පළපුරුදු ලිනක්ස් පරිශීලකයින්ට සමාන මෙවලම් ඇති බව මට විශ්වාසයි, වෙනත් කෙනෙකුගේ ඒවා පිටපත් කිරීමට අවශ්ය නැත.

උපස්ථ උපාංගයේ පරිමාවක් නිර්මාණය කරමු:

#lvcreate -L 256G --name backup backup

අපි එය BTRFS වලින් සංයුති කරමු:

#mkfs.btrfs /dev/backup/backup

අපි මවුන්ට් පොයින්ට් සාදා ගොනු පද්ධතියේ මූල උපවගන්ති සවි කරමු:

#mkdir /backup
#mkdir /backup/btrfs
#mkdir /backup/btrfs/root
#mkdir /backup/btrfs/back
#ln -s /boot /backup/btrfs
# cat >>/etc/fstab << EOF

/dev/mapper/root-root /backup/btrfs/root btrfs defaults,space_cache,noatime,nodiratime 0 2
/dev/mapper/backup-backup /backup/btrfs/back btrfs defaults,space_cache,noatime,nodiratime 0 2
EOF
#mount -a
#update-initramfs -u
#update-grub

උපස්ථ සඳහා නාමාවලි සාදන්න:

#mkdir /backup/btrfs/back/remote
#mkdir /backup/btrfs/back/remote/root
#mkdir /backup/btrfs/back/remote/boot

උපස්ථ ස්ක්‍රිප්ට් සඳහා නාමාවලියක් නිර්මාණය කරමු:

#mkdir /root/btrfs-backup

අපි පිටපත පිටපත් කරමු:

බය හිතෙන bash code ගොඩක්. ඔබේම අවදානමකින් භාවිතා කරන්න. කතුවරයාට තරහ යන ලිපි ලියන්න එපා...#cat >/root/btrfs-backup/btrfs-backup.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"

LOCK_FILE="/dev/shm/$SCRIPT_NAME.lock"
DATE_PREFIX='%Y-%m-%d'
DATE_FORMAT=$DATE_PREFIX'-%H-%M-%S'
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
BASE_SUFFIX=".@base"
PEND_SUFFIX=".@pend"
SNAP_SUFFIX=".@snap"
MOUNTS="/backup/btrfs/"
BACKUPS="/backup/btrfs/back/remote/"

function terminate ()
{
echo "$1" >&2
exit 1
}

function wait_lock()
{
flock 98
}

function wait_lock_or_terminate()
{
echo "Wating for lock..."
wait_lock || terminate "Failed to get lock. Exiting..."
echo "Got lock..."
}

function suffix()
{
FORMATTED_DATE=$(date +"$DATE_FORMAT")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function filter()
{
FORMATTED_DATE=$(date --date="$1" +"$DATE_PREFIX")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function backup()
{
SOURCE_PATH="$MOUNTS$1"
TARGET_PATH="$BACKUPS$1"
SOURCE_BASE_PATH="$MOUNTS$1$BASE_SUFFIX"
TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
TARGET_BASE_DIR="$(dirname $TARGET_BASE_PATH)"
SOURCE_PEND_PATH="$MOUNTS$1$PEND_SUFFIX"
TARGET_PEND_PATH="$BACKUPS$1$PEND_SUFFIX"
if [ -d "$SOURCE_BASE_PATH" ] then
echo "$SOURCE_BASE_PATH found"
else
echo "$SOURCE_BASE_PATH File not found creating snapshot of $SOURCE_PATH to $SOURCE_BASE_PATH"
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_BASE_PATH
sync
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found out of sync with source... removing..."
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
fi
fi
if [ -d "$TARGET_BASE_PATH" ] then
echo "$TARGET_BASE_PATH found"
else
echo "$TARGET_BASE_PATH not found. Synching to $TARGET_BASE_DIR"
btrfs send $SOURCE_BASE_PATH | btrfs receive $TARGET_BASE_DIR
sync
fi
if [ -d "$SOURCE_PEND_PATH" ] then
echo "$SOURCE_PEND_PATH found removing..."
btrfs subvolume delete -c $SOURCE_PEND_PATH
sync
fi
btrfs subvolume snapshot -r $SOURCE_PATH $SOURCE_PEND_PATH
sync
if [ -d "$TARGET_PEND_PATH" ] then
echo "$TARGET_PEND_PATH found removing..."
btrfs subvolume delete -c $TARGET_PEND_PATH
sync
fi
echo "Sending $SOURCE_PEND_PATH to $TARGET_PEND_PATH"
btrfs send -p $SOURCE_BASE_PATH $SOURCE_PEND_PATH | btrfs receive $TARGET_BASE_DIR
sync
TARGET_DATE_SUFFIX=$(suffix)
btrfs subvolume snapshot -r $TARGET_PEND_PATH "$TARGET_PATH$TARGET_DATE_SUFFIX"
sync
btrfs subvolume delete -c $SOURCE_BASE_PATH
sync
btrfs subvolume delete -c $TARGET_BASE_PATH
sync
mv $SOURCE_PEND_PATH $SOURCE_BASE_PATH
mv $TARGET_PEND_PATH $TARGET_BASE_PATH
sync
}

function list()
{
LIST_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
LIST_TARGET_BASE_DIR="$(dirname $LIST_TARGET_BASE_PATH)"
LIST_TARGET_BASE_NAME="$(basename -s .$BASE_SUFFIX $LIST_TARGET_BASE_PATH)"
find "$LIST_TARGET_BASE_DIR" -maxdepth 1 -mindepth 1 -type d -printf "%fn" | grep "${LIST_TARGET_BASE_NAME/$BASE_SUFFIX/$SNAP_SUFFIX}.$DATE_REGEX"
}

function remove()
{
REMOVE_TARGET_BASE_PATH="$BACKUPS$1$BASE_SUFFIX"
REMOVE_TARGET_BASE_DIR="$(dirname $REMOVE_TARGET_BASE_PATH)"
btrfs subvolume delete -c $REMOVE_TARGET_BASE_DIR/$2
sync
}

function removeall()
{
DATE_OFFSET="$2"
FILTER="$(filter "$DATE_OFFSET")"
while read -r SNAPSHOT ; do
remove "$1" "$SNAPSHOT"
done < <(list "$1" | grep "$FILTER")

}

(
COMMAND="$1"
shift

case "$COMMAND" in
"--help")
echo "Help"
;;
"suffix")
suffix
;;
"filter")
filter "$1"
;;
"backup")
wait_lock_or_terminate
backup "$1"
;;
"list")
list "$1"
;;
"remove")
wait_lock_or_terminate
remove "$1" "$2"
;;
"removeall")
wait_lock_or_terminate
removeall "$1" "$2"
;;
*)
echo "None.."
;;
esac
) 98>$LOCK_FILE

EOF

ඌ මොකද කරන්නේ..?BTRFS ස්නැප්ෂොට් සෑදීම සහ BTRFS send/recieve භාවිතයෙන් වෙනත් FS වෙත පිටපත් කිරීම සඳහා සරල විධාන මාලාවක් අඩංගු වේ.

පළමු දියත් කිරීම සාපේක්ෂව දිගු විය හැක, මන්ද ... ආරම්භයේ දී, සියලු දත්ත පිටපත් කරනු ලැබේ. තවදුරටත් දියත් කිරීම් ඉතා වේගවත් වනු ඇත, මන්ද... වෙනස්කම් පමණක් පිටපත් කරනු ලැබේ.

අපි ක්‍රෝන් එකට දමන තවත් ස්ක්‍රිප්ට් එකක්:

තව bash code ටිකක්#cat >/root/btrfs-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"

BACKUP_SCRIPT="$SCRIPT_DIR/btrfs-backup.sh"
RETENTION="-60 day"
$BACKUP_SCRIPT backup root/@
$BACKUP_SCRIPT removeall root/@ "$RETENTION"
$BACKUP_SCRIPT backup root/@home
$BACKUP_SCRIPT removeall root/@home "$RETENTION"
$BACKUP_SCRIPT backup boot/
$BACKUP_SCRIPT removeall boot/ "$RETENTION"
EOF

ඒකෙන් මොකද කරන්නේ..?උපස්ථ FS මත ලැයිස්තුගත කර ඇති BTRFS වෙළුම්වල වර්ධක සැණ රූ නිර්මාණය කර සමමුහුර්ත කරයි. මෙයින් පසු, එය දින 60 කට පෙර සාදන ලද සියලුම පින්තූර මකා දමයි. දියත් කිරීමෙන් පසුව, ලැයිස්තුගත කර ඇති වෙළුම් වල දින දර්ශන /backup/btrfs/back/remote/ උප බහලුම්වල දිස්වනු ඇත.

කේතය ක්‍රියාත්මක කිරීමේ අයිතිය ලබා දෙමු:

#chmod +x /root/btrfs-backup/cron-daily.sh
#chmod +x /root/btrfs-backup/btrfs-backup.sh

අපි එය පරීක්ෂා කර එය ක්‍රෝන් එකට දමමු:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup
#cat /var/log/syslog | grep btrfs-backup
#crontab -e
0 2 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/btrfs-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t btrfs-backup

LVM තුනී උපස්ථය

උපස්ථ උපාංගයේ තුනී තටාකයක් නිර්මාණය කරමු:

#lvcreate -L 274877906944B --poolmetadataspare y --poolmetadatasize 4294967296B --chunksize 64k -Z y -T backup/thin-pool

අපි ddrescue ස්ථාපනය කරමු, මන්ද... scripts මෙම මෙවලම භාවිතා කරනු ඇත:

#apt-get install gddrescue

ස්ක්‍රිප්ට් සඳහා නාමාවලියක් නිර්මාණය කරමු:

#mkdir /root/lvm-thin-backup

අපි ස්ක්‍රිප්ට් පිටපත් කරමු:

ඇතුලේ මාර බයක්...#cat >/root/lvm-thin-backup/lvm-thin-backup.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"

LOCK_FILE="/dev/shm/$SCRIPT_NAME.lock"
DATE_PREFIX='%Y-%m-%d'
DATE_FORMAT=$DATE_PREFIX'-%H-%M-%S'
DATE_REGEX='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
BASE_SUFFIX=".base"
PEND_SUFFIX=".pend"
SNAP_SUFFIX=".snap"
BACKUPS="backup"
BACKUPS_POOL="thin-pool"

export LVM_SUPPRESS_FD_WARNINGS=1

function terminate ()
{
echo "$1" >&2
exit 1
}

function wait_lock()
{
flock 98
}

function wait_lock_or_terminate()
{
echo "Wating for lock..."
wait_lock || terminate "Failed to get lock. Exiting..."
echo "Got lock..."
}

function suffix()
{
FORMATTED_DATE=$(date +"$DATE_FORMAT")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function filter()
{
FORMATTED_DATE=$(date --date="$1" +"$DATE_PREFIX")
echo "$SNAP_SUFFIX.$FORMATTED_DATE"
}

function read_thin_id {
lvs --rows --reportformat basic --quiet -othin_id "$1/$2" | awk '{print $2}'
}

function read_pool_lv {
lvs --rows --reportformat basic --quiet -opool_lv "$1/$2" | awk '{print $2}'
}

function read_lv_dm_path {
lvs --rows --reportformat basic --quiet -olv_dm_path "$1/$2" | awk '{print $2}'
}

function read_lv_active {
lvs --rows --reportformat basic --quiet -olv_active "$1/$2" | awk '{print $2}'
}

function read_lv_chunk_size {
lvs --rows --reportformat basic --quiet --units b --nosuffix -ochunk_size "$1/$2" | awk '{print $2}'
}

function read_lv_size {
lvs --rows --reportformat basic --quiet --units b --nosuffix -olv_size "$1/$2" | awk '{print $2}'
}

function activate_volume {
lvchange -ay -Ky "$1/$2"
}

function deactivate_volume {
lvchange -an "$1/$2"
}

function read_thin_metadata_snap {
dmsetup status "$1" | awk '{print $7}'
}

function thindiff()
{
DIFF_VG="$1"
DIFF_SOURCE="$2"
DIFF_TARGET="$3"
DIFF_SOURCE_POOL=$(read_pool_lv $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_POOL=$(read_pool_lv $DIFF_VG $DIFF_TARGET)

if [ "$DIFF_SOURCE_POOL" == "" ] then
(>&2 echo "Source LV is not thin.")
exit 1
fi

if [ "$DIFF_TARGET_POOL" == "" ] then
(>&2 echo "Target LV is not thin.")
exit 1
fi

if [ "$DIFF_SOURCE_POOL" != "$DIFF_TARGET_POOL" ] then
(>&2 echo "Source and target LVs belong to different thin pools.")
exit 1
fi

DIFF_POOL_PATH=$(read_lv_dm_path $DIFF_VG $DIFF_SOURCE_POOL)
DIFF_SOURCE_ID=$(read_thin_id $DIFF_VG $DIFF_SOURCE)
DIFF_TARGET_ID=$(read_thin_id $DIFF_VG $DIFF_TARGET)
DIFF_POOL_PATH_TPOOL="$DIFF_POOL_PATH-tpool"
DIFF_POOL_PATH_TMETA="$DIFF_POOL_PATH"_tmeta
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)

if [ "$DIFF_POOL_METADATA_SNAP" != "-" ] then
(>&2 echo "Thin pool metadata snapshot already exist. Assuming stale one. Will release metadata snapshot in 5 seconds.")
sleep 5
dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap
fi

dmsetup message $DIFF_POOL_PATH_TPOOL 0 reserve_metadata_snap
DIFF_POOL_METADATA_SNAP=$(read_thin_metadata_snap $DIFF_POOL_PATH_TPOOL)

if [ "$DIFF_POOL_METADATA_SNAP" == "-" ] then
(>&2 echo "Failed to create thin pool metadata snapshot.")
exit 1
fi

#We keep output in variable because metadata snapshot need to be released early.
DIFF_DATA=$(thin_delta -m$DIFF_POOL_METADATA_SNAP --snap1 $DIFF_SOURCE_ID --snap2 $DIFF_TARGET_ID $DIFF_POOL_PATH_TMETA)

dmsetup message $DIFF_POOL_PATH_TPOOL 0 release_metadata_snap

echo $"$DIFF_DATA" | grep -E 'different|left_only|right_only' | sed 's/</"/g' | sed 's/ /"/g' | awk -F'"' '{print $6 "t" $8 "t" $11}' | sed 's/different/copy/g' | sed 's/left_only/copy/g' | sed 's/right_only/discard/g'

}

function thinsync()
{
SYNC_VG="$1"
SYNC_PEND="$2"
SYNC_BASE="$3"
SYNC_TARGET="$4"
SYNC_PEND_POOL=$(read_pool_lv $SYNC_VG $SYNC_PEND)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SYNC_VG $SYNC_PEND_POOL)
SYNC_PEND_PATH=$(read_lv_dm_path $SYNC_VG $SYNC_PEND)

activate_volume $SYNC_VG $SYNC_PEND

while read -r SYNC_ACTION SYNC_OFFSET SYNC_LENGTH ; do
SYNC_OFFSET_BYTES=$((SYNC_OFFSET * SYNC_BLOCK_SIZE))
SYNC_LENGTH_BYTES=$((SYNC_LENGTH * SYNC_BLOCK_SIZE))
if [ "$SYNC_ACTION" == "copy" ] then
ddrescue --quiet --force --input-position=$SYNC_OFFSET_BYTES --output-position=$SYNC_OFFSET_BYTES --size=$SYNC_LENGTH_BYTES "$SYNC_PEND_PATH" "$SYNC_TARGET"
fi

if [ "$SYNC_ACTION" == "discard" ] then
blkdiscard -o $SYNC_OFFSET_BYTES -l $SYNC_LENGTH_BYTES "$SYNC_TARGET"
fi
done < <(thindiff "$SYNC_VG" "$SYNC_PEND" "$SYNC_BASE")
}

function discard_volume()
{
DISCARD_VG="$1"
DISCARD_LV="$2"
DISCARD_LV_PATH=$(read_lv_dm_path "$DISCARD_VG" "$DISCARD_LV")
if [ "$DISCARD_LV_PATH" != "" ] then
echo "$DISCARD_LV_PATH found"
else
echo "$DISCARD_LV not found in $DISCARD_VG"
exit 1
fi
DISCARD_LV_POOL=$(read_pool_lv $DISCARD_VG $DISCARD_LV)
DISCARD_LV_SIZE=$(read_lv_size "$DISCARD_VG" "$DISCARD_LV")
lvremove -y --quiet "$DISCARD_LV_PATH" || exit 1
lvcreate --thin-pool "$DISCARD_LV_POOL" -V "$DISCARD_LV_SIZE"B --name "$DISCARD_LV" "$DISCARD_VG" || exit 1
}

function backup()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
SOURCE_PEND_LV="$SOURCE_LV$PEND_SUFFIX"
TARGET_PEND_LV="$TARGET_LV$PEND_SUFFIX"
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
SOURCE_PEND_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_PEND_LV")
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
TARGET_PEND_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_PEND_LV")

if [ "$SOURCE_BASE_LV_PATH" != "" ] then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "Source base not found creating snapshot of $SOURCE_VG/$SOURCE_LV to $SOURCE_VG/$SOURCE_BASE_LV"
lvcreate --quiet --snapshot --name "$SOURCE_BASE_LV" "$SOURCE_VG/$SOURCE_LV" || exit 1
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
echo "Discarding $SOURCE_BASE_LV_PATH as we need to bootstrap."
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
sync
if [ "$TARGET_BASE_LV_PATH" != "" ] then
echo "$TARGET_BASE_LV_PATH found out of sync with source... removing..."
lvremove -y --quiet $TARGET_BASE_LV_PATH || exit 1
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
sync
fi
fi
SOURCE_BASE_SIZE=$(read_lv_size "$SOURCE_VG" "$SOURCE_BASE_LV")
if [ "$TARGET_BASE_LV_PATH" != "" ] then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_VG/$TARGET_LV not found. Creating empty volume."
lvcreate --thin-pool "$BACKUPS_POOL" -V "$SOURCE_BASE_SIZE"B --name "$TARGET_BASE_LV" "$TARGET_VG" || exit 1
echo "Have to rebootstrap. Discarding source at $SOURCE_BASE_LV_PATH"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SOURCE_BASE_CHUNK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)
discard_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
TARGET_BASE_POOL=$(read_pool_lv $TARGET_VG $TARGET_BASE_LV)
TARGET_BASE_CHUNK_SIZE=$(read_lv_chunk_size $TARGET_VG $TARGET_BASE_POOL)
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
echo "Discarding target at $TARGET_BASE_LV_PATH"
discard_volume "$TARGET_VG" "$TARGET_BASE_LV"
sync
fi
if [ "$SOURCE_PEND_LV_PATH" != "" ] then
echo "$SOURCE_PEND_LV_PATH found removing..."
lvremove -y --quiet "$SOURCE_PEND_LV_PATH" || exit 1
sync
fi
lvcreate --quiet --snapshot --name "$SOURCE_PEND_LV" "$SOURCE_VG/$SOURCE_LV" || exit 1
SOURCE_PEND_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_PEND_LV")
sync
if [ "$TARGET_PEND_LV_PATH" != "" ] then
echo "$TARGET_PEND_LV_PATH found removing..."
lvremove -y --quiet $TARGET_PEND_LV_PATH
sync
fi
lvcreate --quiet --snapshot --name "$TARGET_PEND_LV" "$TARGET_VG/$TARGET_BASE_LV" || exit 1
TARGET_PEND_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_PEND_LV")
SOURCE_PEND_LV_SIZE=$(read_lv_size "$SOURCE_VG" "$SOURCE_PEND_LV")
lvresize -L "$SOURCE_PEND_LV_SIZE"B "$TARGET_PEND_LV_PATH"
activate_volume "$TARGET_VG" "$TARGET_PEND_LV"
echo "Synching $SOURCE_PEND_LV_PATH to $TARGET_PEND_LV_PATH"
thinsync "$SOURCE_VG" "$SOURCE_PEND_LV" "$SOURCE_BASE_LV" "$TARGET_PEND_LV_PATH" || exit 1
sync

TARGET_DATE_SUFFIX=$(suffix)
lvcreate --quiet --snapshot --name "$TARGET_LV$TARGET_DATE_SUFFIX" "$TARGET_VG/$TARGET_PEND_LV" || exit 1
sync
lvremove --quiet -y "$SOURCE_BASE_LV_PATH" || exit 1
sync
lvremove --quiet -y "$TARGET_BASE_LV_PATH" || exit 1
sync
lvrename -y "$SOURCE_VG/$SOURCE_PEND_LV" "$SOURCE_BASE_LV" || exit 1
lvrename -y "$TARGET_VG/$TARGET_PEND_LV" "$TARGET_BASE_LV" || exit 1
sync
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}

function verify()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")

if [ "$SOURCE_BASE_LV_PATH" != "" ] then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "$SOURCE_BASE_LV_PATH not found"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ] then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_BASE_LV_PATH not found"
exit 1
fi
activate_volume "$TARGET_VG" "$TARGET_BASE_LV"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
echo Comparing "$SOURCE_BASE_LV_PATH" with "$TARGET_BASE_LV_PATH"
cmp "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
echo Done...
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}

function resync()
{
SOURCE_VG="$1"
SOURCE_LV="$2"
TARGET_VG="$BACKUPS"
TARGET_LV="$SOURCE_VG-$SOURCE_LV"
SOURCE_BASE_LV="$SOURCE_LV$BASE_SUFFIX"
TARGET_BASE_LV="$TARGET_LV$BASE_SUFFIX"
TARGET_BASE_LV_PATH=$(read_lv_dm_path "$TARGET_VG" "$TARGET_BASE_LV")
SOURCE_BASE_LV_PATH=$(read_lv_dm_path "$SOURCE_VG" "$SOURCE_BASE_LV")

if [ "$SOURCE_BASE_LV_PATH" != "" ] then
echo "$SOURCE_BASE_LV_PATH found"
else
echo "$SOURCE_BASE_LV_PATH not found"
exit 1
fi
if [ "$TARGET_BASE_LV_PATH" != "" ] then
echo "$TARGET_BASE_LV_PATH found"
else
echo "$TARGET_BASE_LV_PATH not found"
exit 1
fi
activate_volume "$TARGET_VG" "$TARGET_BASE_LV"
activate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
SOURCE_BASE_POOL=$(read_pool_lv $SOURCE_VG $SOURCE_BASE_LV)
SYNC_BLOCK_SIZE=$(read_lv_chunk_size $SOURCE_VG $SOURCE_BASE_POOL)

echo Syncronizing "$SOURCE_BASE_LV_PATH" to "$TARGET_BASE_LV_PATH"

CMP_OFFSET=0
while [[ "$CMP_OFFSET" != "" ]] ; do
CMP_MISMATCH=$(cmp -i "$CMP_OFFSET" "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH" | grep differ | awk '{print $5}' | sed 's/,//g' )
if [[ "$CMP_MISMATCH" != "" ]] ; then
CMP_OFFSET=$(( CMP_MISMATCH + CMP_OFFSET ))
SYNC_OFFSET_BYTES=$(( ( CMP_OFFSET / SYNC_BLOCK_SIZE ) * SYNC_BLOCK_SIZE ))
SYNC_LENGTH_BYTES=$(( SYNC_BLOCK_SIZE ))
echo "Synching $SYNC_LENGTH_BYTES bytes at $SYNC_OFFSET_BYTES from $SOURCE_BASE_LV_PATH to $TARGET_BASE_LV_PATH"
ddrescue --quiet --force --input-position=$SYNC_OFFSET_BYTES --output-position=$SYNC_OFFSET_BYTES --size=$SYNC_LENGTH_BYTES "$SOURCE_BASE_LV_PATH" "$TARGET_BASE_LV_PATH"
else
CMP_OFFSET=""
fi
done
echo Done...
deactivate_volume "$TARGET_VG" "$TARGET_BASE_LV"
deactivate_volume "$SOURCE_VG" "$SOURCE_BASE_LV"
}

function list()
{
LIST_SOURCE_VG="$1"
LIST_SOURCE_LV="$2"
LIST_TARGET_VG="$BACKUPS"
LIST_TARGET_LV="$LIST_SOURCE_VG-$LIST_SOURCE_LV"
LIST_TARGET_BASE_LV="$LIST_TARGET_LV$SNAP_SUFFIX"
lvs -olv_name | grep "$LIST_TARGET_BASE_LV.$DATE_REGEX"
}

function remove()
{
REMOVE_TARGET_VG="$BACKUPS"
REMOVE_TARGET_LV="$1"
lvremove -y "$REMOVE_TARGET_VG/$REMOVE_TARGET_LV"
sync
}

function removeall()
{
DATE_OFFSET="$3"
FILTER="$(filter "$DATE_OFFSET")"
while read -r SNAPSHOT ; do
remove "$SNAPSHOT"
done < <(list "$1" "$2" | grep "$FILTER")

}

(
COMMAND="$1"
shift

case "$COMMAND" in
"--help")
echo "Help"
;;
"suffix")
suffix
;;
"filter")
filter "$1"
;;
"backup")
wait_lock_or_terminate
backup "$1" "$2"
;;
"list")
list "$1" "$2"
;;
"thindiff")
thindiff "$1" "$2" "$3"
;;
"thinsync")
thinsync "$1" "$2" "$3" "$4"
;;
"verify")
wait_lock_or_terminate
verify "$1" "$2"
;;
"resync")
wait_lock_or_terminate
resync "$1" "$2"
;;
"remove")
wait_lock_or_terminate
remove "$1"
;;
"removeall")
wait_lock_or_terminate
removeall "$1" "$2" "$3"
;;
*)
echo "None.."
;;
esac
) 98>$LOCK_FILE

EOF

ඒකෙන් මොකද කරන්නේ...?තුනී ස්නැප්ෂොට් හැසිරවීම සහ ddrescue සහ blkdiscard භාවිතා කරමින් thin_delta හරහා ලැබෙන තුනී ස්නැප්ෂොට් දෙකක් අතර වෙනස වෙනත් බ්ලොක් උපාංගයකට සමමුහුර්ත කිරීම සඳහා විධාන මාලාවක් අඩංගු වේ.

අපි ක්‍රෝන් එකට දමන තවත් ස්ක්‍රිප්ට් එකක්:

තව ටිකක් බෂ්#cat >/root/lvm-thin-backup/cron-daily.sh << EOF
#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

SCRIPT_FILE="$(realpath $0)"
SCRIPT_DIR="$(dirname $SCRIPT_FILE)"
SCRIPT_NAME="$(basename -s .sh $SCRIPT_FILE)"

BACKUP_SCRIPT="$SCRIPT_DIR/lvm-thin-backup.sh"
RETENTION="-60 days"

$BACKUP_SCRIPT backup images linux-dev
$BACKUP_SCRIPT backup images win8
$BACKUP_SCRIPT backup images win8-data
#etc

$BACKUP_SCRIPT removeall images linux-dev "$RETENTION"
$BACKUP_SCRIPT removeall images win8 "$RETENTION"
$BACKUP_SCRIPT removeall images win8-data "$RETENTION"
#etc

EOF

ඒකෙන් මොකද කරන්නේ...?ලැයිස්තුගත තුනී වෙළුම්වල උපස්ථ සෑදීමට සහ සමමුහුර්ත කිරීමට පෙර ස්ක්‍රිප්ට් භාවිතා කරයි. අවසාන සමමුහුර්තකරණයේ සිට වෙනස්කම් නිරීක්ෂණය කිරීමට අවශ්‍ය වන ලැයිස්තුගත වෙළුම්වල ස්ක්‍රිප්ට් අක්‍රිය ස්නැප්ෂොට් තබයි.

උපස්ථ පිටපත් සෑදිය යුතු තුනී වෙළුම් ලැයිස්තුව සඳහන් කරමින් මෙම ස්ක්‍රිප්ට් සංස්කරණය කළ යුතුය. ලබා දී ඇති නම් නිදර්ශන අරමුණු සඳහා පමණි. ඔබට අවශ්‍ය නම්, ඔබට සියලුම වෙළුම් සමමුහුර්ත කරන ස්ක්‍රිප්ට් එකක් ලිවිය හැක.

අපි අයිතිවාසිකම් ලබා දෙමු:

#chmod +x /root/lvm-thin-backup/cron-daily.sh
#chmod +x /root/lvm-thin-backup/lvm-thin-backup.sh

අපි එය පරීක්ෂා කර එය ක්‍රෝන් එකට දමමු:

#/usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup
#cat /var/log/syslog | grep lvm-thin-backup
#crontab -e
0 3 * * * /usr/bin/nice -n 19 /usr/bin/ionice -c 3 /root/lvm-thin-backup/cron-daily.sh 2>&1 | /usr/bin/logger -t lvm-thin-backup

පළමු දියත් කිරීම දිගු වනු ඇත, මන්ද ... භාවිතා කරන ලද සියලුම ඉඩ පිටපත් කිරීමෙන් තුනී වෙළුම් සම්පූර්ණයෙන්ම සමමුහුර්ත වනු ඇත. LVM තුනී පාරදත්ත වලට ස්තුතිවන්ත වන්න, ඇත්ත වශයෙන්ම භාවිතා කරන්නේ කුමන බ්ලොක්දැයි අපි දනිමු, එබැවින් පිටපත් කරනු ලබන්නේ සැබවින්ම භාවිතා කරන තුනී පරිමා කුට්ටි පමණි.

LVM තුනී පාර-දත්ත හරහා ලුහුබැඳීම වෙනස් කිරීමට ස්තූතිවන්ත වන පරිදි පසුකාලීන ධාවන දත්ත වැඩි වැඩියෙන් පිටපත් කරනු ඇත.

අපි බලමු මොකද වුනේ කියලා:

#time /root/btrfs-backup/cron-daily.sh
real 0m2,967s
user 0m0,225s
sys 0m0,353s

#time /root/lvm-thin-backup/cron-daily.sh
real 1m2,710s
user 0m12,721s
sys 0m6,671s

#ls -al /backup/btrfs/back/remote/*
/backup/btrfs/back/remote/boot:
total 0
drwxr-xr-x 1 root root 1260 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 322 мар 26 02:00 .@base
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
drwxr-xr-x 1 root root 516 мар 6 09:39 [email protected]
...
/backup/btrfs/back/remote/root:
total 0
drwxr-xr-x 1 root root 2820 мар 26 09:11 .
drwxr-xr-x 1 root root 16 мар 6 09:30 ..
drwxr-xr-x 1 root root 240 мар 26 09:11 @.@base
drwxr-xr-x 1 root root 22 мар 26 09:11 @home.@base
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 22 мар 6 09:39 @[email protected]
...
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
drwxr-xr-x 1 root root 240 мар 6 09:39 @[email protected]
...

#lvs -olv_name,lv_size images && lvs -olv_name,lv_size backup
LV LSize
linux-dev 128,00g
linux-dev.base 128,00g
thin-pool 1,38t
win8 128,00g
win8-data 2,00t
win8-data.base 2,00t
win8.base 128,00g
LV LSize
backup 256,00g
images-linux-dev.base 128,00g
images-linux-dev.snap.2020-03-08-10-09-11 128,00g
images-linux-dev.snap.2020-03-08-10-09-25 128,00g
...
images-win8-data.base 2,00t
images-win8-data.snap.2020-03-16-14-11-55 2,00t
images-win8-data.snap.2020-03-16-14-19-50 2,00t
...
images-win8.base 128,00g
images-win8.snap.2020-03-17-04-51-46 128,00g
images-win8.snap.2020-03-18-03-02-49 128,00g
...
thin-pool <2,09t

කූඩු කරන බෝනික්කන් සමඟ මෙයට ඇති සම්බන්ධය කුමක්ද?

බොහෝ දුරට ඉඩ, LVM LV තාර්කික වෙළුම් අනෙකුත් VG සඳහා LVM PV භෞතික වෙළුම් විය හැක. LVM කූඩු බෝනික්කන් මෙන් පුනරාවර්තන විය හැක. මෙය LVM අතිශය නම්‍යශීලී බවක් ලබා දෙයි.

ප්රාදේශීය සභා

මීළඟ ලිපියෙන්, අපි නිවසේ ඩෙස්ක්ටොප්, ගෘහස්ථ අන්තර්ජාලය සහ P2P ජාල භාවිතා කරමින් මහාද්වීප කිහිපයක අතිරික්තයක් සහිත භූ-බෙදාහැරි ගබඩා/vm පොකුරක් නිර්මාණය කිරීමේ පදනම ලෙස සමාන ජංගම ගබඩා පද්ධති/KVM කිහිපයක් භාවිතා කිරීමට උත්සාහ කරමු.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න