Модуль Apache MPM расшифровывается как Apache Multi-Processing Module, что в переводе означает «Модуль мультипроцессовой обработки». Обычно по-умолчанию в Apache используется модуль MPM prefork .

Определить, какой именно менно модуль Apache MPM используется, можно следующей командой:

Httpd -V | grep mpm -D APACHE_MPM_DIR=»server/mpm/prefork»

Или на системах, подобных Debian, где сервер называется apache2 :

Apache2 -V | grep mpm -D APACHE_MPM_DIR="server/mpm/prefork"

Рассмотрим настройку параметров модуля Apache MPM prefork , исходя из объема оперативной памяти на хосте. Определим средний размер памяти, занимаемый одним процессом Apache:

Ps -ylC httpd | awk "{x += $8;y += 1} END {print "Apache Memory Usage (MB): \ "x/1024; print "Average Proccess Size (MB): "x/((y-1)*1024)}"

На системах, где сервер Apache представлен демоном apache2 , замените в строке httpd на apache2 .

Команда покажет общий объем памяти, потребляемой всеми процессами Apache и средний объем памяти на один процесс. Примеры:

В дистрибутивах, подобных Debian:

User@debian:~$ ps -ylC apache2 | awk "{x += $8;y += 1} \ END {print "Apache Memory Usage (MB): "x/1024; \ print "Average Proccess Size (MB): "x/((y-1)*1024)}" Apache Memory Usage (MB): 231.531 Average Proccess Size (MB): 13.6195

Лучше эту команду выполнить несколько раз, и желательно тогда, когда ваш сервер будет находиться под максимальной нагрузкой, чтобы определить средние значения под нагрузкой.

Теперь, зная средний объем памяти, используемый сервером Apache, и зная объем физической памяти, можно вычислить значение MaxClients , которое задается в файле конфигурации сервера Apache httpd.conf .

Допустим, на вашем VPS или VDS сервере 1 Гб оперативной памяти, и вы хотите оставить 512 Мб для остальных процессов, отдав серверу Apache 512 Мб.

Предыдущая команда выдала результаты:

# ps -ylC httpd | awk "{x += $8;y += 1} \ END {print "Apache Memory Usage (MB): "x/1024; \ print "Average Proccess Size (MB): "x/((y-1)*1024)}" Apache Memory Usage (MB): 64.3789 Average Proccess Size (MB): 10.7298

Т.е. на один процесс Apache в среднем уходит 10 Мб памяти. Определим значение MaxClients:

MaxClients = Весь объем памяти для Apache / Объем памяти на один процесс

MaxClients = 512 Мб / 10 МБ = 50.

Теперь мы знаем самое важное значение параметра модуля Apache MPM prefork , задающее максимальное число дочерних процессов таким, чтобы не была "съедена" вся оперативная память, а только часть ее (в нашем примере - половина, равная 512 Мб).

Внесем данные в файл настроки модуля Apache MPM prefork, обычно располагающийся по пути /etc/httpd/conf/httpd.conf :

StartServers 2 MinSpareServers 2 MaxSpareServers 5 MaxClients 50 ServerLimit 50 MaxRequestsPerChild 100 KeepAlive Off

Краткое описание параметров модуля Apache MPM Prefork:

StartServers - число дочерних процессов, создаваемых при запуске сервера.

MinSpareServers - минимальное число неиспользуемых (запасных) дочерних процессов сервера, ожидающих потенциальные запросы.

MaxSpareServers — максимальное число запасных процессов, ожидающих потенциальные запросы. Если это число будет превышено, лишние процессы будут убиты.

MaxClients — самый важный параметр модуля MPM prefork, устанавливает верхний предел количества одновременно активных процессов. Именно от него зависит потребление памяти. Его значение перекрывает значение предыдущих параметров.

ServerLimit обычно равен MaxClients.

MaxRequestsPerChild - как часто сервер перерабатывает процессы, убивая старые и начиная (запуская) новые. Полезен при утечках памяти Apache и его библиотек.

KeepAlive - обеспечивает долгоживущие сессии HTTP, позволяющие отправлять несколько запросов через одно и то же соединение. Полезно включить, если страницы содержат много изображений.

Также есть хороший скрипт check_httpd_limits.pl , написанный на Perl, позволяющий определить, сколько памяти занимают процессы сервера Apache . Скрипт выдает предупреждения (или ошибки), если установленные в конфигурации Apache пределы памяти превышают размеры доступной памяти на сервере.



что замедляет работу Apache и как получить максимум от PHP?

Приложения, использующие архитектуру LAMP (Linux, Apache, MySQL, PHP/Perl), постоянно совершенствуются и все шире используются. Но системный администратор часто не имеет полного контроля за самими приложениями, поскольку они написаны кем-то другим. Эта статья сфокусирована на действиях, которые вы можете выполнить для оптимизации Apache и PHP.

настройка Apache

Apache - часть программного обеспечения, легко поддающаяся настройке. Он имеет множество функций, и каждая является ценной. Настройка Apache отчасти состоит в надлежащем распределении ресурсов и подразумевает отключение ненужных настроек.

конфигурирование мультипроцессорных модулей

Приложение Apache является модульным, в том смысле, что вы легко можете добавлять и удалять его элементы. Эту модульную функциональность в ядре Apache - управление сетевыми соединениями и отправку запросов - обеспечивают мультипроцессорные модули (Multi-Processing Modules, MPM). Модули позволяют вам использовать потоки или даже перемещать Apache в другую операционную систему.

Одновременно может быть активен только один мультипроцессорный модуль и он должен быть скомпилирован статически при помощи --with-
mpm=(worker|prefork|event).

Традиционная модель "один процесс на запрос" назвается prefork. Более новая, модель с потоками (thread), называемая worker, использует несколько процессов, каждый с несколькими потоками, для получения более высокой производительности при более низких накладных расходах. Наконец, event - экспериментальный модуль, который содержит особые группы потоков для различных задач. Чтобы определить, какой мультипроцессорный модуль вы сейчас используете, выполните

Выбор мультипроцессорного модуля зависит от многих факторов. Отключение модуля event до тех пор, пока он имеет экспериментальный статус, -- это выбор между потоками и их отсутствием. Внешне кажется, что использовать потоки лучше, чем использовать fork, если все основные модули являются безопасными потоками, включая все используемые PHP-библиотеки. Prefork - более безопасный выбор; если вы выбрали worker, вы должны провести тщательное тестирование. Рост производительности также зависит от входящих в дистрибутив библиотек и вашего оборудования.

Независимо от того, какой мультипроцессорный модуль вы выбрали, вы должны соответствующим образом сконфигурировать его. Вообще, конфигурирование модуля подразумевает определение, как Apache контролирует количество запущенных worker"ов, являются ли они потоками или процессами. Ниже показаны важные опции конфигурирования модуля prefork.

StartServers 50
MinSpareServers 15
MaxSpareServers 30
MaxClients 225
MaxRequestsPerChild 4000

В модуле prefork новый процесс создан при помощи запроса. Резервные процессы простаивают, чтобы общаться с поступающими запросами, что уменьшает время ожидания запуска. Предыдущая конфигурация запускает 50 процессов, как только стартует веб-сервер, и старается поддерживать в наличии от 10 до 20 простаивающих запущенных серверов. Жесткий лимит процессов определяется при помощи MaxClients. Даже если процесс может общаться с множеством последовательных запросов, Apache убивает процессы после 4000 соединений, что уменьшает риск утечки памяти.

Конфигурирование мультипроцессорных модулей с поддержкой потоков производится подобным образом, за исключением того, что вы должны определить, сколько потоков и процессов должно использоваться. Документация Apache дает разъяснения по всем параметрам и необходимым расчетам.

Выбор используемых значений подразумевает некий метод проб и ошибок. Наиболее важное значение - MaxClients. Цель состоит в том, чтобы разрешить достаточное количество процессов worker или потоков, чтобы сервер не занимался исключительно свопингом. Если поступает больше запросов, чем может быть обработано, то по крайней мере те, которые поступили, обрабатываются; другие блокируются.

Если MaxClients слишком высок, все клиенты получают недостаточно высокий уровень сервиса, поскольку веб-сервер пробует выгрузить один процесс, чтобы позволить выполняться другому. Установка слишком низкого значения приводит к тому, что вы можете необоснованно отказать в обслуживании. Проверка количества процессов, запущенных в момент повышенной нагрузки, и анализ объема памяти, используемой всеми процессами Apache, дает вам хорошую идею относительно установки этого значения. Если вы устанавливаете значение MaxClients выше 256, вы должны установить то же значение для ServerLimit; внимательно прочтите документацию по мультипроцессорным модулям, чтобы узнать о соответствующих предостережениях.

Настройка числа запускаемых серверов и наличие запасных зависит от роли сервера. Если на сервере выполняется только Apache, вы можете поставить невысокое значение, поскольку вы можете использовать машину в полной мере. Если система используется еще и базой данных или другим сервером, вы должны ограничить число запасных запущенных серверов.

эффективное применение опций и переопределений

Каждый запрос, который обрабатывает Apache, проходит через сложный набор правил, которые диктуют любые ограничения или специальные инструкции, которым должен следовать веб-сервер. Доступ к папке может быть ограничен IP-адресом для определенной папки, или могут быть сконфигурированы имя пользователя и пароль. Эти опции также включают обработку определенных файлов, например, если предоставляется листинг каталога, они определяют, как будут обрабатываться определенные типы файлов, или должен ли быть сжат вывод.

Эти конфигурации имеют вид контейнеров в httpd.conf, например, определяет, что конфигурация обращается к местоположению на диске, или задает отсылку на путь, указанный в URL. В качестве примера покажем контейнер Directory, применяемый к каталогу root


AllowOverride None
Options FollowSymLinks

Эта конфигурация, ограниченная тегами и , применяется к данному каталогу и его содержимому - в этом случае к каталогу root. Здесь тег AllowOverride определяет, что пользователям не разрешается отменять любые опции (более подробно об этом позже). Опция FollowSymLinks разрешена, что позволяет Apache видеть прошлые символьные линки для обслуживания запроса, даже если файл не входит в каталог, содержащий веб-файлы. Это означает, что если файл в вашем веб-каталоге является символьным линком на /etc/passwd, веб-сервер успешно обслужит файл, если поступит запрос. Использование -FollowSymLinks отключит эту возможность, и тот же самый запрос будет причиной возврата ошибки клиенту.

Последний сценарий - повод для беспокойства на двух фронтах. Первый - вопрос производительности. Если FollowSymLinks отключен, Apache должен проверять каждый компонент имени файла (каталоги и собственно файл), чтобы убедиться, что они не являются символьными линками. Это влечет дополнительные накладные расходы в форме нагрузки на диск. Сопутствующая опция FollowSymLinksIfOwnerMatch следует за символьным линком, если владелец файла тот же, что и владелец линка. Это оказывает такое же воздействие на производительность, как и отключение следования символьным линкам. Для наилучшей производительности используйте опции, приведенные выше.

Читатели, которых волнуют вопросы безопасности, уже должны быть обеспокоены. Безопасность - всегда компромисс между функциональностью и риском. В этом случае функциональность - это скорость, и риск предполагает неавторизованный доступ к файлам системы. Смягчающим фактором является то, что серверы приложений LAMP обычно предназначены для определенной функции, и пользователи не могут создавать потенциально опасные символьные линки. Если жизненно необходимо разрешить проверку символьной ссылки, вы можете разрешить это только в определенной области файловой системы:


Options FollowSymLinks


Options -FollowSymLinks

Теперь любой каталог public_html в домашнем каталоге пользователя имеет опцию FollowSymLinks, отключенную для этого и всех вложенных каталогов. Как вы видели, опции могут конфигурироваться на покаталожной основе через конфигурацию главного сервера. Пользователи могут самостоятельно отменить конфигурацию сервера (если администратором разрешено AllowOverride) через файл.htaccess. Этот файл содержит дополнительные директивы сервера, которые загружаются и применяются к каждому запросу каталога, в котором содержится файл.htaccess.

Несмотря на то, что директива AllowOverride препятствует пользователям в совершении тех действий, которые вы хотите им запретить, Apache по- прежнему должен искать файл.htaccess, чтобы выяснить, нужно ли что-нибудь сделать. Родительский каталог может определить директивы, которые должны быть обработаны запросом дочернего каталога, что означает, что Apache должен также исследовать каждый компонент дерева каталогов, ведущий к запрашиваемому файлу. По понятным причинам это является причиной высокой дисковой активности по каждому запросу.

Самое простое решение - не позволять любые переопределения, которые отменяют необходимость проверки Apache файла.htaccess. Любые специальные конфигурации затем помещаются непосредственно в httpd.conf. Ниже показано, что нужно добавить в httpd.conf, чтобы позволить проверку пароля для пользовательского каталога project, вместо того чтобы помещать информацию в файл.htaccess и надеяться на AllowOverride.


AuthUserFile /home/user/.htpasswd
AuthName "uber secret project"
AuthType basic
Require valid-user

Если конфигурация помещена в httpd.conf и AllowOverride отключен, интенсивность использования диска может уменьшиться. Каталог пользователя project может не привлечь большого количества обращений, но учитывайте мощь этого метода применительно к сайту, работающему с большой нагрузкой. Иногда невозможно исключить использование файлов.htaccess. в следующем примере выбор ограничен определенной частью файловой системы; возможность отмены также может быть ограничена.


AllowOverrides None


AllowOverrides AuthConfig

Теперь Apache все же ищет файлы.htaccess в родительском каталоге, но прекращает поиск в каталоге public_html. Например, если запрашивается файл /home/user/public_html/project/notes.html, то его успешное отображение произойдет только в том случае, если каталоги public_html и project будут найдены.

Уместно сделать одно последнее замечание относительно относящихся к отдельным каталогам конфигураций. Любой документ о настройке Apache дает указание запретить DNS lookup через директиву HostnameLookups off, поскольку попытки обратно разрешить соединения всех IP-адресов с вашим сервером - излишняя трата ресурсов. Однако любые ограничения, базирующиеся на имени хоста, вынуждают веб-север выполнять обратный lookup на IP- адресе клиента и прямой lookup на основании результата проверки подлинности имени. Поэтому благоразумно избегать использования средств контроля доступа, базирующихся на имени хоста, и, когда они необходимы, проверять их, как описано.

постоянные соединения

Когда клиент соединяется с веб-сервером, разрешается порождение множественных запросов по одному и тому же TCP-соединению, что уменьшает время ожидания, связанное с многократными соединениями. Это полезно, когда веб-страница содержит несколько изображений: клиент может запросить страницу и затем все изображения в течение одного соединения. Обратная сторона состоит в том, что процесс worker на сервере должен ожидать закрытия сеанса клиентом, прежде чем он сможет перейти к следующему запросу.

Apache позволяет вам определять, как будут обработаны постоянные соединения, называемые keepalives. KeepAlive 5 на глобальном уровне httpd.conf позволяет серверу обработать 5 запросов на соединение, прежде чем соединение будет насильственно прервано. Установка этого числа в 0 запретит использование постоянных соединений. KeepAliveTimeout, тоже на глобальном уровне, определяет, как долго Apache будет ожидать другого запроса, прежде чем сессия закроется.

Обработка постоянных соединений не является конфигурацией типа "один-размер-годится всем". Некоторые веб-сайты функционируют лучше, если keepalives запрещены (KeepAlive 0), а в некоторых случаях их включение может принести огромную пользу. Единственное решение - попробовать оба варианта и выяснить все самостоятельно. Тем не менее, разумно использовать низкий таймаут, например, 2 секунды, при помощи KeepAliveTimeout 2, если вы разрешили keepalives. Это даст гарантии, что любой клиент, желающий сделать другой запрос, будет иметь достаточное количество времени, и что процессы worker не останутся без работы, пока будут ждать другого запроса, который может никогда не поступить.

сжатие

Веб-сервер может сжимать вывод, прежде чем возвратить его клиенту. В результате уменьшается объем страницы, посылаемой по Интернету, но все это - за счет циклов CPU на веб-сервере. Для тех серверов, которые могут позволить себе высокую нагрузку на CPU, это отличный способ создания быстро загружаемых страниц - размер страницы может после сжатия уменьшиться втрое.

Изображения обычно уже сжаты, поэтому необходимо сжимать только текстовый вывод. Apache предусматривает сжатие при помощи mod_deflate. Несмотря на то, что mod_deflate может быть просто отключен, он содержит множество сложных моментов, которые описаны в соответствующей документации.

настройка PHP

PHP - движок, который запускает код приложений. Вы должны установить только модули, которые планируете использовать, и сконфигурировать ваш веб- сервер для использования PHP только для файлов скриптов (обычно те файлы, названия которых заканчиваются на.php) а не всех статических файлов.

кеширование кода операции

Когда запрашивается скрипт, PHP читает его и собирает в то, что называется код операции Zend, бинарное представление кода, который будет выполнен. Этот код операции затем выполняется движком PHP и теряется. Кэш кода операции сохраняет его и в следующий раз при запросе страницы вновь использует. Это экономит немало времени. Доступно несколько реализаций кэша кода операции доступны; я успешно использовал eAccelerator. Инсталляция eAccelerator требует наличия в компьютере библиотек разработки PHP. Поскольку разные дистрибутивы Linux помещают файлы в разные места, получите инструкции по инсталляции непосредственно с веб-сайта eAccelerator"а. Также возможно, что ваш дистрибутив уже содержит нужный софт, и вы должны просто установить соответствующий пакет.

Независимо от того, каким образом вы установили на своей системе eAccelerator, есть несколько вариантов конфигурации. Конфигурационным файлом обычно бывает /etc/php.d/eaccelerator.ini. Директива eaccelerator.shm_size определяет размер кэша совместно используемой памяти, где хранятся скомпилированные скрипты. Значение измеряется в мегабайтах. Определение подходящего размера зависит от приложения. eAccelerator предоставляет скрипт для показа статуса кэша, который включает использование памяти; 64 мегабайта - хорошее значение для начала:

Eaccelerator.shm_size="64"

Вы также можете настроить максимальный размер для shared memory, если выбранное вами значение не было принято. Добавьте

Kernel.shmmax=67108864

в /etc/sysctl.conf и запустите sysctl -p, чтобы настройки вступили в силу. Значение kernel.shmmax измеряется в байтах.

Если превышен объем выделяемой shared memory, eAccelerator должен удалить из памяти старые скрипты. По умолчанию это отключено. Директива

Eaccelerator.shm_ttl = "60"

устанавливает, что когда eAccelerator исчерпывает размер shared memory, любой скрипт, доступ к которому не был получен в течение 60 секунд, должен быть удален.

Другая популярная альтернатива eAccelerator -- Alternative PHP Cache (APC). Создатели Zend также имеют коммерческий кэш кода операции, включающий оптимизатор для дальнейшего повышения эффективности.

Вы конфигурируете PHP в php.ini. Четыре важных параметра настройки определяют, какое количество системных ресурсов может потреблять PHP, как показано в таблице 1.

Таблица 1. Параметры настройки php.ini, связанные с ресурсами.

Размер этих значений обычно зависит от приложения. Если вы принимаете от пользователей большие файлы, max_input_time может быть увеличен или в php.ini, или путем его переопределения в коде. Подобным образом, для программ, потребляющих большое количество CPU или памяти могут потребоваться более высокие значения. Цель состоит в том, чтобы уменьшить воздействие "прожорливой" программы, поэтому глобальная отмена этих настроек не рекомендуется. Другое замечание относительно max_execution_time: это относится ко времени, затраченному CPU на процесс, а не к абсолютному времени. Таким образом, программа, совершающая большое количество вводов/выводов и небольшое количество вычислений, может выполняться намного дольше, чем max_execution_time. max_input_time также может быть больше, чем max_execution_time.

Количество записей лога, которые может сделать PHP, может настраиваться. В продакшне экономят место на диске, отменяя все журналы, кроме самых критических. Если журналы необходимы для диагностики проблем, вы можете вернуть то журналирование, которое необходимо. Директива

Error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR

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

заключение

Эта статья сфокусирована на настройке веб-сервера, как Apache, так и PHP. С Apache главная идея состоит в том, чтобы исключить лишние проверки, которые должен делать веб-сервер, например, обработку файла.htaccess. Вы также должны настроить мультипроцесорный модуль (MPM), который позволит сбалансировать используемые системные ресурсы и простаивающие worker"ы для входящих запросов. Лучшее, что вы можете сделать для PHP - установить кэш кода операции. Наблюдение за несколькими параметрами настройки ресурсов также гарантирует, что скрипты не завладеют ресурсами и не замедлят работу системы.

Шон Волберг, старший сетевой инженер, P.Eng

Обработка файлов.xls с помощью Apache POI

В ходе работы над различными программными продуктами часто возникает необходимость импорта и экспорта данных из различных "закрытых" форматов файлов. Чаще всего эта необходимость возникает применительно к файлам в форматах офисных продуктов корпорации Microsoft, в частности Word (doc, docx) и Excel (xls, xlsx). В силу особенностей реализации этих форматов, реализация такой обработки "в лоб" целиком своими силами была бы весьма нетривиальной и достаточно трудоёмкой задачей. К счастью, основная часть работы уже сделана за нас - существуют открытые Java-библиотеки, позволяющие преобразовать эти файлы в объектную модель Java, после чего получение из них необходимой нам информации не составит особого труда. В этой заметке показан пример реализации такой выборки данных из документа.xls с помощью Apache POI (на примере версии 3.6) - популярной библиотеки от Apache Software Foundation.

Из чего состоит документ Excel

Для начала, определимся с терминологией. Документ Excel (workbook ) состоит из одного или более листов (или вкладок, в оригинале - sheets ). Каждый лист представляет из себя матрицу из m строк (rows ) по n ячеек (cells ) в каждой. Максимальные размерности m и n различаются для разных версий Excel. В API POI каждому из структурных элементов файла Excel соответствует свой базовый интерфейс и его реализации для документов.xls и.xls, а работа с файловой системой осуществляется посредством класса org.apache.poi.poifs.filesystem.POIFSFileSystem .

Обратите внимание, что для страницы в документе Excel 2007 (.xlsx) существует сразу 3 реализации - помимо "общего" класса XSSFSheet добавлены XSSDialogSheet (страница-диалог) и XSSFChartSheet (страница, содержащая только график).

Алгоритм обработки

Таким образом, в общем случае, обработка документа Excel сводится к последовательному перебору ячеек и строк на каждой его странице. Значение каждой ячейки может быть преобразовано к нужному нам типу (строка, число, дата и т.д.) посредством методов, описанных в интерфейсе Cell и его реализациях.

Тип данных Метод Комментарий
CELL_TYPE_BLANK нет Используется для проверки того, пуста ли ячейка
CELL_TYPE_NUMERIC Возвращает long
Возвращает Date
CELL_TYPE_STRING Возвращает простую строку
Используется для отформатированных строк. Возвращает RichTextString
Используется для получения гиперссылок. Возвращает Hyperlink
CELL_TYPE_FORMULA getCellFormula () Возвращает строку, содержащую формулу, в соответствии с которой формируется значение ячейки
CELL_TYPE_BOOLEAN getBooleanCellValue () Возвращает boolean
CELL_TYPE_ERROR getErrorCellValue () Возвращает код ошибки (byte)

Если тип содержимого ячейки не совпадает с тем типом данных, к которому мы пытаемся его преобразовать, будет сгенерировано исключение. Какое именно - зависит от конкретных типов данных между которыми мы пытаемся осуществить преобразование. К примеру, при попытке получения числового значения из строковой ячейки, будет сгенерирован java.lang.IllegalStateException . Для того, чтобы избежать исключительной ситуации, можно заранее проверить, к какому типу относится содержимое конкретной ячейки - для этой цели существует метод getCellType(), объявленный всё в том же интерфейсе Cell.

Пример разбора файла

Теперь перейдём от теории к практике - рассмотрим на примере, как может выглядеть код простейшей программы на Java, получающей данные из документа xls посредством API Apache POI. Предположим, что мы хотим выбрать данные из некоего справочника контактной информации, который выглядит примерно так:

Таким образом, наш документ состоит из трёх столбцов - ФИО, Адрес и Телефон. Чтобы упростить задачу, создадим класс с теми же самыми полями, который будет хранить информацию о контактных лицах:

package com.tuneit.poi.sample; /* * Класс, предназначенный для хранения * перснональной информации контактного лица */ public class ContactPerson { private String name; //ФИО private String address; //Адрес private String phoneNumber; //Номер телефона //Getters & setters ... }

Это простейший POJO-класс, содержащий только поля (соответствующие столбцам нашего xls-документа) и get- и set-методы к ним (в листинге не приведены).

Теперь рассмотрим основной фрагмент кода - собственно, сам парсер содержимого документа:

public static final NAME_COLUMN_NUMBER = 0; //ФИО public static final ADDRESS_COLUMN_NUMBER = 1; //Адрес public static final PHONE_COLUMN_NUMBER = 2; //Телефон... public ListGetContacts(String path){ ListContacts = new ArrayList(); //Создаём пустой список контактов File addressDB = new File(path); //Переменная path содержит путь к документу в ФС POIFSFileSystem fileSystem = new POIFSFileSystem(addressDB); //Открываем документ HSSFWorkbook workBook = new HSSFWorkbook(fileSystem); // Получаем workbook HSSFSheet sheet = workBook.getSheetAt(0); // Проверяем только первую страницу Iterator rows = sheet.rowIterator(); // Перебираем все строки // Пропускаем "шапку" таблицы if (rows.hasNext()) { rows.next(); } // Перебираем все строки начиная со второй до тех пор, пока документ не закончится while (rows.hasNext()) { HSSFRow row = (HSSFRow) rows.next(); //Получаем ячейки из строки по номерам столбцов HSSFCell nameCell = row.getCell(NAME_COLUMN_NUMBER); //ФИО HSSFCell addressCell = row.getCell(ADDRESS_COLUMN_NUMBER); //Адрес HSSFCell phoneCell = row.getCell(PHONE_COLUMN_NUMBER); //Номер телефона // Если в первом столбце нет данных, то контакт не создаём if (nameCell != null) { Person person = new Person(); person.setName(nameCell.getStringCellValue()); //Получаем строковое значение из ячейки person.setAddress(""); //Адрес может не быть задан if (addressCell != null && !"".equals(addressCell.getStringCellValue())) { person.setAddress(addressCell.getStringCellValue()); //Адрес - строка } person.setPhone(""); //Телефон тоже может не быть задан if (phoneCell != null && !"".equals(phoneCell.getStringCellValue())) { person.setPhoneNumber(phoneCell.getStringCellValue()); // Телефон - тоже строка } contacts.add(person); //Добавляем контакт в список } } return contacts; }

Таким образом, на выходе приведённого выше метода мы получим коллекцию объектов класса Person, сформированных из данных исходного xls-файла. Разумеется, в случае решения более общей задачи - например, написания универсального обработчика xls-документов, логика программы усложнится, но её основа, скорее всего, останется прежней - всё тот же последовательный перебор всех строк таблицы.

Представляю вашему вниманию вторую статью из серии, посвященной процессу записи данных в СУБД Cassandra. В этот раз я планирую представить информацию о следующем компоненте — промежуточном кэше данных колоночных семейств.

Сразу же после помещения данных в Commit Log, информация также дублируется в структуру, называемую Memtable. Этот компонент имеет следующие свойства:

Теперь рассмотрим все подробнее. Чтобы лучше понять структуру Memtable, дополним иллюстрации из первой части обзора (). Напомню, что изображения созданы на подобии иллюстраций из официальной документации.

Принцип работы: процесс записи данных начинается с логирования всех операций в Commit Log, это необходимо для восстановления в случае сбоя работы узла. Сразу после этого данные дублируются в Memtable. Однако Memtable не осуществляет логирование, то есть точное запоминание вообще всех операций, а только хранит самые свежие данные. Это вполне логично с той точки зрения, что место в оперативной памяти значительно дороже, чем место на жестком диске. Исходя из того, что данные в Memtable упорядочены по ключу записи, а внутри ключа по колонкам, то наш рисунок можно усложнить соответствующим образом. Возьмем расширенный вариант схемы также из предыдущей части обзора процесса записи данных:

Для поиска и вставки новых элементов в Memtable используется алгоритм Skip List, вернее его реализация на Java — ConcurrentSkipListMap. Понимание принципа его работы не совсем обязательно в контексте изучения Memtable, однако этот алгоритм делает и без того быстрый поиск по оперативной памяти ещё быстрее и поэтому я вкратце постараюсь объяснить его основы.

Принцип работы алгоритма состоит в создании нескольких уровней с данными. На первом уровне находится список всех упорядоченных по возрастанию ключей. С определенной вероятностью какое-либо значение с первого уровня может быть продублировано на второй уровень. Значения со второго уровня также с некоторой вероятностью могут быть продублированы на уровень выше и так далее. Пропуски не допускаются — например, нельзя чтобы значение было на первом и третьем уровне, а на втором отсутствовало. При поиске элементов обращение сначала идет к самому высокому уровню, первое встретившееся значение сравнивается с искомым и если оно не равно ему, то спускаемся на уровень ниже и в зависимости от того меньше текущее значение искомого или больше, поиск идет в сторону убывания или возрастания элементов соответственно. Лучше всего этот процесс показывает анимация (кликните для просмотра) из статьи на Википедии:

Более подробно рассмотреть алгоритм по шагам можно в статье на Хабре и некоторых других источниках, а мы идем дальше.

К данным, находящимся в Memtable, впоследствии можно получать доступ как к кэшу при клиентских запросах чтения. Это также одно из отличий от Commit Log, к которому не могут осуществляться клиентские запросы.

Когда Memtable достигает определенного объема, происходит сброс (flush) данных в структуру, называемую SSTable, которая располагается на жестком диске. Регулировать максимальный объем Memtable можно с помощью параметра memtable_total_space_in_mb, который по умолчанию с версии Cassandra 2.0.2 стал равен четверти (ранее треть) от объема памяти, выделяемой для динамической памяти Java (Java heap size).

В свою очередь управление памятью Java осуществляет Cassandra самостоятельно и в зависимости от объема RAM устанавливаются следующие значения:

Many users new to Cassandra are tempted to turn up Java heap size too high, which consumes the majority of the underlying system’s RAM. In most cases, increasing the Java heap size is actually detrimental for these reasons:

— In most cases, the capability of Java to gracefully handle garbage collection above 8GB quickly diminishes.

— Modern operating systems maintain the OS page cache for frequently accessed data and are very good at keeping this data in memory, but can be prevented from doing its job by an elevated Java heap size.

If you have more than 2GB of system memory, which is typical, keep the size of the Java heap relatively small to allow more memory for the page cache.

Следующий параметр, отвечающий за работу Memtable — file_cache_size_in_mb . Судя по описанию в официальной документации, используется как промежуточный кэш для чтения данных (SSTable-reading buffer) перед их записью в SSTable.

Осуществлять гибкое управление Memtable можно с помощью параметров memtable_flush_writers и memtable_flush_queue_size . Первый параметр отражает количество (от 2 до 8 по умолчанию) экземпляров процесса, отвечающего за сброс данных на жесткий диск. Если у вас множество каталогов данных, большой размер Java heap или в в процессе перемещения данных из Memtable на HDD участвует множество жестких дисков, рекомендуется увеличить это значение и таким образом распараллелить процесс. Это актуально также при использовании SSD. Второй параметр задает максимальное количество полных Memtable, ожидающих сброса на жесткий диск. Его рекомендуют устанавливать в значение, которое равно максимальному количеству индексов какого-либо колоночного семейства. Эта рекомендация связана с особенность хранения индексов: индекс для колоночного семейства — это фактически ещё одно колоночное семейство, ключом которого является индексное поле оригинального CF:

At the storage layer, a secondary index is simply another column family, where the key is the value of the indexed column, and the columns contain the row keys of the indexed table…

…Cassandra co-locates index entries with their associated original table keys.

Стоит отдельно рассмотреть изменения касательно Memtable, которые были введены в версии Cassandra 2.1. Если до этой версии Memtable располагались исключительно в Java heap, то теперь можно переместить буфер Memtable в собственную память Cassandra. В связи с этим были добавлены соответствующие переменные в параметры конфигурации. Параметр memtable_allocation_type определяет три новых значения (первое я пропущу, поскольку оно соответствует типу хранения до версии 2.1):

multiple memtables may exist for a single column family, one current and the rest waiting to be flushed.

Однако остается вопрос что значит «полная Memtable» (full memtable) и почему рекомендуется устанавливать значение параметра memtable_flush_queue_size к максимальному количеству индексов для одного колоночного семейства:

The number of full memtables to allow pending flush (memtables waiting for a write thread). At a minimum, set to the maximum number of indexes created on a single table.

Возможно имеет место следующий алгоритм: когда одиночный сегмент commit log достигает своего максимального объема, создается новый файл commit log (один для всех CF) на жестком диске и новые Memtable (по одной для каждого CF) в оперативной памяти. Одновременно старый commit log помечается битом 0 (то есть ожидает операции flush). Если будет достигнут один из максимальных пределов — commitlog_total_space_in_mb для commit log и memtable_total_space_in_mb для memtable, самые старшие полные memtable начинают помещаться в очередь (memtable flush queue) и после их сброса на диск в SSTable, удаляются (точно также и соответствующие им commit log). Это лишь мое предположение на основе той информации, которую мне удалось найти в сети.