Перейти до вмісту

Блог ·

Планування пулів IPv4-адрес для VPS

Адреси це той єдиний ресурс, якого не докупити у вівторок. Як формувати пули, чому суддею має бути база даних і що стається, коли пул пересихає.

Автор: Provibr

Усе інше в продукті VPS еластичне. Треба більше CPU, купіть вузол. Треба більше диска, купіть диск. Треба більше адрес, і ви в черзі очікування, платите брокерові або заповнюєте форму обґрунтування для регіонального реєстратора.

IPv4 є тим єдиним ресурсом, який поводиться як фізичний товар, і зазвичай йому дістається найменше уваги в проєктуванні, бо на початку у вас є /24, і 254 має вигляд достатку. Достатком це перестає бути рівно в тій точці, де перепроєктувати дорого.

Почніть із того, що блок насправді вам дає

Придатна кількість ніколи не дорівнює розміру блока. Дві адреси йдуть на мережу й на широкомовну, і ще одна на шлюз. На малих розмірах це не похибка округлення, це більша частина блока:

БлокАдресиМережа + широкомовнаШлюзПродаваніНакладні витрати
/24256212531%
/273221299%
/2816211319%
/29821538%
/30421175%

/29 звучить як вісім адрес рівно доти, доки ви не продасте пʼять із них. Якщо ви купуєте адресний простір малими блоками, закладайте накладні витрати окремим рядком; на /29 ви викидаєте три восьмих того, за що заплатили.

Дві межі варто закодувати в тому, що ви будуєте. Ми приймаємо /8 як найбільший, бо для більших блоків смужка використання перестає щось означати, і /30 як найменший, бо /31 і /32 за звичайними правилами для хостів мають нуль придатних адрес, і прийняти їх означає лише отримати пул, який ніколи не зможе нічого видати. Відмовити в них явно краще, ніж прийняти їх і бути порожнім.

Ще одна тонкість: адресі шлюзу дозволено сидіти всередині вашого діапазону видачі, і її просто пропускають. Це свідомо, бо так клієнтові найлегше міркувати, але це означає, що місткість пулу є обчисленням і ніколи не збереженим числом. Усе, що тримає лічильник вільних адрес, розійдеться з дійсністю того дня, коли хтось пересуне шлюз.

Формуйте пули навколо того, що продаєте, а не того, що купили

Одиниця, яку бачить клієнт, це тариф. Одиниця, яку ви купили в брокера, це блок. Ці дві майже ніколи не однакової форми, і звʼязування їх разом ламається першого ж разу, коли ви купуєте другий блок.

Улаштування, яке витримало: тариф указує на пул, а пул це або один префікс, або названа група префіксів. Додати продуктові місткість тоді означає додати префікс до групи, і це один рядок. Розподільник обходить групу по черзі й бере першу адресу, яку може отримати, тож група є ще й порядком спорожнення: покладіть наперед той блок, який хочете витратити першим.

Підблоки і помилка, що мовчки видає адресу двічі

Клієнти не використовують /24 як одну пласку мережу. Вони її ріжуть: шматок за одним маршрутизатором, шматок в іншому VLAN, шматок із власним шлюзом. Тож адресний план потребує дочірніх блоків.

Саме тут живе цікава відмова, і її варто сформулювати точно, бо вона мовчазна.

Механізм, що не дає двом одночасним замовленням отримати ту саму адресу, це частковий унікальний індекс на (префікс, адреса), обмежений рядками, які не звільнено. Той індекс діє в межах префікса. Якщо два рядки префіксів можуть кожен видати ту саму адресу, то з погляду індексу це дві різні адреси, і платформа видасть той самий IP двом машинам, і в програмі не станеться геть нічого поганого.

Індекс цього не виправить. Виправити має розкладка. Тож адресний простір є суворим розбиттям, і правила, які роблять його таким, такі:

  1. Дитина лежить цілком усередині батька і є строго меншою.
  2. Сусіди не можуть перекриватися.
  3. Батько не видає нічого, що потрапляє всередину дочірнього блока. З батьківського вікна вирізається весь блок, а не лише власний діапазон видачі дитини, бо інакше відповідь залежала б від діапазону, який якийсь адміністратор пересуне наступного тижня.
  4. Вкладеність має один рівень.

З цими чотирма «якому префіксу належить 192.0.2.70» завжди має рівно одну відповідь, і наявного індексу достатньо.

Що дитина успадковує, це окремий набір рішень, і відповіді неоднакові. Шлюз: ніколи (дитині без власного шлюзу немає для чого існувати). DNS: так, якщо власне поле порожнє, бо резолвери належать мережі, а не блокові. Діапазон видачі: лише там, де батьківський діапазон справді торкається дитини, бо батьківський діапазон виражено в батькових адресах і зазвичай він з дитиною взагалі не перетинається; успадкувати його наосліп означає отримати порожнє вікно.

Хай судить база даних

Спокуса, коли два замовлення приходять одночасно, це щось заблокувати або тримати лічильник. Обидва гірші за нудну відповідь.

Обидва замовлення обчислюють ту саму «найнижчу вільну адресу» і обидва пробують вставити. Одна вставка перемагає, друга наражається на порушення унікальності, і той, хто програв, переходить до наступного кандидата. База даних це єдина сторона, яка бачить кожного, хто пише, включно з тим, хто в іншому процесі, іншому воркері чи іншій вкладці браузера.

Наслідок має значення, коли ви пишете код: не перевіряйте спершу. Прочитати «чи ця адреса вільна» і потім вставити відкриває рівно те вікно, заради закриття якого обмеження й існує. Невдала вставка є відповіддю на «чи була вона вільна», і єдиною надійною.

Одна деталь реалізації, на якій людей ловить: багато ORM загортають помилки драйвера у власний тип помилки, тож потрібний вам SQLSTATE лежить не на винятку, який ви ловите, а на його причині. Перевіряйте весь ланцюг і використовуйте назву обмеження, щоб вирішити, яке повідомлення показати. В одній таблиці часто чотири різні правила унікальності, і якщо всі вони кажуть те саме, клієнта відправляють не до того поля.

Що стається, коли пул пересихає

За «немає доступної адреси» ховаються три різні відмови, і звалювання їх докупи щоразу породжує звернення в підтримку:

СитуаціяЩо це означаєЩо має прочитати клієнт
Тариф не вказує на жоден пулКонфігурація, а не місткістьУ тарифу немає адресного пулу
У префікса непридатні даніОдин зламаний рядок, інші ціліЦі префікси не вдалося прочитати
Усі кандидати зайнятіСправжнє вичерпанняЦей пул повний, і ось який саме

Середній випадок вартий додаткового коду. Один префікс із нечитабельними даними не повинен блокувати інші префікси у своїй групі; занотуйте його, спробуйте решту й повідомте про нього, лише якщо не спрацювало взагалі нічого. Інакше один поганий рядок кладе замовлення для цілої продуктової лінійки.

А повідомлення про вичерпання має називати префікс і його CIDR. «Немає доступного IP» відправляє когось читати журнали. «Пул повний: customer-block-2 (198.51.100.0/28)» відправляє його купувати адреси.

Віддавайте адреси назад, і будьте уважні щодо моменту

Звільнення це та половина, яка тихо втрачає місткість.

Два правила, що виявилися важливішими, ніж очікувалося. Перше: звільнити це не видалити рядок, а виставити часову позначку звільнення. Частковий унікальний індекс дивиться лише на живі рядки, тож адреса одразу придатна для повторної видачі, а «хто мав 192.0.2.10 торік» лишається питанням з відповіддю. Це більша частина причини взагалі вести облік адрес, і це те питання, яке ставить скарга на зловживання.

Друге: звільнення відбувається, коли машина підтверджено зникла, а не коли видалення запросили. Лише той, хто стоїть поруч із гіпервізором, знає, що VM справді зникла; звільнення за вихідною командою віддає адресу наступному клієнтові, поки стара машина ще працює й ще відповідає на ній. Дзеркальний випадок це замовлення, що падає на півдорозі: там видачу відкидають, а не звільняють, бо її ні на чому не налаштували.

Тут є свідома асиметрія, яку варто підкреслити, бо шаром вище ми робимо протилежний вибір. Адреси використовують повторно, найнижча вільна перша. Ідентифікатори машин не використовують повторно ніколи. Запізніле повідомлення про стан видаленої VM, що приземляється на новий рядок із тим самим ідентифікатором, псує історії двох машин; адреса так історії не несе, а ніколи не використовувати її повторно означало б назавжди вичерпати /24 після 254 машин. Той самий продукт, протилежні правила, різні причини.

Резервування належать до тієї самої таблиці, що й видачі

Вам знадобиться притримувати адреси: балансувальник навантаження, шлюз на блоці, який ви ще не розгорнули, пʼять адрес, які хтось пообіцяв клієнтові на наступний квартал.

Кладіть їх у ту саму таблицю, що й справжні видачі. Кожен читач, який питає «що зайнято», розподільник, смужка використання, список підказок в адресному полі, тоді враховує їх автоматично, і немає другої адміністрації, якій можна розійтися з першою. Окрема таблиця резервувань це друге джерело правди, яке розійдеться з першим протягом місяця.

З одним винятком, який легко зробити неправильно: зарезервована адреса ніколи не повинна опинитися в білому списку фаєрвола машини. Той список будується з видач, що належать одному серверу, а резервування не належить жодному серверу. Помилитеся тут, і VM одного клієнта почне приймати трафік, адресований чужому балансувальнику навантаження.

А IPv6

Ми розпізнаємо введення IPv6 і ввічливо відмовляємо, а не приймаємо його й обчислюємо щось правдоподібне: наполовину робочий шлях IPv6 небезпечніший за жоден, бо числа, які він видає, мають правильний вигляд. Дешеве рішення, яке себе окупає, це зберігати адреси, шлюзи та сервери DNS текстом, а не 32-бітним цілим, щоб додати IPv6 пізніше було кодом, а не міграцією кожного рядка, який ви маєте.

Коротка версія

  • Закладайте накладні витрати. /29 це пʼять продаваних адрес, а не вісім.
  • Хай тарифи вказують на пули, а пули на префікси. Купівля простору має бути одним рядком.
  • Якщо ви дозволяєте підблоки, зробіть адресний простір суворим розбиттям, інакше правило унікальності, що вас захищає, тихо діє в межах префікса й не захищає нічого.
  • Хай гонку вирішує унікальне обмеження. Ніколи не перевіряйте спершу.
  • Звільняйте за підтвердженням, а не за запитом, і зберігайте історію.
  • Називайте пул у повідомленні про вичерпання. Це різниця між зверненням у підтримку й замовленням на купівлю.

Це вийшло з побудови керування адресами в Provibr, де адреси видаються при розміщенні замовлення й повертаються, коли агент підтверджує, що машини справді немає.

Читати далі

Почніть з одного хоста й одного агента

Створіть обліковий запис, встановіть агента однією командою та підключіть свій перший хост Proxmox. Пробний період триває 14 днів і не потребує платіжних даних.