Балансирането на натоварването увеличава производителността на системата, особено от гледна точка на приложението, позволявайки на няколко компютъра да обслужват едни и същи данни. Той работи по такъв начин, че натоварването се разпределя между клиентски заявки към реплика възли, освен неговия първичен или главен възел, като същевременно насочва модификациите на базата данни само към главния възел. Всички модификации на главния възел впоследствие се разпространяват към всяка реплика с помощта на PostgreSQL Streaming Replication.
Как могат средствата за балансиране на натоварване да повлияят на PostgreSQL?
Използването на балансиране на натоварването ще насочи клиентските приложения да се свържат със сървъра за балансиране на натоварването и ще разпределят инициираните връзки към наличните възли на PostgreSQL в зависимост от типа на заявките за заявка. Това помага да се подчертае изключителното натоварване на конкретен PostgreSQL сървър и насърчава паралелен баланс на натоварването между наличните възли в клъстера.
С помощта на PostgreSQL вече има няколко съществуващи решения, които да накарат това да работи. Тези решения могат да работят безпроблемно или балансирането на натоварването може да работи с текущата топология - с първични и резервни възли - но балансирането на натоварването се прилага в самия слой на приложението. Балансирането на натоварването е изправено пред предизвикателства с проблеми със синхронизацията, което е основната трудност за сървърите, работещи заедно. Тъй като няма единно решение, което да елиминира въздействието на проблема със синхронизирането за всички случаи на употреба, има множество решения. Всяко решение се справя с този проблем по различен начин и свежда до минимум въздействието му за конкретно натоварване.
В този блог ще разгледаме тези балансатори на натоварване, като ги сравним и колко е полезно за вашето работно натоварване на PostgreSQL.
Балансиране на натоварването на HAProxy за PostgreSQL
HAProxy е управляван от събития, неблокиращ механизъм, комбиниращ прокси с много бърз I/O слой и базиран на приоритети, многонишков планировчик. Тъй като е проектиран с цел препращане на данни, неговата архитектура е проектирана да работи в олекотен процес, който е оптимизиран за преместване на данни възможно най-бързо с възможно най-малко операции. Той се фокусира върху оптимизиране на ефективността на кеша на процесора чрез залепване на връзки към същия процесор възможно най-дълго. Като такъв, той прилага многослоен модел, предлагащ механизми за байпас на всяко ниво, като гарантира, че данните няма да достигнат по-високи нива, освен ако не е необходимо. По-голямата част от обработката се извършва в ядрото. HAProxy прави всичко възможно, за да помогне на ядрото да свърши работата възможно най-бързо, като дава някои намеци или като избягва определени операции, когато предположи, че могат да бъдат групирани по-късно. В резултат на това типичните цифри показват 15% от времето за обработка, прекарано в HAProxy срещу 85% в ядрото в TCP или HTTP затворен режим и около 30% за HAProxy срещу 70% за ядрото в HTTP поддържащ активност.
HAProxy също има допълнителни функции за балансиране на натоварването. Например, функцията за TCP прокси ни позволява да я използваме за връзки към база данни, особено за PostgreSQL, като използваме вградената поддръжка на услугата за проверка. Въпреки че има поддръжка на услугата за база данни, тя не е достатъчна за желаната проверка на здравето, особено за тип репликация на клъстер. Стандартният подход при внедряването му за производство е да се използва TCP проверка, след което да зависи от xinetd с HAProxy.
Плюсове от използването на HAProxy за PostgreSQL
Най-доброто нещо с HAProxy е неговата лека маса, лесна за конфигуриране и използване и върши работата, както се очаква. Използването на HAProxy върху PostgreSQL клъстер е внедрено и разгръщано многократно от големи организации до различни МСП/SMB за тяхното производствено използване. Отдавна е доказано за производство и висок капацитет на натоварване не само за бази данни, но дори и с други мрежови услуги, като уеб приложения или за балансиране на географското натоварване (разпределение на трафика в множество центрове за данни). Притежавайки HAProxy върху PostgreSQL, той позволява на потребителите възможността да ограничават или ограничават отговорите, за да паралелизират и разпределят правилно натоварването към всички налични възли в клъстера. Вграденият механизъм с HAProxy също така позволява на потребителя да настрои висока наличност безпроблемно и по-лесно за мащабиране, ако е необходимо натоварване и да избегне единична точка на повреда (SPOF).
Недостатъци от използването на HAProxy за PostgreSQL
HAProxy не предоставя филтриране на заявки, нито анализ на заявки за идентифициране на типа заявени изрази. Липсва му възможност за извършване на разделяне на четене/запис на един порт. Задаването на балансьор на натоварване върху HAProxy изисква поне да настроите различни портове за вашите записи и различни за вашите четения. Това изисква промени в приложението, за да отговарят на вашите нужди.
HAProxy също поддържа много проста функция с PostgreSQL за проверка на здравето, но това само определя дали възелът е нагоре или не, сякаш просто пингува възела и чака отговор за връщане. Той не идентифицира каква роля възелът се опитва да препрати исканите връзки от клиента към желания възел. Следователно той не разбира или няма функция в HAProxy, за да разбере топологията на репликация. Въпреки че потребителят може да създаде отделни слушатели на базата на различни портове, но все пак той добавя промени в приложението, за да задоволи нуждите от балансиране на натоварването. Това означава, че използването на външен скрипт с xinetd може да бъде решението за запълване на изискванията. Все пак той не е интегриран в HAProxy и може да бъде податлив на човешка грешка.
Ако един възел или група възли трябва да бъдат поставени в режим на поддръжка, тогава ще трябва също да приложите промени към вашия HAProxy, в противен случай това може да бъде катастрофално.
Pgpool-II за балансиране на натоварването на вашия PostgreSQL
Pgpool-II е софтуер с отворен код и е обгърнат от масивната PostgreSQL общност за внедряване на балансиране на натоварването и използване на това, за да действа като техен междинен софтуер от приложението надолу до прокси слоя, след което разпределя натоварването след като е анализирал напълно типа заявка за заявка или връзка с база данни. Pgpool-II съществува толкова дълго време от 2003 г., което първоначално беше наречено Pgpool, докато не стана Pgpool-II през 2006 г., което служи като свидетелство за много стабилен прокси инструмент не само за балансиране на натоварването, но и за множество страхотни функции .
Pgpool-II е известен като швейцарското армейско ножче за PostgreSQL и е прокси софтуер, който се намира между PostgreSQL сървъри и PostgreSQL клиент на база данни. Основната идея на PgPool-II е, че той седи на клиента, след което заявките за четене трябва да се доставят до резервните възли, докато записът или модификациите отиват направо към основния. Това е много интелигентно решение за балансиране на натоварването, което не само балансира натоварването, но също така поддържа висока наличност и осигурява обединяване на връзки. Интелигентният механизъм позволява балансиране на натоварването между главни и подчинени. Така че записите се зареждат към главния, докато обработката на прочитанията се насочва към наличните сървъри само за четене, които са вашите предполагаемо горещи резервни възли. Pgpool-II също осигурява логическа репликация. Въпреки че използването и значението му са намаляли с подобряването на вградените опции за репликация от страна на сървъра на PostgreSQL, това все още остава ценна опция за по-старите версии на PostgreSQL. Освен всичко това, той осигурява и обединяване на връзки.
Pgpool-II има по-сложна архитектура от PgBouncer, за да поддържа всички функции, които прави. Тъй като и двете поддържат обединяване на връзки, последният няма функции за балансиране на натоварването.
Pgpool-II може да управлява множество PostgreSQL сървъри. Използването на функцията за репликация позволява създаване на резервно копие в реално време на 2 или повече физически диска, така че услугата да може да продължи без спиране на сървърите в случай на повреда на диска. Тъй като Pgpool-II също е способен за обединяване на връзки, той може да осигури ограничаване на превишаването на връзките. Има ограничение за максималния брой едновременни връзки с PostgreSQL и връзките се отхвърлят след толкова много връзки. Задаването на максимален брой връзки обаче увеличава потреблението на ресурси и се отразява на производителността на системата. pgpool-II също има ограничение за максималния брой връзки, но допълнителните връзки ще бъдат поставени на опашка, вместо незабавно да връщат грешка.
При балансиране на натоварването, Ако база данни се репликира, изпълнението на заявка SELECT на всеки сървър ще върне същия резултат. pgpool-II се възползва от функцията за репликация, за да намали натоварването на всеки PostgreSQL сървър, като разпределя SELECT заявки между множество сървъри, подобрявайки общата пропускателна способност на системата. В най-добрия случай производителността се подобрява пропорционално на броя на сървърите на PostgreSQL. Балансът на натоварването работи най-добре в ситуация, когато има много потребители, изпълняващи много заявки едновременно.
Използвайки функцията за паралелна заявка, данните могат да бъдат разделени между множеството сървъри, така че заявка да може да се изпълни на всички сървъри едновременно, за да се намали общото време за изпълнение. Паралелната заявка работи най-добре при търсене на данни в голям мащаб.
Плюсове от използването на Pgpool за PostgreSQL
Това е богат на функции тип софтуер не само за балансиране на натоварването. Основните функции и поддръжката на този инструмент са силно при поискване, което осигурява обединяване на връзки, алтернативен go PgBouncer, собствена репликация, онлайн възстановяване, кеширане на заявки в паметта, автоматично преминаване при отказ и висока наличност с неговия подпроцес, използващ watchdog. Този инструмент е толкова стар и непрекъснато се поддържа масово от PostgreSQL общността, така че справянето с проблеми не може да бъде трудно да се потърси помощ. Документацията е ваш приятел тук, когато търсите въпроси, но търсенето на помощ в общността не е трудно и фактът, че този инструмент е с отворен код, така че можете свободно да го използвате, стига да спазвате лиценза на BSD.
Pgpool-II също има SQL анализатор. Това означава, че е в състояние да анализира точно SQLs и да пренапише заявката. Това позволява на Pgpool-II да увеличи паралелизма в зависимост от заявката.
Недостатъци от използването на Pgpool за PostgreSQL
Pgpool-II не предлага STONITH (застреляйте другия възел в главата), който осигурява механизъм за ограждане на възли. Ако PostgreSQL сървърът се повреди, той поддържа наличността на услугата. Pgpool-II може също да бъде единствената точка на отказ (SPOF). След като възелът падне, връзката и наличността на вашата база данни спират от тази точка. Въпреки че това може да бъде поправено чрез резервиране с Pgpool-II и използване на watchdog за координиране на множество Pgpool-II възли, това добавя допълнителна работа.
За пул на връзки, за съжаление, за тези, които се фокусират само върху обединяването на връзки, това, което Pgpool-II не прави много добре, е обединяването в пул, особено за малък брой клиенти. Тъй като всеки дъщерен процес има свой собствен пул и няма начин да се контролира кой клиент се свързва с кой дъщерен процес, остава твърде много на късмета, когато става въпрос за повторно използване на връзки.
Използване на JDBC драйвер за балансиране на натоварването на вашия PostgreSQL
Свързването с база данни на Java (JDBC) е интерфейс за програмиране на приложения (API) за езика за програмиране Java, който определя как клиентът може да има достъп до база данни. Той е част от платформата Java Standard Edition и предоставя методи за запитване и актуализиране на данни в база данни и е ориентиран към релационни бази данни.
PostgreSQL JDBC драйвер (накратко PgJDBC) позволява на Java програмите да се свързват към PostgreSQL база данни, използвайки стандартен, независим от базата данни Java код. Това е JDBC драйвер с отворен код, написан на Pure Java (Тип 4) и комуникира в собствения мрежов протокол на PostgreSQL. Поради това драйверът е независим от платформата; веднъж компилиран, драйверът може да се използва във всяка система.
Това не е сравнимо с решенията за балансиране на натоварването, които посочихме по-рано. Следователно, този инструмент е вашият API за програмен интерфейс за приложение, който ви позволява да се свързвате от вашето приложение за всеки тип език за програмиране, който е написан, който поддържа JDBC или поне има адаптер за свързване с JDBC. От друга страна е по-благоприятно с Java приложенията.
Балансирането на натоварването с JDBC е доста наивно, но може да свърши работа. Снабден с параметрите на връзката, които могат да задействат механизма за балансиране на натоварването, който този инструмент може да предложи,
- targetServerType - позволява отваряне на връзки само към сървъри с необходимо състояние/роля в съответствие с определящия фактор за сървърите на PostgreSQL. Разрешените стойности са произволни, първични, главен (отхвърлен), подчинен (отхвърлен), вторичен, preferSlave и preferSecondary. Състоянието или ролята се определят чрез наблюдение дали сървърът позволява запис или не.
- hostRecheckSeconds - контролира колко време в секунди се кешират знанията за състоянието на хоста в широкия глобален кеш на JVM. Стойността по подразбиране е 10 секунди.
- loadBalanceHosts – позволява ви да конфигурирате дали първият хост винаги се опитва (когато е зададен на false) или ако връзките се избират произволно (когато е зададено на true)
Така че използва loadBalanceHosts, който приема булева стойност. loadBalanceHosts е деактивиран по време на режима по подразбиране и хостовете са свързани в дадения ред. Ако активираните хостове са избрани на случаен принцип от набора от подходящи кандидати. Основният синтаксис при свързване към базата данни чрез jdbc е както следва,
- jdbc:postgresql:database
- jdbc:postgresql:/
- jdbc:postgresql://host/database
- jdbc:postgresql://host/
- jdbc:postgresql://host:port/database
- jdbc:postgresql://host:port/
Като се има предвид, че loadBalanceHosts и връзката получават множество хостове, конфигурирани точно както по-долу,
jdbc:postgresql://host1:port1,host2:port2,host3:port3/database
Това позволява на JDBC да избира произволно от набора от подходящи кандидати.
Плюсове от използването на PgJDBC за PostgreSQL
Няма нужда да изисквате междинен софтуер или прокси като балансьори на натоварване. Този процес добавя повече повишаване на производителността от интерфейса на приложението, тъй като няма допълнителен слой за преминаване на всяка заявка. Ако имате готови приложения и са написани да поддържат взаимодействие с JDBC, това може да бъде от полза и ако не се нуждаете от повече междинен софтуер, особено ако бюджетът ви е ограничен и иска да ограничи само процесите, посветени на неговата единствена цел и функция. За разлика от приложенията с голям трафик и голямо търсене, това може да изисква прокси сървъри да действат като балансьори на натоварването и може да изисква допълнителни ресурси за правилно обработване на високи заявки за връзки, което също изисква изискване за обработка на процесора и паметта.
Недостатъци от използването на PgJDBC за PostgreSQL
Трябва да настроите своя код за всяка връзка, която да бъде поискана. Това е интерфейс за програмиране на приложения, което означава, че има работа, с която трябва да се справите, особено ако вашето приложение е много взискателно към всяка заявка да бъде изпратена до правилните сървъри. Няма висока наличност, автоматична мащабируемост и има единична точка на повреда.
Какво ще кажете за обвивки или инструменти, внедрени с libpq за балансиране на натоварването на вашия PostgreSQL?
libpq е интерфейсът на C приложния програмист към PostgreSQL. libpq е набор от библиотечни функции, които позволяват на клиентските програми да предават заявки към задния сървър на PostgreSQL и да получават резултатите от тези заявки.
libpq е и основната машина за няколко други интерфейса на приложения PostgreSQL, включително тези, написани за C++, PHP, Perl, Python, Tcl, Swift и ECPG. Така че някои аспекти на поведението на libpq ще бъдат важни за вас, ако използвате един от тези пакети.
libpq не автоматизира балансирането на натоварването и не трябва да се разглежда като инструмент за решения за балансиране на натоварването. И все пак, той може да се свърже към следващите налични сървъри, ако предишните сървъри, изброени за връзка, не успеят. Например, ако имате два налични възела за горещ режим на готовност, ако първият възел е твърде зает и не успее да отговори на съответната стойност на изчакване, тогава той се свързва със следващия наличен възел в дадената връзка. Той разчита на какъв тип атрибути на сесията сте посочили. Това разчита на параметър target_session_attrs.
Параметърът target_session_attrs приема стойности четене-записване и всяка, която е стойността по подразбиране, ако не е посочена. Параметърът target_session_attrs е, че ако е зададен на четене-запис, само връзка, в която транзакции за четене-запис се приемат по време на връзката. Заявката SHOW transaction_read_only ще бъде изпратена при всяка успешна връзка. Ако резултатът е включен, тогава връзката ще бъде затворена, което означава, че възелът е идентифициран като реплика или не обработва записи. Ако в низа за връзка са посочени няколко хоста, всички останали сървъри ще бъдат изпробвани точно така, сякаш опитът за свързване е бил неуспешен. Стойността по подразбиране на този параметър е произволна, което означава, че всички връзки са приемливи. Въпреки че разчитането на target_session_attrs не е достатъчно за балансиране на натоварването, може да сте в състояние да симулирате кръговрат. Вижте моя примерен C код по-долу, използвайки libpq,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libpq-fe.h>
const char* _getRoundRobinConn() {
char* h[2];
h[0] = "dbname=node40 host=192.168.30.40,192.168.30.50";
h[1] = "dbname=node50 host=192.168.30.50,192.168.30.40";
time_t t;
//srand((unsigned)time(&t));
sleep(1.85);
srand((unsigned)time(NULL));
return h[rand() % 2];
}
void
_connect()
{
PGconn *conn;
PGresult *res;
char strConn[120];
snprintf(strConn, 1000, "user=dbapgadmin password=dbapgadmin %s target_session_attrs=any", _getRoundRobinConn());
//printf("\nstrConn value is: %s\n", strConn);
conn = PQconnectdb(strConn);
res = PQexec(conn, "SELECT current_database(), inet_client_addr();");
if ( PQresultStatus(res)==PGRES_TUPLES_OK )
{
printf("current_database = %s on %s\n", PQgetvalue(res, 0, 0),
PQhost(conn));
} else {
printf("\nFailed... Message Code is: %d\n", PQresultStatus(res));
}
PQclear(res);
PQfinish(conn);
}
int main(void)
{
int i;
for (i=0 ; i<5 ; i++)
_connect();
return 0;
}
Резултатът разкрива,
[email protected]:/home/vagrant# gcc -I/usr/include/postgresql -L/usr/lib/postgresql/12/lib libpq_conn.c -lpq -o libpq_conn; ./libpq_conn
current_database = node40 on 192.168.30.40
current_database = node40 on 192.168.30.40
current_database = node50 on 192.168.30.50
current_database = node40 on 192.168.30.40
current_database = node50 on 192.168.30.50
Обърнете внимание, че ако възел .40 (основният възел) падне, той винаги ще насочва връзката към .50, стига стойността на target_session_attrs да е някаква.
В този случай можете просто да създадете свой собствен свободно с помощта на libpq. Въпреки че процесът на разчитане на libpq и/или неговите обвивки е твърде груб, за да се каже, че това може да осигури желания механизъм за балансиране на натоварването с равномерно разпределение към възлите, които имате. Определено този подход и кодирането могат да бъдат подобрени, но мисълта е, че това е безплатно и с отворен код и можете да кодирате, без да разчитате на междинен софтуер и свободно да проектирате начина, по който ще работи балансирането на натоварването.
Плюсове от използването на libpq за PostgresQL
libpq библиотеката е интерфейсът на приложението на програмиста, изграден на езика за програмиране C. И все пак, библиотеката е внедрена на различни езици като обвивки, така че програмистите да могат да комуникират с базата данни PostgreSQL, използвайки любимите си езици. Можете директно да създадете свое собствено приложение, като използвате любимите си езици и след това да изброите сървърите, към които възнамерявате да бъдат изпратени заявки, но само след другия, ако неуспех или изчакване изпратете натоварването ви към наличните възли, на които възнамерявате да разпределите натоварването. Предлага се на езици като Python, Perl, PHP, Ruby, Tcl или Rust.
Недостатъци от използването на libpq за PostgresQL
Внедряването на паралелизма на натоварване не е идеално и трябва да напишете свой собствен механизъм за балансиране на натоварването чрез код. Няма конфигурация, която можете да използвате или персонализирате, тъй като това е изцяло програмен интерфейс към базата данни PostgreSQL с помощта на параметър target_session_attrs. Това означава, че когато композирате връзка с база данни, трябва да имате поредица от връзки за четене към вашите реплика/готови възли, след което да пишете заявки, които отиват към записващия или основния възел във вашия код, независимо дали е във вашето приложение или трябва да създадете свой собствен API за управление на решението за балансиране на натоварването.
Използването на този подход определено не се нуждае или разчита на междинен софтуер от гледна точка на предното приложение към базата данни като бекенд. Разбира се, това е леко, но когато изпращате списъка със сървъри при свързване, това не означава, че натоварването се разбира и изпраща равномерно, освен ако не трябва да добавите кода си за този подход. Това само създава проблеми, но вече има съществуващи решения, така че защо трябва да се преоткрива колелото?
Заключение
Внедряването на вашите балансатори на натоварване с PostgreSQL може да бъде взискателно, но зависи от типа приложение и цената, с която се занимавате. Понякога, за голямо търсене на натоварване, това изисква нуждата от междинен софтуер, действащ като прокси, за да разпредели правилно натоварването и също така да наблюдава състоянието или здравето на възела. От друга страна, той може да изисква сървърни ресурси или трябва да се изпълнява на специален сървър, или изисква допълнителен процесор и памет, за да задоволи нуждите и това добавя разходи. Следователно има и прост начин, но отнемащ време, но предлага разпределение на натоварването към наличните сървъри, които вече имате. И все пак това изисква умения за програмиране и разбиране на функционалността на API.