Apache Tomcat, разработен от Apache Software Foundation, е сървлет контейнер на Java с отворен код, който функционира и като уеб сървър. Докато над 10 000 уебсайта разчитат на Tomcat като уеб сървър, Plumbr на сървърите за приложения на Java показа, че над 60% от уебсайтовете, които използват Java технология, разчитат на Apache Tomcat за хостване на бизнес логиката.
Производствените среди трябва да са с висока производителност. Това изисква Apache Tomcat да бъде конфигуриран да се справя с максималното възможно натоварване и все пак да предоставя най-доброто време за реакция на потребителите. Производителността, която предоставя сървърът на приложения, често зависи от това колко добре е конфигуриран. Често предоставените настройки по подразбиране не са оптимални.
В eG Innovations нашето решение за мониторинг на производителността на eG Enterprise IT използва Apache Tomcat като уеб сървър. През годините открихме няколко съвета и трикове за конфигуриране на Tomcat за постигане на възможно най-високо ниво на скалируемост. Тази публикация в блога документира нашето обучение относно най-добрите практики, които трябва да използвате, когато внедрявате Tomcat в производство.
Първата стъпка към постигане на висока производителност е да се признае, че само настройката на сървъра за приложения Tomcat не е достатъчна. В крайна сметка Tomcat работи върху Java виртуална машина (JVM). Така че лошо конфигурирана JVM ще компрометира производителността. По същия начин JVM работи на операционна система и е важно да имате възможно най-добрата конфигурация на операционната система, за да постигнете възможно най-висока производителност. Дори тесните места в кода на приложението могат да доведат до оплаквания „Tomcat е бавен“. Като цяло трябва да се предприеме холистичен подход за настройка на производителността на Tomcat.
Настройката на производителността трябва да се извърши на всеки слой: операционната система, JVM, контейнера Tomcat и на ниво код на приложението
В следващите раздели ще представим най-добрите практики за конфигуриране на операционната система, JVM, контейнера Tomcat и кода на приложението за възможно най-добра производителност.
Тъй като Tomcat използва JVM, производителността на JVM също влияе върху производителността на Tomcat.
Преди да започнете да коригирате каквито и да било настройки, трябва да се уверите, че сте избрали модерна JVM за вашето приложение. Има много показатели, които показват 5-20% печалби в производителността от всяка версия на Java (вижте тази статия за повече подробности). Много JVM са налични в 32-битови и 64-битови режими. Докато 32-битовият режим е ограничен до 2 GB памет, 64-битовите JVM позволяват Java heap да бъде зададен много по-високо. Затова се уверете, че използвате 64-битова JVM за най-добра производителност и най-висока скалируемост.Събирането на боклук е процесът, чрез който Java програмите извършват автоматично управление на паметта. В миналото събирането на боклука се извършваше по принципа "спиране на света". Тоест, когато се случи събиране на боклук, приложението беше поставено на пауза, за да се възстанови паметта. Днес има много реализации за събиране на боклук, при които събирането на боклук се случва успоредно с изпълнението на приложението.
За най-добра производителност се уверете, че сте избрали модерен колектор за боклук като G1GC (Garbage First Garbage Collector) или Z Garbage Collector. Настройката MaxGCPauseMillis за JVM може да се използва за задаване на пиковото време на пауза, очаквано в средата. Препоръчва се тази стойност да бъде между 500-2000ms за най-добра производителност. Докато по-дългите паузи увеличават пропускателната способност, по-кратките паузи намаляват латентността и пропускателната способност. В допълнение към различните настройки на GC, наблюдавайте Tomcat сървъра в производство и се уверете, че процентът на времето, което JVM изразходва за събиране на боклук, е нисък. Всяка стойност над 5% ще бъде пагубна за производителността на Tomcat.Наличието на памет в JVM също може да повлияе неблагоприятно на производителността на Tomcat.
Трябва да се уверите, че е налична достатъчно памет във всички пулове на паметта на купчината и без паметта. Ако някой от пуловете памет изчерпва наличната памет, ще срещнете изключения OutOfMemory и приложението може да се провали по неочаквани начини. Използвайте флаговете Xmx и Xms на JVM, за да зададете максималния размер на купчината и размера на стека, и флаговете XX, за да зададете PermSize или MetaspaceSize в зависимост от използваната версия на JRE (прочетете тази статия за допълнителна справка).Уверете се, че наличната памет за всеки от пуловете памет на JVM е достатъчна. Недостигът на памет ще повлияе неблагоприятно на производителността на Tomcat сървъра.
Задаването на ограниченията на паметта често е процес на проба и грешка. Задаването на ограниченията на паметта да бъдат твърде ниски може да доведе до изключения, докато задаването им на твърде високи може да доведе до загуба на ресурси. Използвайте инструмент за наблюдение на JVM и анализирайте производителността през седмица или повече, като вземете предвид и пиковите часове, за да определите оптималните стойности на пуловете памет на JVM.Ако паметта нараства неограничено в JVM, ще трябва да определите дали има памет теч в приложението.
Направете дъмп на паметта с помощта на вградени инструменти на Java като JvisualVM и Jconsole. Използвайте инструменти като Eclipse Memory Analyzer (MAT), за да определите подозрителни течове на памет. Dominator Tree на MAT ще ви помогне да стесните нишките/обектите, които причиняват изтичане на памет.Накрая, проследете активността на нишките в JVM.
Докато всички нишки в JVM трябва да се проследяват, за да се открият изтичания на нишки, важно е да се проследяват блоковете на нишките и блокиранията, тъй като те са вредни за производителността. Проследяването на стека на блокиращи нишки и блокирани нишки може да разкрие проблеми на ниво код на приложението.Идентифициране на блокове на нишки и блокирания, причиняващи спиране на приложението
В допълнение, наблюдавайте използването на процесора на отделни нишки, за да откриете избягали нишки, които заемат процесора, забавяйки Tomcat. Отново всеки инструмент за наблюдение на ниво JVM може да предостави тези прозрения. В някои случаи фоновите нишки на приложение може да отнемат прекомерни ресурси. Като наблюдавате активността на нишката, можете да определите такива сценарии и дори да определите реда от код/метода, който причинява проблема.Както е случаят с JVM, много скалируемост и са направени подобрения в сигурността с най-новите версии. Затова се уверете, че използвате най-новата версия на Tomcat. В момента Tomcat 9 е най-новата версия.
Конфигурационният файл server.xml на Tomcat включва няколко елемента, които могат да бъдат променени, за да се подобри производителността на Tomcat.
Конфигуриране на конекторите
Това са елементи, които позволяват на Tomcat да получава заявки от клиенти. Едно копие на конектор слуша за заявки на конкретен номер на TCP порт на сървър.
Ако във вашия Tomcat сървър идват различни типове натоварвания, трябва да обмислите наличието на множество конектори – така че един тип трафик се обработва на един порт, а вторият тип на друг порт. Това намалява промените, които различните видове натоварвания могат да си пречат.Всяка входяща заявка се обработва от нишка в Tomcat. Атрибутът maxThreads на конектор дефинира максималния брой едновременни нишки, които могат да се изпълняват за конектор. Броят на едновременно изпълняваните нишки зависи от хардуера и броя на процесорите, които има. Колкото по-добър е хардуерът и по-голям е броят на процесорите, толкова по-голяма паралелност ще трябва да поддържа Tomcat.
Ако атрибутът maxThreads е зададен твърде ниско, заявките ще трябва да изчакат, докато нишката стане достъпна за обработка на заявката. Това може да увеличи времето за реакция, виждано от потребителите. Следователно, за най-добра производителност, задайте maxThreads на достатъчно висока стойност, така че нишките да са винаги налични в Tomcat за обработка на входящи заявки.Атрибути на конектор Tomcat
От гледна точка на наблюдение е важно да наблюдавате броя на нишките, активни в пула от нишки на всеки конектор. Ако броят на активните нишки е близо до ограничението за maxThreads, трябва да помислите за настройка на конфигурацията на сървъра Tomcat, за да позволите по-голям пул от нишки за конектора.
Изборът на протокола на конектора за обработка на входящи заявки също влияе върху пропускателната способност на сървъра Tomcat. Например Tomcat 9 поддържа блокиращи и неблокиращи конектори. Вижте тази сравнителна таблица.
С блокиращ конектор, при който всяка работна нишка се използва, докато свързаната с нея връзка бъде завършена. Неблокиращият конектор обаче води до по-добро управление на нишки с по-дълго изпълнявани заявки. Тестовете за производителност показват, че неблокиращият конектор осигурява по-добра производителност при по-дълго изпълнявани заявки.
Обмислете използването на неблокиращи конектори, тъй като това осигурява по-голяма производителност.Настройката enableLookups за конектор определя дали Tomcat сървърът извършва обратно търсене в DNS, за да намери името на хоста на всеки отдалечен клиент.
DNS търсенията са скъпи и ако тази стойност е зададена на true, забавянето на DNS услугата може да накара да изглежда, че Tomcat е бавен. Следователно, за най-добра производителност, задайте enableLookups на false за всички използвани конектори.Друга важна настройка на конектора е acceptCount. Това е максималната дължина на опашката за приемане, където се поставят заявки, докато чакат нишка за обработка. Когато опашката за приемане е пълна, допълнителните входящи заявки ще бъдат отказвани. Стойността по подразбиране от 100 е неадекватна за типични производствени натоварвания.
Следователно, за най-добра производителност, задайте acceptCount трябва да бъде достатъчно голям, за да поеме пакета от входящи връзки, които сървърът може да получи. Ако acceptCount е твърде нисък, клиентите ще видят грешки „отказана връзка“. Ако стойността е твърде висока, опашката ще заеме допълнителна памет на сървъра.Когато използвате конекторите NIO и NIO2, можете да конфигурирате размера на буферите за четене и запис на сокета, използвани от Tomcat. Атрибутите socket.rxBufSize и socket.txBufSize управляват настройката за размера на буфера.
Колкото по-голяма е стойността на socket.rxBufSize и socket.txBufSize, толкова по-висока е поддържаната пропускателна способност. Помислете за настройки от 64KB или по-високи за тези стойности.Често може да имате клиенти, свързващи се през WAN връзки към сървъра Tomcat. Атрибутът за компресиране контролира дали Tomcat компресира съдържание, когато го изпраща на клиенти.
Задайте този атрибут на „включено“ за най-добра производителност. Тогава се използва GZIP компресия. Типовете съдържание, които трябва да бъдат компресирани, са предоставени в compressibleMimeType.Всяка комуникация между клиента и сървъра, която е предимно текст, било то HTML, XML или просто Unicode, може редовно да бъде компресирана до 90 % с помощта на прост и стандартен GZIP алгоритъм. Това може да има огромно въздействие върху намаляването на мрежовия трафик, позволявайки отговорите да се изпращат обратно към клиента много по-бързо, като в същото време позволява повече мрежова честотна лента да бъде достъпна за други тежки мрежови приложения.
Използване на изпълнители
Когато използвате конектори, набор от нишки е предназначен за всеки конектор. Ако използвате множество конектори, можете да конфигурирате изпълнител. Изпълнителят е общ пул от нишки, който може да се споделя от множество конектори. Това не само позволява по-добро споделяне на нишки между конектори, но също така осигурява механизъм за намаляване на броя на нишките в пула, ако входящото работно натоварване не изисква тези нишки за обработка. Когато използвате пул от нишки за конектор, Tomcat не възстановява нишки в пула, така че ако видите голям поток от заявки веднъж, това може да увеличи броя на нишките в пула за целия живот на сървъра Tomcat. Когато използвате изпълнител, настройката maxThreads се дефинира на ниво изпълнител. В такъв случай администраторите на Tomcat трябва да наблюдават активността и използването на пула от нишки на ниво изпълнител, а не на ниво конектор.
Конфигуриране на публични SSL сертификати
Ако вашият конектор е активиран за SSL, уверете се, че сте го конфигурирали с валиден публичен SSL сертификат.Проверете този блог, за да разберете въздействието върху производителността, което неправилната конфигурация на SSL сертификат може да има върху производителността на Tomcat.
Настройте настройките за кеширане на ресурси
За подобряване на производителността Tomcat е конфигуриран по подразбиране да кешира статични ресурси. Размерът на кеша обаче трябва да бъде конфигуриран да бъде достатъчно голям, за да осигури спестяване на производителност.
За да настроите настройките на кеша на Tomcat, намерете директивата Context (в server.xml или context.xml) и задайте атрибута cacheMaxSize на подходящата стойност.Обединяване на връзки към база данни
Отварянето на връзка към базата данни е скъпо. Пулирането на връзки е често срещана техника за оптимизиране на достъпа до базата данни чрез наличие на пул от отворени връзки, така че заявките да могат да приемат връзки от пула и да връщат връзки обратно към пула, след като приключат със задачите си. Като не се налага да създавате и прекъсвате връзки за всяка заявка, обединяването на връзки позволява отговорът на приложението да бъде по-бърз и намалява излишните разходи за обработка на връзката на сървъра на базата данни. Tomcat има вградена поддръжка за обединяване на връзки към бази данни.
Както в случая с пулове от нишки, уверете се, че настройката maxActive на пула за връзки към базата данни, която определя дали максималният брой активни връзки в пула е достатъчно голям, за да поеме натоварването, което обработва. Наблюдавайте използването на пула за връзки към базата данни, защото ако връзката пулът е напълно използван, новите заявки ще чакат свободните връзки да бъдат налични, което води до увеличаване на времето за отговор.Оптимизации на Web.xml
Файлът server.xml се използва за указване на специфични за сървъра конфигурации. Има само един server.xml за всеки екземпляр на Tomcat сървър. Файлът web.xml се използва за указване на специфични за уеб приложението конфигурации. Има един файл web.xml за всяко уеб приложение, разположено на сървъра Tomcat. Настройките по подразбиране, наследени от всички уеб приложения, се дефинират от файл web.xml в главната конфигурационна директория на Tomcat.
Стойностите на свойствата по подразбиране в този файл са настроени за среди за разработка и трябва да бъдат променени за производствени внедрявания. Настройката на компилатора на Java Server Pages (JSP) има настройка за режим на разработка. Това е вярно по подразбиране. Променете това на false, за да избегнете често проверяване на JSP, за да видите дали е необходима повторна компилация. Предварително компилирайте JSP, за да избегнете натоварването на компилацията на производствените сървъри. По същия начин задайте genStringAsCharArray на „true“, за да създадете по-ефективни масиви от знаци. Задайте trimSpaces на „true“, за да премахнете ненужните байта от отговора.Неефективният код на приложението може също да причини забавяне на приложението, внедрено на Tomcat. Регистрирането е обичаен начин за проследяване на работата на приложението. Регистрирането в изходните файлове обаче е синхронизирана операция и прекомерното регистриране всъщност може да забави производителността на приложението.
Използвайте техники за проследяване на транзакции, които се основават на инструменти с байт-код, за да наблюдавате обработката на приложенията, без да са необходими промени в кода на приложението. Тези техники разчитат на специално създаден jar файл, който използва инструменталния API, който JVM предоставя, за да промени съществуващия байт-код, който е зареден в JVM.
ИТ екипите и разработчиците могат да използват тази възможност, за да навлизат в бавни транзакции и проактивно да откриват проблеми с производителността, преди да засегнат крайните потребители.
Разпределено проследяване на транзакции, използвано за идентифициране на проблеми на ниво код в уеб приложения, поддържани от Tomcat
Често може да чуете, че сървърите за приложения, базирани на Java, като Tomcat, са бавни или не са готови за производство. В този блог сме предоставили набор от най-добри практически конфигурации, за да извлечете максимума от вашия сървър за уеб приложения Tomcat. Нашето решение за мониторинг на производителността на приложения eG Enterprise използва Apache Tomcat като основен контейнерен двигател и е широко разпространено, за да поддържа мониторинг на десетки хиляди сървъри, десетки милиони показатели в реално време и над сто хиляди крайни потребители в производство. Така че можете да сте сигурни, че най-добрите практики, които сме предоставили тук, действително работят!
PREV: Какво представлява планът за поддръжка на сървъра и защо е важен...