Оптимизация на Bitrix код, кеширане, композит и др.

кеширане

Имах възможност да работя с различни проекти и различни хора. Имаше проекти, натоварени като посещаемост, но бедни като функционалност. Беше обратното - 500 посещения на месец, а сложността на функционалността беше безкрайна. Но ето какво не беше късмет - така че е с развитието. Трябваше да разработя проект от нулата и преди стартирането само няколко пъти. В други случаи беше необходимо да се справим с поддръжката на съществуващ код (написан от други разработчици) и въвеждането на нова функционалност в него. Но го смятам за огромен плюс на моята работа. Първо, можете да намерите много решения, както интересни, така и, честно казано, „гадни“. Второ, трябва да използвате огромно количество сиво вещество, за да съберете цялата картина в главата си, така че когато се въведат някои подобрения, старите да не се разпаднат.

Често трябва да помислите как всичко „работи бързо“ и как да пренесете съществуващия код, който генерира 200, 300, 500, 900, а понякога и 2-4k заявки към базата данни на удар, а скоростта на изобразяване на генерираното съдържание от клиента надвишава 3-5 секунди.

В тази статия ще засегна основните принципи на оптимизацията на приложенията на Bitrix (да, считам сайтовете на Bitrix за „приложения“, а не за сайтове) от страна на сървъра. И така, да започваме

Как да анализираме натоварването на Bitrix

Първият инструмент, който трябва да разгледате, когато оптимизирате, е Bitrix Debugging. Това е такъв бутон на административния панел, при щракване върху него се появява в долната част на страницата, ще се появи информация за скоростта на генериране на страницата и заявките, които генерира.

оптимизация

кеширане

Не забравяйте за прости инструменти.Винаги можете да измерите скоростта на дадена секция, като използвате прости извиквания към функцията microtime, нещо подобно:

Тази конструкция ще покаже времето за изпълнение на кода в секунди, което ще даде малко храна за размисъл. Гъвкавостта на този метод е, че можете просто да стесните областта за търсене от огромно парче код до обвиване на една функция.

По-долу няма да пиша за спестяване „при съвпадения“, като замяна на foreach с for или array_map, няма да правя кампания за промяна на регулярни изрази към функции за низове и т.н. Ще пиша за това в отделна публикация по-късно.

Оптимизация по брой заявки

Първото нещо, което идва на ум, е да намалим броя на възможните заявки до минимум. Представете си тази ситуация – трябва да изведете списък с продукти на страницата, а под списъка с продукти да създадете определена област, която ще съдържа логата на всички марки, които притежават продуктите от страницата. Марките се съхраняват в отделен информационен блок, марката има име (ИМЕ) и подробно изображение (DETAIL_PICTURE), а всеки продукт има свойство, което указва връзка към елемент от информационния блок на марката (PROPERTY_BRAND). Какво обикновено прави разработчик, който не мисли с главата си:

    получава списък с продукти по заявка, където получава името на продукта и обвързването с марката

Никога не правете това. Това е ужасно, подло и грешно. Имаше период в живота ми, когато наистина се уморих да казвам това на хората.

Какви проблеми виждам тук? Е, първо, това всъщност е заявка за получаване на марки в цикъл. Ако мислите за това, тогава такива страници се правят, като правило, за не много голям брой продукти (200, може би 300). В този случай бих използвал различен метод. В продуктов цикъл има смисъл да се съберат всички идентификатори в масив,и след това използвайте този масив, за да изпълните една единствена заявка към база данни. Ще изглежда нещо подобно:

Умишлено използвах хеш масив с ключове, за да съхранявам идентификаторите на марката тук. Ако има много продукти, тогава марките най-вероятно ще бъдат дублирани в редовен номериран масив, след което той ще трябва да бъде обединен (или на ниво php, или на ниво база данни), като за това ще трябва да заобиколите целия масив. А при запис в масив с ключове скоростта на достъп до даден елемент е почти мигновена (в разумни граници). Преразходът на паметта очевидно е малък (марките трябва да са много по-малко от стоките при нормални условия), но увеличаването на скоростта на работа с масива ще се усети.

Като цяло е по-добре да направите една малко по-сложна заявка, за да изберете всички необходими данни, отколкото сто малки заявки, всяка от които ще получи само част от тези данни.

Оптимизация според количеството данни за избор

Нашият пример по-горе има друг огромен недостатък. Според условието на проблема се нуждаем само от имидж на марката. Нашата заявка обаче ще получи всички възможни полета и свойства от информационния блок с марки. Не забравяйте да посочите точния набор от данни, който искате да използвате на страницата. Това може да спести доста време при извличане. Bitrixне може да генерира оптимални заявки (в D7 това очевидно е по-добре, но все още не е дошло до ум и само малцина го използват). Следователно, колкото по-малко данни изберете, толкова по-малко Bitrix ще генерира съединения, подзаявки, съединения в заявката и толкова по-бързо ще бъде обработена вашата заявка. В действителност ще изглежда така:

Искам да отбележа още един момент, който разработчиците често пренебрегват. Класът CIBlockResult има метод GetNextElement(). Той се връщаобектът _CIBElement, който ви позволява да получите достъп до полетата на избрания елемент и неговите свойства. Не трябва да използвате метода GetProperties(), без да сте напълно наясно, че той извлича всички свойства от базата данни като цяло. Ако добавите факта, че хората го използват в цикъл върху всички елементи на селекцията, тогава тази част от кода може да се окаже много тежка. Ограничете набора от избираеми свойства и не използвайте GetNextElement() в кръгови селекции. Оправдано е да се получат всички свойства само в изключителни ситуации (например на страница с подробности за продукта, където често са необходими почти всички свойства). Ето пример закак да не правите :

Ако наистина разбирате, че трябва да направите това, тогава поне ограничете списъка със свойства, методът GetProperties() съдържа 2 параметъра - ред на сортиране и филтриране по свойства, подобно на CIBlockElement::GetProperty(); И между другото, дори ако сте предали само свойствата, които трябва да $arSelect в родителската заявка, те ще влязат в GetFields(). Но GetProperties() ще избере само онези свойства, които съответстват на филтъра, който му е подаден (по подразбиране всички свойства). Накратко, това е заявка в цикъл и често доста голяма, така че трябва да я избягвате.

Автоматично кеширане на компоненти

Не забравяйте за възможностите за кеширане в Bitrix. Първата и най-лесна функция е автоматичното кеширане в компонентите. Основната клетка на сайта в концепцията на Bitrix е компонент. Всяка страница се състои от набор от компоненти. И всеки компонент, ако не противоречи на логиката му, трябва да бъде кеширан. Това е особено вярно за "тежки" компоненти, които се занимават с големи извадки от данни и тяхната работа в дългосрочен план (например продуктов каталог), данните, в коитосе актуализира доста рядко. Е, тъй като тази операция се използва доста често, интерфейсът за кеширане на компоненти е доста прост. Достатъчно е да обвиете кода, който трябва да бъде кеширан в кодов блок:

По подразбиране кешът зависи от набора от входни параметри. Тези. ако компонентът има един параметър с някаква стойност, тогава за този набор от параметри ще бъде генериран кешът. Промяната на тази настройка ще генерира различен кеш за компонента. Стойността по подразбиране на параметъра CACHE_TIME на компонента ще бъде взета като време за кеша. Той може да бъде променен, ако желаете, чрез предаване на първия параметър на метода StartResultCache( $cacheTime ).

Също така, в допълнение към параметрите, можете също да добавите зависимости към идентификатора на кеша, като използвате втория параметър на функцията. Например, за да направите кеша зависим от групата на потребителя, можете да използвате следната конструкция:

Важно е да се разбере, че автоматичното кеширане по подразбиране запазва само html изход, който е рамкиран от блок с извикване на метода StartResultCache (). Съответно връзката на шаблона също трябва да бъде вътре в този блок. За да включите шаблона в кеша, трябва да управлявате връзката на шаблона в нашия блок:

Но можете също да включите данни в автоматичния кеш на компонента Bitrix. За да направите това, използвайте метода SetResultCacheKeys(). Този метод приема като вход масив от ключове, които се съдържат в $arResult. Ако искате да съхраните в кеша на компонентите някакъв низ, например името на продукта (за да го използвате, след като компонентът бъде изпълнен, например в component_epilog.php), който компонентът показва, тогава трябва да използвате следната конструкция:

Има още един тънък момент. Важно е да избягвате погрешно кеширанеданни. Ако по време на работа има шанс да получите неправилни данни, тогава трябва да се справите с тази ситуация и да нулирате автоматичното кеширане. В противен случай в кеша ще бъде записан неправилен набор от данни + шаблон и потребителят ще вижда неправилни данни по време на живота на кеша. За да нулираме кеша, използваме следната конструкция:

Важно е да разберете, че когато даден компонент е кеширан, неговият резултат се връща от кеша и целият код, който е записан в кода на компонента вътре в кеширащия блок, както и целият код на шаблона, няма да бъдат повторно изпълнени, така че ако внезапно използвате отложени функции в шаблоните на компоненти (или в result_modifier.php), тогава те няма да работят при кеширане. Затова никога не използвайте отложени функции в шаблон на компонент (по-конкретно във файловете result_modifier.php и template.php). Ако все пак трябва да използвате отложени функции, можете да ги извикате във файла component_epilog.php на шаблона, т.к. неговото извикване не се кешира.

Двигател за кеширане в Bitrix

Компонентите не са единственото нещо в Bitrix. Съответно всичко това също се нуждае от кеширане. В Bitrix има специален клас за това - CPHPCache. Това е обвивка над други видове кеширане, поддържани от Bitrix (APC, Memcached, файлов кеш). Съхранението за кеша се задава в настройките на Bitrix.

Използването му е изключително просто:

Този клас може също да кешира html изход. За да започнете HTML кеширане, трябва да извикате метода StartDataCache(). Можете да използвате метода Output(), за да изведете запазения html. Нека прецизираме нашия пример:

Повече подробности за класа за кеширане можете да намерите на страниците с документация.

HTML кеширане (или съставно)

В Bitrix отдавна има възможносткеширане на цели страници. Същността на механизма е глупаво да запазите генерираната страница в html формат и при следващи посещения да дадете точно запазения html, без да зареждате базата данни и без да изпълнявате кода. Доскоро обаче тази технология имаше леки проблеми, вкл. и актуализиране на данни. Данните в кеша се актуализират твърде често или изобщо не се актуализират, до голяма степен поради липса на разбиране на технологията от разработчиците. Поради това често можете да видите този механизъм деактивиран на сайта.

HTML кеширането беше заменено от технологията Composite Site. Всъщност това е същото нещо, само че в нова обвивка и с малко подобрена и по-сложна функционалност. Идеята е да запазите страницата в html и да върнете този html при следващия достъп до нея и за да запазите данните на страницата, подходящи за потребителя, след зареждане в асинхронен режим се правят ajax заявки, които изтеглят данните в динамични блокове (като кошницата на потребителя или произволен блок със списък с нови продукти).

Благодарение на тази технология скоростта на изпращане на html код от сървъра може да достигне 10 ms, което по принцип е много бързо (Google препоръчва изобразяване на цялото съдържание до 200 ms, т.е. това е 20 пъти по-бързо от препоръките на Google).

Когато настройвате композитния режим, трябва да направите много, но рутинна работа. В повечето случаи е просто, но понякога трябва да си набиете мозъка. Тази работа се свежда до финализиране на кода на шаблона на компонента. За да може композитът да работи на сайта, е необходимо всички компоненти да „поддържат“ композитния режим на работа (или, както се казва в Bitrix, компонентите и шаблоните трябва да „гласуват“ за композитния режим). Самият компонент гласува "да" по подразбиране (с изключение на няколко стандартни компонента). Въпреки това шаблонът по подразбиране- против. Това се прави така, че самият разработчик да реши дали е възможно да настрои композит за конкретен шаблон, защото в по-голямата си част, когато работите с Bitrix, трябва да работите с шаблони. За да може шаблонът на компонента да гласува с „да“, трябва да извикате метода setFrameMode(), нещо подобно: