|
Кеширането е особено наложително в големи интернет приложения с голям обем данни и интезивни заявки към базите данни. Кеширането на данните извлечени от базата данни в повечето случаи води до намаляване натоварването на сървъра и ускоряване на работата на приложението.
Файлов кеш Един от начините за кеширане е просто запазване на резултатите от SELECT заявките във файлове. Отварянето на файл и съответно десерелизирането на данните е значително по-бързо в сравнение с изпълнението на сложна SELECT заявка включваща голям брой таблици и релации. Следващия пример представлява опростена реализация на файлов кеш: CODE
Стратегии за формиране на ключа Кешираните данни се идентифицират по зададен ключ. Ключът трябва да бъде уникален в рамките на цялата система. Добра практика е използването на принципа на namespace. Например ако имаме клас за оторизация на потребителите наречен „UserAuth”, и всички потребители се идентифицират с число - идентификатор (id), то подходящ ключ би бил: „UserAuth:users:1234”, където 1234 е идентификатора на потребителя. Някои разсъждения за горния код Възможно е да се пропусне записването на времето на валидност на данните. Вместо това то да се подава като параметър при извличане на данните. Това дава възможност да се провери дали файла е валиден още преди да се отвори, като се използва функцията filemtime(). Това на пръв поглед изглежда чудесна идея, но така нарушаваме общия интерфейс за кеширане. Тоест, ако в последствие решим да използваме кеш в паметта, ще трябва навсякъде да променяме начина на използване на класа. Друга важна причина да запишем времето на валидност заедно с данните е тази, че това ни дава възможност да направим скрипт за „почистване” на кеша. Тоест изтриване на вече невалидните файлове. Как се използва този клас В едно web-приложение кеширането е подходящо най-вече при заявките към базата данни. Въпреки, че повечето SQL сървъри поддържат вътрешен кеш, който е напълно прозрачен, не винаги той се оказва оптималното решение. Причината е в това, че вътрешния кеш на сървъра не е съобразен с конкретната логика на вашето приложение. Следва пример, който извлича съдържанието на цялата таблица с информация за потребителите като използва описания по-горе клас. Ако няма валидни кеширани данни, функцията създава такива с валидност 10 минути: CODE
В примера за краткост са пропуснати проверките за грешка и се подразбира, че имаме отворена връзка с базата данни. Също така не е описана и самата таблица users. Какви проблеми можем да очакваме Първия проблем е че този клас така както е написан, ще работи само в Linux. Проблема е в това, че използваме „/tmp”. Можем вместо това да вземем от 'session.save_path' от php.ini. Също твърдото задаване на разделителя за директории е неуместно. Във Windows се използват обратно наклонени черти. Можем да направим функцията getFileName() универсална така: CODE
Следващия проблем е малко по-сложен. Нека си представим, че една инстанция на нашия клас започва да чете от кеша. Както знаете това става в отделна нишка. В следващия момент друга инстанция, активирана от друг потребител и съответно работеща в друга нишка също опитва да чете. Дотук няма нищо нередно. Но ако междувременно срока на валидност е изтекъл, втората нишка ще започне да записва - ето го и проблема. Ще се получи неочакван резултат. Сега проблема ни изглежда очевиден, но преди малко не всеки би се досетил за него. Това е сериозен и трудно откриваем бъг, тъй като на практика е малко вероятно да се случи. Има ли решение - да. PHP може да заключва файлове за чрез функцията flock(). Заключването работи с отворен чрез fopen() файл и има 2 режима:
В следващия пример е показано как с тези 2 възможности се решава конфликта с едновременния достъп до файла (коментирани са само промените): CODE
Всъщност добавихме само 3 реда код. Следващия проблем е синхронизацията на кеша с реалните данни от таблицата (или заявката в общия случай). Необходимо е при промяна на данните в базата, кеша да се синхронизира. Най-лесния начин е да изтрием файла, а следващият опит за четене от кеша ще го създаде с вече синхронизирани данни. Тоест, трябва ни метод за изтриване: CODE
Сега нека да си припомним обектно-ориентирания подход Добре е да дефинираме интерфейс, който се имплементира от различните варианти на кеширане. Така ще гарантираме еднотипно използване на различните видове кеш, или иначе казано ще можем да променяме лесно вида на използвания кеш според обстоятелствата. Нека да дефинираме абстрактен клас, който съдържа само 3-те задължителни метода. Този клас в последствие ще се наследява от различните реализации на кеширане: CODE
Сега да променим класа FileCache: CODE
Ето, че имаме завършен клас за файлов кеш.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||









