sexta-feira, 10 de outubro de 2014

Performance Tuning JBoss 7

Seguem algumas dicas para efetuar um tuning de performance da versão JBoss-as-7.1.1.Final Community em um Linux Debian 7.6.




Configurações da JVM


Dentro do arquivo $JBOSS_home/bin/standalone.conf, você pode efetuar as seguintes configurações:

- Memória: uma configuração para um servidor de pequeno porte para uma máquina com memória física de 4Gb seria:

JAVA_OPTS="-Xms2g -Xmx2g -XX:PermSize=256m -XX:MaxPermSize=512m"

- GC Paralelo: caso a máquina tenha vários processadores é interessantes habilitar o GC paralelo e dividir as regiões de memória.

# Paralell GC
JAVA_OPTS="$JAVA_OPTS -server -XX:+UseParallelGC -XX:+UseParallelOldGC -
XX:SurvivorRatio=2 -XX:NewRatio=2
"


Configurações do Linux


- Linux HugePages: Você pode também habilitar o HugePages no sistema operacional e habilitar o uso de large pages na JVM:

Veja aqui como habilitar o hugepages para o debian: https://wiki.debian.org/Hugepages. Basicamente é criar um grupo no linux, criar o ponto de montagem, configurar os parametros do kernel e adicionar um usuário ao grupo criado, ou seja, o usuário que irá subir o jboss.

Para uma máquina de 4Gb de memória física, temos os seguintes valores para o Hugepages:

Arquivo /etc/sysctl.conf:

# Total memory
kernel.shmmax = 4294967295

# Ceil(shmmax/PAGE_SIZE)
kernel.shmall = 1048576

# Allocate n * 2048kb (Hugepagesize) for HugePageTables

vm.nr_hugepages = 1536

Ainda no standalone.conf, para habilitar o uso do Hugepages na JVM, você precisa usar o parâmetro abaixo:

# Large Pages
JAVA_OPTS="$JAVA_OPTS -XX:+UseLargePages"



Configurações do JBoss


Dentro do standalone.xml, temos:

- Compressão do tráfego: o mais recomendável é que você utilize um servidor web como Apache Web Server para receber as requisições e direcione para o jboss, mas mesmo assim é interessante verificar como compactar alguns tipos de arquivos:

<system-properties>
    <property name="org.apache.coyote.http11.Http11Protocol.COMPRESSION" value="on"/>
    <property name="org.apache.coyote.http11.Http11Protocol.COMPRESSION_MIME_TYPES" value="text/html,text/xml,text/plain,text/css,text/javascript,text/json,application/x-javascript,application/javascript,application/json"/>
    <property name="org.apache.coyote.http11.Http11Protocol.COMPRESSION_MIN_SIZE" value="1024"/>
</system-properties>


- Logger: diminua os níveis de logger do jboss, e se for o caso, remova o CONSOLE handler dele, para a maioria dos casos, você pode só diminuir o nível para WARN e deixar INFO para as mensagens de inicialização do JBoss:

        <logger category="org.jboss.as">
            <level name="INFO"/>
        </logger>
        ...
        <root-logger>
            <level name="WARN"/>
        </root-logger>



 - Thread Pool: configure um thread pool para receber as requisições web, estimando a quantidade de usuários concorrentes que você espera que aquele servidor suporte. Abaixo segue uma configuração para suportar em torno de 200 usuários concorrentes.

    <subsystem xmlns="urn:jboss:domain:threads:1.1">
        <bounded-queue-thread-pool name="http-executor" blocking="true">
            <core-threads count="200" />
            <queue-length count="1000" />
            <max-threads count="300" />
            <keepalive-time time="5" unit="seconds"/>
        </bounded-queue-thread-pool>

    <subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="true">
        <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"
            executor="http-executor" enable-lookups="false"
            max-connections="300" max-post-size="2048" max-save-post-size="4096"
        />


- Mail/Default: caso seu servidor não utilize o mail-session do JBoss, você pode remover a extension, o subsystem e o socket-binding conforme abaixo. Isso irá deixar a inicialização do servidor mais rápida.

    <extension module="org.jboss.as.mail"/>
     ...
    <subsystem xmlns="urn:jboss:domain:mail:1.0">
        <mail-session jndi-name="java:jboss/mail/Default">
            <smtp-server outbound-socket-binding-ref="mail-smtp"/>
        </mail-session>
    </subsystem>
    ...
    <outbound-socket-binding name="mail-smtp">
        <remote-destination host="localhost" port="25"/>
    </outbound-socket-binding>



- JBoss Web Native: instale os connectors nativos para uma melhor performance das conexões HTTP.

Abaixo segue o link para fazer download dos binários já compilados para cada plataforma:

http://jbossweb.jboss.org/downloads/jboss-native-2-0-10.html


Descompacte dentro da $JBOSS_HOME/bin/native:

ls -l $JBOSS_HOME/bin/native/lib*-1.so


Habilite dentro do arquivo standalone.xml:

<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="true">


- Deployment Scanner: desabilite a checagem do scanner, assim ele não irá fazer hot-deploy de arquivos. Isso pode ser um falha de segurança e diminui o overhead no disco. Com a configuração abaixo, ele só irá fazer o deploy durante a inicialização do JBoss:

        <subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1">
            <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="0"/>
        </subsystem>



 - Compilation JSP e arquivos estátivos: desabilite a checagem para compilação das JSPs e desabilite a listagem de recursos estáticos:

<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false">
        <configuration>
            <static-resources listings="false" sendfile="49152"
                file-encoding="utf-8" read-only="true" webdav="false" max-depth="3" disabled="false" />
            <jsp-configuration
                development="false"
                check-interval="1"
                disabled="false"
                display-source-fragment="true"
                dump-smap="false"
                error-on-use-bean-invalid-class-attribute="false"
                generate-strings-as-char-arrays="false"
                java-encoding="UTF8"
                keep-generated="true"
                mapped-file="true"
                modification-test-interval="4"
                recompile-on-fail="false"
                scratch-dir=""
                smap="true"
                source-vm="1.6"
                tag-pooling="true"
                target-vm="1.6"
                trim-spaces="false"
                x-powered-by="true"/>
        </configuration>



- Data Source: estime e configure a quantidade de conexões que a aplicação terá. A maioria das aplicações usam OpenSessionInView, ou seja, cada request utiliza somente uma conexão de banco, pensando assim, podemos estimar o tamanho do pool, com o mesmo tamanho do thread pool, assim para 200 usuários concorrentes, teríamos:

<datasources>
        <datasource jndi-name="java:jboss/datasources/ExemploDS" pool-name="ExemploDS" enabled="true" use-java-context="true" use-ccm="false">
            <connection-url>....</connection-url>
            <driver>....</driver>

            <pool>                <min-pool-size>100</min-pool-size>
                <max-pool-size>200</max-pool-size>
                <prefill>true</prefill>
                <use-strict-min>false</use-strict-min>
            </pool>
            <statement>
                <track-statements>true</track-statements>
                <prepared-statement-cache-size>50</prepared-statement-cache-size>
                <share-prepared-statements />
            </statement>
            <timeout>
                <blocking-timeout-millis>10000</blocking-timeout-millis>
                <idle-timeout-minutes>2</idle-timeout-minutes> 
                <set-tx-query-timeout />
                <query-timeout>30</query-timeout>
                <use-try-lock>30</use-try-lock>
            </timeout>


Lembre-se de verificar se o banco suporta essa quantidade de conexões. Para Oracle, você pode utilizar o select abaixo:

select name, value from v$parameter
where name in ('processes', 'sessions', 'transactions');




- Validação da conexão: habilite também as validações de conexão. Isso evita problemas na aplicação devido oscilações na rede. Abaixo seguem alguns exemplos:

Oracle

<validation>
  <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker"/>
  <stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleStaleConnectionChecker"/>
  <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter"/>
</validation>


Postgresql:

<validation>
  <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker" />
  <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter" />

</validation>

Aqui temos a listagem completa para cada banco de dados:

http://www.ironjacamar.org/doc/userguide/1.0/en-US/html/ex_datasources.html


Configurações de Segurança


 - Usuário jboss-as: Crie um usuário específico para o efetuar o start e shutdown do JBoss. Você pode utilizar os arquivos que vem dentro do jboss para configurar isso no linux:

$JBOSS_HOME/bin/init.d/
    - jboss-as.conf
    - jboss-as-standalone.sh

Copie o jboss-as.conf para /etc/jboss-as/

cp $JBOSS_HOME/bin/init.d/jboss-as.conf /etc/jboss-as/.


Copie o jboss-as-standalone.sh para dentro de /etc/init.d/

cp $JBOSS_HOME/bin/init.d/jboss-as-standalone.sh   /etc/init.d/jboss-as


Execute o chkconfig para adicioná-lo a configuração:

chkconfig --add jboss-as


- DataSource: usuário e senha: não deixe exposto o usuário e senha da conexão de banco no standalone.xml. Você pode utilizar um security-domain com o SecureIdentity, que é um login-module que vem dentro do picketbox, que é a biblioteca de segurança do JBoss, e gerar uma senha criptografada.

Aqui você tem mais informações sobre o picketbox: http://picketbox.jboss.org/

Crie o security-domain:

        <subsystem xmlns="urn:jboss:domain:security:1.1">
            <security-domains>
                <security-domain name="ExemploDSSecurity" cache-type="default">
                    <authentication>
                        <login-module code="SecureIdentity" flag="required">
                            <module-option name="username" value="dbuser"/>
                            <module-option name="password" value="2afa5c8be6f4b2ec"/>
                        </login-module>
                    </authentication>
                </security-domain>


Altere o pool para usar o security-domain criado:

<subsystem xmlns="urn:jboss:domain:datasources:1.1">
    <datasources>
        <datasource jndi-name="java:jboss/datasources/ExemploDS" pool-name="ExemploDS" enabled="true" use-java-context="true" use-ccm="false">
            <connection-url>.....</connection-url>
            <driver>...</driver>

            <security>
                <security-domain>ExemploDSSecurity</security-domain>
            </security>


Para gerar a senha, crie o seguinte script:

$JBOSS_HOME/bin/makepasswd.sh
----------

#!/bin/bash

read -s -p "password: " PASS

## Build ClassPath for command
CP=
CP=${CP}:$JBOSS_HOME/modules/org/picketbox/main/picketbox-4.0.7.Final.jar
CP=${CP}:$JBOSS_HOME/modules/org/jboss/logging/main/jboss-logging-3.1.0.GA.jar

echo ""
java -classpath ${CP} org.picketbox.datasource.security.SecureIdentityLoginModule ${PASS}


------------

Dê a permissão necessária:

chmod +x makepasswd.sh


Execute e ele irá gerar uma senha que você irá substituir no parâmetro do módulo:

         <module-option name="password" value="2afa5c8be6f4b2ec"/>

Configurações de Monitoramento


- JConsole: o JBoss tem um protocolo específico para conexão via JMX, então para conectar via jconsole, você precisa utilizar os pacotes que vem dentro do JBoss.

Em outra máquina com o JBoss, utilize o script abaixo para inicializar o jconsole:

 $JBOSS_HOME/bin/jconsole.sh


Utilize a seguinte URL:

service:jmx:remoting-jmx://{host_name}:{port}

A porta padrão para do JBoss é a 9999.

Em outro momento, iremos explicar como utilizar ferramentas específicas como JProfiler, Zorka e Zabbix, AppDynamics para efetuar um monitoramento mais efetivo.

Aqui tem mais informações de como utilizar o jconsole:

https://developer.jboss.org/wiki/UsingJconsoleToConnectToJMXOnAS7 

- JBoss Management: para habilitar o bind das interfaces de rede da aplicação de gerenciamento do JBoss para todos IPs disponíveis na máquina, você pode alterar a seguinte configuração:

        <interface name="management">
            <any-address/>
        </interface>

        <interface name="public">
            <any-address />
        </interface>


Lembre-se de configurar seu firewall para não permitir conexões na porta 9999 fora da sua rede, ela é a porta da interface de management da configuração acima.



Conclusão

 Vimos algumas configurações de performance e segurança do JBoss, mas sempre há como melhorar alguns itens, caso você tenha mais algum detalhe que foi esquecido, não deixe de enviar para gente acrescentar aqui.