블로그 이미지
redkite

카테고리

분류 전체보기 (291)
00.SI프로젝트 산출물 (0)
00.센터 운영 문서 (0)
01.DBMS ============.. (0)
01.오라클 (117)
01.MS-SQL (15)
01.MySQL (30)
01.PostgreSql (0)
01.DB튜닝 (28)
====================.. (0)
02.SERVER ==========.. (0)
02.서버-공통 (11)
02.서버-Linux (58)
02.서버-Unix (12)
02.서버-Windows (2)
====================.. (0)
03.APPLICATION =====.. (11)
====================.. (0)
04.ETC =============.. (0)
04.보안 (5)
====================.. (0)
05.개인자료 (1)
06.캠핑관련 (0)
07.OA관련 (1)
Total
Today
Yesterday

달력

« » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

공지사항

최근에 올라온 글

  1. http://pastebin.com/A5pRDv2P

    ###INPUT###
    input {
      tcp {
        port => 514
        type => "syslog-relay"
      }
      udp {
        port => 514
        type => "syslog-relay"
        buffer_size  => 16384
      }
      gelf {
        port => 12201
        type => "gelf"
      }
    }
    filter {
      grep {
        type => "syslog-relay"
        match => [ "@message", ":\s\%ASA-" ]
        add_tag => "got_syslog_cisco"
        drop => false
        }
      grep {
        type => "syslog-relay"
        match => [ "@message", ":\s\%ASA-" ]
        add_tag => "got_syslog_standard"
        drop => false
        negate => true
        }
     
      # strip the syslog PRI part
      grok {
        type => "syslog-relay"
        pattern => [ "(?m)<%{POSINT:syslog_pri:int}>(?:%{SPACE})%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_pri"
       add_field => [ "syslog_raw_message", "%{@message}" ]
     }
     syslog_pri {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_pri" ]
       remove => [ "message_remainder" ]
     }
     
     # strip the syslog timestamp and force event timestamp to be the same.
     # the original string is saved in field %{syslog_timestamp}.
     # the original logstash input timestamp is saved in field %{received_at}.
     grok {
       # put cisco log timestamp in cisco_syslog_timestamp as ES can't store 2 format of dates in the same field
       # also parse the hostname if present....
       type => "syslog-relay"
       tags => [ "got_syslog_cisco" ]
       pattern => [ "(?m)%{SYSLOGTIMESTAMPWITHYEAR:cisco_syslog_timestamp}(\s+%{SYSLOGHOST:syslog_hostname}\s+\:|\:)?\s+%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_timestamp"
       add_field => [ "received_at", "%{@timestamp}" ]
     }
     grok {
       # put log timestamp in syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{TIMESTAMP_RFC3339:syslog_timestamp}%{SPACE}%{GREEDYDATA:message_remainder}", "(?m)%{SYSLOGTIMESTAMPWITHOUTYEAR:syslog_timestamp}%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_timestamp"
       add_field => [ "received_at", "%{@timestamp}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       remove => [ "message_remainder" ]
     }
     date {
       # parse the cisco_syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" , "got_syslog_cisco" ]
       cisco_syslog_timestamp => [ "MMM dd yyyy HH:mm:ss", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601" ]
     }
     date {
       # parse the syslog_timestamp
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp", "got_syslog_standard" ]
       syslog_timestamp => [ "MMM dd yyyy HH:mm:ss", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601" ]
     }
     
     # strip the host field from the syslog line.
     # the extracted host field becomes the logstash %{@source_host} metadata
     # and is also available in the filed %{syslog_hostname}.
     # the original logstash source_host is saved in field %{logstash_source}.
     
     grok {
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{SYSLOGHOST:syslog_hostname}%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => "got_syslog_host"
       add_field => [ "logstash_source", "%{@source_host}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_host" ]
       replace => [ "@source_host", "%{syslog_hostname}", "@message", "%{message_remainder}" ]
       #replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_host" ]
       remove => [ "message_remainder" ]
     }
     
     
     # strip the app name and set it in syslog_file_name field to compute the local log file name
     grok {
       # do the stip multiline for standard syslog
       # program can still be like "program_main/program_param"
       type => "syslog-relay"
       tags => [ "got_syslog_standard" ]
       pattern => [ "(?m)%{SYSLOGPROG:syslog_program}\:%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => [ "got_syslog_program", "%{program}" ]
       add_field => [ "syslog_file_name", "%{program}" ]
     }
     grok {
       # split the main and param part of the program
       type => "syslog-relay"
       tags => [ "got_syslog_program" ]
       match => ["program", "%{MULTIPROG}" ]
       add_tag => [ "got_syslog_program_param", "%{program_main}", "%{program_param}"  ]
     }
     
     grok {
       # do the strip single line for cisco syslog
       type => "syslog-relay"
       tags => [ "got_syslog_cisco" ]
       pattern => [ "\%%{SYSLOGPROG:syslog_program}\:%{SPACE}%{GREEDYDATA:message_remainder}" ]
       add_tag => [ "got_syslog_program", "%{program}" ]
       add_field => [ "syslog_file_name", "%{program}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_program" ]
       replace => [ "@message", "%{message_remainder}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "got_syslog_timestamp" ]
       remove => [ "message_remainder" ]
     }
     
     
     #############################################################
     #
     # Jboss logs = tag JBOSSserver
     #
     #############################################################
     
     # try to get multilines back
     multiline {
       # match 2012-07-30 10:29:55,985
       type => "syslog-relay"
       tags => "JBOSSserver"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     # remove logs which are malformed stacktraces
     grep {
       # tag the malformed stacktrace
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       match => [ "@message", "java\.lang\.Throwable" ]
       add_tag => "got_syslog_stacktrace"
       drop => false
       negate => false
       }
     
     
     # Parse jboss messages
     grok {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       pattern => [ "(?m)%{JBOSSSERVERLOG}" ]
     }
     mutate {
       # remove the timestamp at the begining of the message
       # doing this completly remove timestamp of errors in the file output module
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       replace => [ "@message", "%{jboss_loglevel} [%{jboss_class}] %{jboss_caller}: %{jboss_message}" ]
     }
     mutate {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       remove => [ "jboss_message" ]
     }
     
     
     # set the date to the Jboss error date
     date {
       type => "syslog-relay"
       tags => [ "JBOSSserver" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     
     #############################################################
     #
     # Tomcat
     #
     #############################################################
     
     # define multiline messages starting at the date
     # Feb 28, 2012 2:07:33 PM org.apache.jk.common.ChannelSocket processConnection
     # WARNING: processCallbacks status 2
     # 2012-02-28 14:10:27,723 DEBUG [shq.servlet.GetResourceFlex] - <Ressource demandee : /sde/>
     
     multiline {
       type => "syslog-relay"
       tags => "Tomcat"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     #############################################################
     #
     # OUD
     #
     #############################################################
     
     # OUD logs are XML inside <record> </record>
     multiline {
       type => "syslog-relay"
       tags => "OUDSERVER"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     #############################################################
     #
     # SHQ Synapse
     #
     #############################################################
     
     # OUD logs are XML inside <record> </record>
     multiline {
       type => "syslog-relay"
       tags => "synapse"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     multiline {
       type => "syslog-relay"
       tags => "oud"
       pattern => "\<\/record\>"
       negate => false
       what => "previous"
     }
     
     
     # synapse/main tagged logs
     # 2012-06-21 13:04:25,024 [10.100.64.74-qxpsbp01] [HttpServerWorker-9]  INFO
     multiline {
       type => "syslog-relay"
       tags => "synapse/main"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     multiline {
       type => "syslog-relay"
       tags => "synapse/service"
       pattern => "^([0-9][0-9]-[a-zA-Z][a-zA-Z][a-zA-Z]-2012|\d{4}-\d{2}-\d{2}\s\d{2}\:\d{2}\:\d{2}|[a-zA-Z]{3}\s\d{2},\s\d{4})"
       negate => true
       what => "previous"
     }
     
     # synapse service.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/main" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse service.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/service" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse wrapper.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/wrapper" ]
       pattern => [ "(?m)%{SYNAPSESERVICELOG}" ]
     }
     
     # synapse trace.log
     grok {
       type => "syslog-relay"
       tags => [ "synapse/trace" ]
       pattern => [ "(?m)%{SYNAPSETRACELOG}" ]
     }
     
     # set the date to the SYNAPSE error date
     date {
       type => "syslog-relay"
       tags => [ "synapse/main" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     date {
       type => "syslog-relay"
       tags => [ "synapse/service" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     date {
       type => "syslog-relay"
       tags => [ "synapse/wrapper" ]
       # season to taste for your own syslog format(s)
       jboss_timestamp => [ "yyyy-MM-dd HH:mm:ss,SSS" ]
     }
     
     
     
     
     
     #############################################################
     #
     # Other messages
     #
     #############################################################
     
     # rebuild multiline messages
     multiline {
       type => "gelf"
       pattern => "^\s"
       what => "previous"
     }
    }
    output {
    #  stdout {
    #  }
     
    #  gelf {
    #    chunksize => 1420
    #    facility => "logstash-gelf"              #########Default Setting ##########
    #    host => "qxplog02.corp.shq.local"
    #    level => "INFO"                             #########Default Setting ##########
    #    port => 12201
    #    sender => "%{@source_host}"
    #  }
     
     elasticsearch {
       host => "localhost"
       embedded => false
     }
     
     file {
       flush_interval => 10
       tags => ["got_syslog_standard"]
       path => "/opt/data/syslog/%{+YYYY}/%{+MM}/%{+dd}/%{@source_host}/%{syslog_file_name}.log"
       message_format => "%{@timestamp} %{@source_host} %{@message}"
     }
     
     file {
       flush_interval => 10
       tags => ["got_syslog_cisco"]
       path => "/opt/data/syslog/%{+YYYY}/%{+MM}/%{+dd}/%{@source_host}/%{program}.log"
       message_format => "%{@timestamp} %{@source_host} %{@message}"
     }
    }
     


Posted by redkite
, |

2012-05-18 10:26:01,434 INFO  [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms

I'm finding that the Severity in graylog2 is always 'Alert'. I'm using the following config file with the multiline, grok and mutate filters:

input {
  # Tail the JBoss server.log file
  file {
    type => "log4j"
    path => "/JBoss/server/all/log/server.log"
  }
}

filter {
  multiline {
    type => "log4j"
    pattern => "^\\s"
    what => "previous"
  }

  grok {
    type => "log4j"
    pattern => "%{DATESTAMP:timestamp} %{WORD:severity} %{GREEDYDATA:message}"
  }

  mutate {
    type => "log4j"
    replace => [ "@message", "%{message}" ]
  }
}

output {
  # Emit events to stdout for easy debugging of what is going through logstash
  stdout {
    debug => true
  }

  # Send Jboss log to graylog2
  gelf {
    facility => "jboss"
    host => "log01"
  }
}

Here's the logstash debug output for this log entry:

{
         "@source" => "file://stg-app01//JBoss/server/all/log/server.log",
           "@type" => "log4j",
           "@tags" => [],
         "@fields" => {
        "timestamp" => [
            [0] "2012-05-18 10:26:01,434"
        ],
         "severity" => [
            [0] "INFO"
        ],
          "message" => [
            [0] " [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms"
        ]
    },
      "@timestamp" => "2012-05-18T10:26:01.601000Z",
    "@source_host" => "stg-app01",
    "@source_path" => "//JBoss/server/all/log/server.log",
        "@message" => " [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms"
}

Finally, here's how graylog2 sees this entry:

From: stg-app01
Date: 2012-05-18 10:26:31 +0000
Severity: Alert
Facility: jboss
File: //JBoss/server/all/log/server.log:151
timestamp: 2012-05-18 10:26:01,434
severity: INFO
message: [com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms
Full message:
[com.xxxx.xxxx.server.singleton.ConnectionHASingleton] Summary (PSW Bucket: 1) 1 current(22ms), 0 shared(0ms), 0 static(0ms), 0 health(0ms) Total elapsed 26ms

It has two severity entries. Am I doing something wrong?

 

 

Have a look at the "level" flag in your output configuration. In your
case you'll want to change the naming in grok to something like
"jboss_severity" and then use this in your output:

gelf {
  level =>  [%{severity}, %{jboss_severity}]
  # rest of config
}

Posted by redkite
, |

Indexing and searching Weblogic logs using Logstash and Graylog2

Recently we decided to get rid of our Splunk "Free" log indexing solution as the 500MB limit is too limited for our 20+ Weblogic environments (we couldn't even index all production apps with that) and $boss said "he won't pay over 20000€ for a 2GB enterprise license, that's just rediculous". So I went out on the interwebs to watch out for alternatives, and stumbled over Graylog2 and Logstash. This stuff seemed to have potential, so I started playing around with it.

Logstash is a log pipeline that features various input methods, filters and output plugins. The basic process is to throw logs at it, parse the message for the correct date, split the message into fields if desired, and forward the result to some indexer and search it using some frontend. Logstash scales vertically, and for larger volumes it's recommended to split the tasks of logshipping and log parsing to dedicated logstash instances. To avoid loosing logs when something goes down and to keep maintenance downtimes low, it's also recommended to put some message queue between the shipper(s) and the parser(s).

Redis fits exactly in that pictures, and acts as a key-value message queue in the pipeline. Logstash has a hard coded queue size of 20 events per configured input. If the queue fills up, the input gets blocked. Using a dedicated message queue instead is a good thing to have.

Graylog2 consits of a server and a webinterface. The server stores the logs in Elasticsearch, the frontend lets you search the indexes.

So, our whole pipeline looks like this:

logfiles  logstash shipper  redis  logstash indexer cluster  gelf  graylog2-server  elasticsearch cluster  graylog2-web-interface

Logstash is able to output to Elasticsearch directly, and there is the great Kibana frontend for it which is in many ways superior to graylog2-web-interface, but for reasons I explain at the end of the post we chose Graylog2 for weblogic logs.

Installation

The first step was to get graylog2, elasticsearch and mongodb up and running. We use RHEL 6, so this howto worked almost out of the box. I changed following:

  • latest stable elasticsearch-0.19.10
  • latest stable mongodb 2.2.0
  • default RHEL6 ruby 1.8.7 (so I left out any rvm stuff in that howto, and edited the provided scripts removing any rvm commands)

Prepare access to the logfiles for logstash

Next was to get logstash to index the logfiles correctly.

We decided to use SSHFS for mounting the logfile folders of all Weblogic instances onto a single box, and run the logstash shipper on that one using file input and output to redis. The reason for using SSHFS instead of installating logstash directly on the Weblogic machines and using for example a log4j appenders to logstash log4j inputs was mainly that our Weblogics are managed by a bank's data centre, so getting new software installed requires a lot work. The SSH access was already in place.

We have weblogic server logs (usually the weblogic.log), and each application generates a log4j-style logfile.

/data/logfiles/prod/server01/app1.log
/data/logfiles/prod/server01/app2.log
/data/logfiles/prod/server01/weblogic.log
/data/logfiles/prod/server02/app1.log
...
/data/logfiles/qsu/server01/app1.log
... and so on

This is the configuration file for the file-to-redis shipper. The only filter in place is the multiline filter, so that multiline messages get stored in redis as a single event already.

input {
  # server logs
  file {
    type => "weblogic-log"
    path => [ "/data/logfiles/*/*/weblogic.log" ]
  }
  # application logs
  file {
    type => "application"
    path => [ "/data/logfiles/*/*/planethome.log",
              "/data/logfiles/*/*/marktplatz*.log",
              "/data/logfiles/*/*/immoplanet*.log",
              "/data/logfiles/*/*/planetphone.log" ]
  }
}
filter {
  # weblogic server log events always start with ####
  multiline {
    type => "weblogic"
    pattern => "^####"
    negate => true
    what => "previous"
  }
  # application logs use log4j syntax and start with the year. So below will work until 31.12.2099
  multiline {
    type => "application"
    pattern => "^20"
    negate => true
    what => "previous"
  }
}
output {
  redis {
    host => "phewu01"
    data_type => "list"
    key => "logstash-%{@type}"
  }
}

And this is the config for the logstash parsers. Here the main work happens, logs get parsed, fileds get extracted. This is CPU intensive, so depending on the amount of messages, you can simply add more instances with the same config.

input { redis { type => "weblogic" host => "phewu01" data_type => "list" key => "logstash-weblogic" message_format => "json_event" } redis { type => "application" host => "phewu01" data_type => "list" key => "logstash-application" message_format => "json_event" } } filter { ################### # weblogic server logs ################### grok { # extract server environment (prod, uat, dev etc..) from logfile path  type => "weblogic" patterns_dir => "./patterns" match => ["@source_path", "%{PH_ENV:environment}"] } grok { type => "weblogic" pattern => ["####<%{DATA:wls_timestamp}> <%{WORD:severity}> <%{DATA:wls_topic}> <%{HOST:hostname}> <(%{WORD:server})?> %{GREEDYDATA:logmessage}"] add_field => ["application", "server"] } date { type => "weblogic" # joda-time doesn't know about localized CEST/CET (MESZ in German), # so use 2 patterns to match the date wls_timestamp => ["dd.MM.yyyy HH:mm 'Uhr' 'MESZ'", "dd.MM.yyyy HH:mm 'Uhr' 'MEZ'"] } mutate { type => "weblogic" # set the "Host" in graylog to the environment the logs come from (prod, uat, etc..) replace => ["@source_host", "%{environment}"] } ###################### # application logs ###################### # match and pattern inside one single grok{} doesn't work # also using a hash in match didn't work as expected if the field is the same, # so split this into single grok{} directives grok { type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_ENV:environment}"] } grok { # extract app name from logfile name type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_APPS:application}"] } grok { # extract node name from logfile path type => "application" patterns_dir => "./patterns" match => ["@source_path", "%{PH_SERVERS:server}"] } grok { type => "application" pattern => "%{DATESTAMP:timestamp} %{DATA:some_id} %{WORD:severity} %{GREEDYDATA:logmessage}" } date { type => "application" timestamp => ["yyyy-MM-dd HH:mm:ss,SSS"] } mutate { type => "application" replace => ["@source_host", "%{environment}"] } } output { gelf { host => "localhost" facility => "%{@type}" } }

In ./patterns there is a file containing 3 lines for the PH_ENV etc grok patterns to match.

I had several issues initially:

  • rsync to jumpbox and mounting to logserver via ssfhs would cause changes to go missing on some, but not all files
  • chaining rsyncs would cause some messages to be indexed with partial @message, as some files are huge and slow to transfer.
    • This was solved by mounting all logfile folders on the different environments directly with SSHFS, where possible.
    • The remaining rsync'ed files are rsync'ed with "--append --inplace" rsync parameters
  • indexing files would always start at position 0 of the file, over and over again
    • Only happened for rsync, using "--append --inplace" fixes this

Meanwhile I also took a look at Kibana, another great frontend to ElasticSearch. For the weblogic logs I'll keep Graylog2, as it allows saving predefined streams and provides that easy-to-use quickfilter, which eases up log crawling for our developers (they only want to search for a string in a timeframe - they also never made use of the power of Splunk). Also Kibana doesn't provide a way to view long stack traces in an acceptable fashion yet (cut message a n characters and provide a more link, something like that). But I added Apache logs in logstash, and those are routed to a logstash elasticsearch output and Kibana as WebUI. I'd really like to see some sort of merge between Kibana and Graylog2 and add saved searches to that mix - that would make a realy competitive Splunk alternative.


Posted by redkite
, |

logstash + graylog2 – cant ask more for logging

 
 
 
 
 
 
i
 
5 Votes

Quantcast

Everyone knows how important logging is for a web application. It is a shelter we build for the rainy day. But the logs in all the application has enormous amount of valuable information, that can give interesting perspectives about the application. Also as applications grow in complexity and scale, logs become spread across multiple machines and files. Soon developers/support people will be overwhelmed by the sheer number of log files to search and track issues. In order to overcome this situation, and to have a clear, simplified oversight over the system, a central logging system becomes necessary.

Was part of a team which was responsible for building a highly distributed and complex system. Just to give a idea of the kind of complexity involved, let me give a brief summary of tech components. The project was developed using three languages (1 dynamic and 2 static), uses sql and a nosql db, a queuing engine, etc.. In order to get the log consolidated and have a central view, we evaluated splunk. Unfortunately it was extremely costly. So we were forced to look at open source alternatives and finally we selected logstash and graylog.

Looking back at that decision, was one of the great decisions. I will share some insights into how logstash and graylog2 could be configured.

First we need to download the logstash jar to each of the machines where log files are generated.
Then we need to configure the input file for logstash to process. its pretty simple. we need to provide the path to files and also group them under different types.

1
2
3
4
5
6
input {
  file {
    type => nginx_web
    path => ["/opt/nginx/logs/access.log", "/opt/nginx/logs/error.log"]
  }
}

Graylog uses a log format called Graylog Extended Log Format(GELF). By using this format, we can send custom fields with the log. This format also doesnot have a log size limitation. We can preprocess the logs and define custom fields based on the line logged, before they are sent to the graylog server. Below is a example of nginx log being parsed using grok patterns(regular expressions) and fields are defined with the values matched. Grok patterns are extremely powerful, so they need a separate detailed blog… but thats for later.

1
2
3
4
5
6
filter {
 grok {
   type => nginx_web
   pattern => "%{IP:clientip} (?:%{HOST:clienthost}|-) (?:%{USER:clientuser}|-) \[%{HTTPDATE:time}\] \"(?:%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}|%{DATA:unparsedrq})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QUOTEDSTRING:httpreferrer} %{QUOTEDSTRING:httpuseragent}"
 }
}

The corresponding nginx log format is:

1
log_format  main  '$remote_addr $host $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $ssl_cipher $request_time';

Above grok filter will parse each log entry and fill the values for the following fields clientip, clienthost, clientuser, time, verb, request, httpversion, unparsedrq, response, bytes, httpreferrer, httpuseragent.

The advantage of splitting the input log entry into multiple fields, is that custom rules to search, group can be done on each of these fields in the graylog2 web.
Sample grok pattern for the rails 3 project is:

1
2
3
4
5
6
7
8
grok {
  type => app
  pattern => "\[%{WORD:requesttoken}\] \[%{IP:clientip}\] (?:%{DATA:logstmt}|-)"
}
grok {
  type => app
  pattern => "Rendered %{DATA:renderedtemplate} \(%{DATA:rendertime}\)"
}

The above grok filter parses the rails 3 app log and defines the following fields: requesttoken, clientip, logstmt, renderedtemplate, rendertime.

Next we need to configure the output. This is where we specify the output format as gelf and the graylog server to contact.
We can also specify custom fields. Here we are sending a custom field named environment with value as ‘uat’.
Another predefined field in gelf format is ‘facility’ and here we are setting it with the value of field ‘type’.

1
2
3
4
5
6
7
output {
 gelf {
 host => "graylog-server-ip"
 facility => "%{@type}"
 custom_fields => ["environment", "uat"]
 }
}

A complete sample configuration for logstash agent is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
input {
  file {
    type => pg91
    path => ["/var/lib/pgsql/9.1/pgstartup.log", "/var/lib/pgsql/9.1/data/pg_log/*.log"]
  }
  file {
    type => app
    path => ["/app/employeemgmt/shared/log/uat.log"]
  }
  file {
    type => nginx_web
    path => ["/opt/nginx/logs/access.log", "/opt/nginx/logs/error.log"]
  }
}
  
filter {
 grok {
   type => nginx_web
   pattern => "%{IP:clientip} (?:%{HOST:clienthost}|-) (?:%{USER:clientuser}|-) \[%{HTTPDATE:time}\] \"(?:%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}|%{DATA:unparsedrq})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QUOTEDSTRING:httpreferrer} %{QUOTEDSTRING:httpuseragent}"
 }
 grok {
   type => app
   pattern => "\[%{WORD:requesttoken}\] \[%{IP:clientip}\] (?:%{DATA:logstmt}|-)"
 }
 grok {
   type => app
   pattern => "Rendered %{DATA:renderedtemplate} \(%{DATA:rendertime}\)"
 }
}
  
output {
 gelf {
 host => "graylog-server-ip"
 facility => "%{@type}"
 custom_fields => ["environment", "uat"]
 }
}

All these configuration need to be done in a conf file.
Once the conf file is ready, we need to install the graylog2 server. Installation is pretty simple, again download the server jar file and run it. This graylog2 wiki will help you with that.
Finally we need to start the logstash agent using:

1
java -jar logstash-1.1.0-monolithic.jar agent -f logstash-agent.conf

Enjoy all your logs are in central Graylog2 server. Watch out for the next post on graylog2 web interface and how we can use it.

5 Responses to logstash + graylog2 – cant ask more for logging

  1. Nice article, concisely describes how to use logstash grok stuff. I was wondering how large your log volume is. And if you had any issues setting up elasticsearch to handle the volume. We have a stupid amount of log volume and had issues getting elasticsearch to handle it without building an elasticsearch cluster dedicated to logs.

    • boojapathy says:

      Elasticsearch occupies a pretty large space in order to store these logs. unfortunately the most easy solution is to build a elasticsearch cluster. But also you can look at logstash processing and leaving out unnecessary logs, for example load balancer health checks etc…

  2. Philipp says:

    can you expand your example in order to put the ssl_chiper and request_time in additional fields too?

    my logformat looks like this:
    ‘$host $remote_addr – $remote_user [$time_local] “$request” ‘
    ‘$status $body_bytes_sent “$http_referer” ‘
    ‘”$http_user_agent” “$http_x_forwarded_for” ‘
    ‘$ssl_cipher $request_time ‘
    ‘$gzip_ratio $upstream_addr $upstream_response_time’;

    I am not able to catch any field after http_user_agent :/

    This is my logstash filter
    “%{IPORHOST:host} %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] \”%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\” %{NUMBER:response} (?:%{NUMBER:bytes}|-) \”(?:%{URI:referrer}|-)\” %{QS:agent} %{QS:x_forwarded_for} %{USER:ssl_chiper} %{NUMBER:request_time} %{NUMBER:gzip_rato} %{IPORHOST:upstream} %{NUMBER:upstream_request_time}”

    • boojapathy says:

      Based on my understanding from the above log format, the “%{USER:ssl_chiper}” has to be replaced by “%{QUOTEDSTRING:ssl_chiper}”. In case, you are still having issues, can you post a sample line from the log file for which it is failing.

  3. Sharmith says:

    How to create a custom field and fill it with dynamic data from the log message.
    Sample log message given below. I want to add one field for “client IP” filled with client IP address, “Event ID” filled with event ID number in the below example “675″, “Username” filled with Username, “Service Name” filled with service name from the log.
    Your help on this is highly appreciated.
    Log:
    MSWinEventLog 1 Security 15596139 Mon Aug 06 11:21:48 2012 675 Security SYSTEM User Failure Audit XXXXX1 Account Logon Pre-authentication failed: User Name: xxxxxxxxx User ID: %{S-1-5-21-1058243859-2292328430-792808483-12929} Service Name: krbtgt/XXX Pre-Authentication Type: 0×0 Failure Code: 0×19 Client Address: 10.X.X.X 15534664

Posted by redkite
, |

Graylog2 v0.10 Finally Released – Install on CentOS 6.3

So the much anticipated Graylog2 version 0.10 was released on the 14th, so I finally found some time to build a test box with all the new software and see how it compares to get up and running.

So let’s get started.

Only non-default repo I have installed is:

We are downloading the following software packages:

Download all the software: (http://www.graylog2.org/download)

A one liner for the lazy:

Just to make sure we got everything:

Extract everything:


Great now let’s get Ruby installed:

Great now let’s get Libyaml installed:

Install RVM (Ruby Version Manager):

 Once it’s done you need to source rvm to use it:

Check to make sure ruby is working and it can find the binary:

Install Ruby Gem Bundle:

Update System Gems:


 Installing Elastic Search:

 Install the ES service wrapper:

 Give yourself a control script:

 Give the ES cluster a unique name:

 Fire it up and test it:

 Should get a response similar to:

Add ElasticSearch to boot:


 Setup 10gen Repo and Install MongoDB:

Create the mongo db directory:

Mongo configure file create and start:

Wait for it to start, it takes a couple seconds:

Setup MongoDB and auth

Set MongoDB to start on boot:

Intall MongoDB Gem:


Install Graylog2-Server:

 Configure Graylog2.conf:

Configure at least these variables in /etc/graylog2.conf:

  • is_master = true
    • Set only one graylog2-server node as the master. This node will perform periodical and maintenance actions that slave nodes won’t. Every slave node will accept messages just as the master nodes. Nodes will fall back to slave mode if there already is a master in the cluster.
  • elasticsearch_config_file = /etc/graylog2-elasticsearch.yml
    • This is the path to the ElasticSearch configuration file for the built-in ElasticSearch node of graylog2-server. Your graylog2-server node will act as a node in your ElasticSearch cluster, but not store any data itself. It will distribute the writes to other nodes in the ElasticSearch cluster.
  • elasticsearch_max_docs_per_index = 20000000
    • How many log messages to keep per index. This setting multiplied withelasticsearch_max_number_of_indices results in the maximum number of messages in your Graylog2 setup. It is always better to have several more smaller indices than just a few larger ones.
  • elasticsearch_max_number_of_indices = 20
    • How many indices to have in total. If this number is reached, the oldest index will be deleted.
  • elasticsearch_shards = 4
    • The number of shards for your indices. A good setting here highly depends on the number of nodes in your ElasticSearch cluster. If you have one node, set it to 1. Read more about this in the knowledge base article about configuring and tuning ElasticSearch.
  • elasticsearch_replicas = 0
    • The number of replicas for your indices. A good setting here highly depends on the number of nodes in your ElasticSearch cluster. If you have one node, set it to 0. Read more about this in the knowledge base article about configuring and tuning ElasticSearch.
  • recent_index_ttl_minutes = 60
    • Graylog2 keeps a so called recent index that includes only the newest log messages. This allows fast overview pages in the web interface. The messages you see in the “show recent messages” view are from this index. If you have thousands of messages per minute, set it to 1 minute because there are so many new messages coming in. If you have just a few messages per minute, set it to a higher values to still have a good overview without having to click on “show all messages”.
  • mongodb_*
    • Enter your MongoDB connection and authentication information here. Make sure that you connect the web interface to the same database. You don’t need to configure mongodb_user and mongodb_password ifmongodb_useauth is set to false.

 

 The most important ones (the rest you can leave as default if you want):
  • processor_wait_strategy = blocking  (this helps load on the server by quite a bit)
  • mongodb_password = whatever password you set earlier
  • Take note of the AMQP Section we will come back to this later

Start up Graylog2-Server:

Note: You may see a couple snappy error messages the first time you start graylog2.  Just ignore them the first time as it’s having to setup all the indexes.
Wait until you get this message:

Open another SSH session and test it out and make sure it’s working:

You should see a whole bunch of output if it was successful.  If not you will receive something like:

Exit WebBrick:

Drop an init.d script to make it easy:

 Load it up:


Install Graylog2 Web Interface:

Fix the Gemfile:
Note:  The current version of Graylog2-Web-Interface uses json-1.5.5, unfortunately there is a royal pain in the butt issue of installing Ruby 2.0.0 and not having the ruby development headers to compile it.  To work around this issue we need to change the required version of json in the gemfile inside the graylog2-web-interface folder.
I also made some changes to the version of the mongo driver it’s using, as it was set to use a much older version (pretty sure the mongo, bson_ext part is optional)
Edit Gemfile inside graylog2-web-interface:

This is what my /usr/local/graylog2-web-interface/Gemfile looks like:


curl -L https://get.rvm.io | bash -s stable --autolibs=enabled --ruby --rails --trace   ### 안되면 이걸로 실행

rvm install 1.9.2 

Setup a Graylog2 User:

 Give root RVM access:

Setup the web interface’s mongo config:

 Start Graylog2 and setup your first user:

# Note: If mongo isn’t running, you used an @ symbol in your password or if you installed mongo from source or some other method, check /etc/mongod.conf and see where it is putting the database.  You may have to create /data/db directory, you will get an error that looks like this:

Open a browser and see if the web ui is working:


Install and configure Passenger:

Note: There is currently a bug with passenger-3.0.19 and ruby-2.0.0 if you run passenger-install-apache2-module you will get compilation errors. See this github issue

If they’ve fixed the passenger bug and you install a version > 3.0.19 then the below doesn’t apply otherwise you can use these steps as a workaround.
To work around the current issue with passenger-3.0.19 you can edit the gempacktask.rb inside the passenger gem:

Delete everything in it and paste the following into it (quick way to delete everything inside vim type: 1000 dd:

Now let’s install the apache module:

 Create passenger.conf for httpd:

Paste the text from the end of the passenger-apache2-module install:

 Set Permissions and Add Apache to startup and load:

Open a browser and see if the web ui is working:

Technically, you’ve got a working version of Graylog2 setup and working at this point.  If you wanted you could start forwarding syslog messages to the Graylog2 Server on port 514 and off you go.
If you would like to setup an AMQP broker so that messages can be queued and add a few useful features (restarting graylog2-server without losing syslog messages), read further and see how it’s setup.

Setup AMQP (RabbitMQ):
I’m going to be using RabbitMQ as our AMQP broker, you can use others if you wish.
Install RabbitMQ:


rabbitmq-server-3.1.0-1.noarch.rpm
Get RabbitMQAdmin:

 Start Rabbit and add to Startup:

Create RabbitMQ Users and Exchanges for Graylog to use, here is the link to the official docs for reference:RabbitMQ Management

Edit the graylog2.conf to enable AMQP:

Monitor the Graylog2.log file for this next part, as you will immediately see java errors if something isn’t setup right (ignore the plugin errors):

Go to the Graylog2 Web Interface > Settings > AMQP:
Add new configurations with these parameters there
  • Exchange: messages
  • Routing key: syslogudp
  • TTL: 720000
  • Type: syslog
If no errors in the graylog2.log file and the web ui says added successfully.  Look under Server Health on the web ui home page:

graylog2-AMQP


 Setup the new Graylog2-Radio: Official Documentation

Edit the init script, add the comments at the top for chkconfig and change a couple paths:

Edit the Graylog2-Radio Inputs:

Start Graylog2-Radio:

You can monitor the log file to see if its working at:

If everything is working correctly:

Add Graylog2-Radio to Startup:

Change rsyslog to forward to Graylog2 port:

At the very bottom of the file:

Of course this is by far the simplest method of getting all this working.  Some other things you can do is add more exchanges for your applications, just don’t forget to setup the corresponding nodes in the graylog2-web-interface and inside the graylog2-radio inputs config file.

I ran through this entire setup 3 times and I “think” I got all the errors, but if you run into anything please let me know!

Side note: Stream Dashboards seem broken in 0.10.2 of the web-interface


RabbitMQ 설치 관련 오류 

yum install libcom 설치    

RabbitMQ 설치 오류 메시지 처리 방법

Database Hang (/var/log/rabbitmq/startup_log) 
- /var/lib/rabbitmq/mnsia 디렉토리 삭제 후 재시작

Network Startup Failed

- rabbitmq could not start tcp listener 
- netstat -nlp 로 tcp 5672 사용 데몬 확인

As in most cases I'm sure, this issue was caused by a misunderstanding on my part. RHEL provides an amqp server called Qpid which was already running. Since I thought that epmd was running on 5672, I missed the listing for ampq/Qpid in
etstat (not a fan of symbolic ports in the 
output now).

Stopping the Qpid service corrects the problem.

# service qpidd stop & chkconfig --del qpidd



Client SYSLOG 연동 : 기본 시스로그로 연동 시 graylog2에서 host field 값에 프로세스명이 찍히는 버그 발생. 아래의 rsyslog 설치 후 셋팅 진행하도록 workarround.

/etc/rsyslog.conf:

$template GRAYLOG2,"<%PRI%>%HOSTNAME% %TIMESTAMP% %syslogtag% %APP-NAME% %msg%\n"
$ActionForwardDefaultTemplate GRAYLOG2
*.* @graylog-server

/etc/sysconfig/rsyslogd.conf

SYSLOGD_OPTIONS="-c2 -m 0 -r514"


Posted by redkite
, |

24시간 365일 서버/인프라를 지탱하는 기술 - 4.2  아파치 튜닝
발제 : 문태준
http://groups.google.com/group/sysadminstudy

 

4.2    아파치 튜닝      209
        웹 서버 튜닝    209
        웹 서버가 병목현상?    209
        아파치의 병렬처리와 MPM        210
        httpd.conf 설정  216
        Keep-Alive      227
        아파치 이외의 선택방안 검토      227

 

** 이번 장에서는 웹서버에서 프로세스 또는 쓰레드 수를 제어하는 설정항목에 대해 공부를 함.

ㅇ 웹 서버 튜닝

ㅇ 웹 서버가 병목현상?


추축하지 말라! 계측하라!


여기서 살펴보는 것은 아파치 설정항목 중에서 특히 대규모 환경에서 성능에 영향을 미칠 부분에 대해 알아봄

 

ㅇ 아파치의 병렬처리와 MPM

병렬처리의 구현모델 : 멀티프로세스 / 멀티쓰레드 / 이벤트 구동 모델

아파치는 내부의 각종 기능이 모듈화에 의해 깔끔하게 분리되어 있는 것이 특징이며 병렬처리를 수행하는 코어 부분의 구현도 모듈로 되어 있다. MPM Multi Processing Module(http://httpd.apache.org/docs/2.2/ko/mod/)

 

유닉스 환경에서 대표적인 MPM은 다음의 두가지이다.
- prefork : 미리 복수의 프로세스를 생성해서 클라이언트의 접속에 대비하는 멀티프로세스 모델
- worker : 멀티쓰레드와 멀티프로세스의 하이브리드형

 

프로그래밍 모델 관점에서 본 멀티프로세스/멀티쓰레드의 차이
- 멀티프로세스에서는 기본적으로 프로세스 간에 메모리를 직접  공유하지는 않는다. 메모리 공간이 독립해 있으므로 안전한다.
- 멀티쓰레드에서는 메모리 공간 전체를 복수의 쓰레드가 공유하므로, 리소스 경합이 발생하지 않도록 주의할 필요가 있다.

  이것이 멀티쓰레드 프로그래밍이 복잡하다고 하는 이유다.
- prefork : 안정지향, 후방호환성이 높은 MPM
- worker : 확장성이 높은 MPM

 

 

성능 관점에서 본  멀티프로세스/멀티쓰레드의 차이
일반적으로 멀티쓰레드가 가볍고 빠르다. 그 이유는
- 복수의 메모리 공간을 각각 지닌 멀티프로세스보다도 메모리 공간을 공유하는 멀티쓰레드쪽이 메모리 소비량이 적다
-> 멀티프로세스의 경우에도 부모와 자식 프로세스에서 갱신되지 않는 메모리 공간은 공유(Copy on Write) 되므로 그렇게까지 현저한 차이가 나는 것은 아니다.
- 멀티쓰레드는 메모리 공간을 공유하고 있으므로, 쓰레드 전환에 걸리는 비용이 멀티프로세스보다 적다. (컨텍스트 스위치 비용)

- prefork 를 worker로 변경하더라도 하나의 클라이언트에 대한 응답시간이 고속화되는 것은 아니다
- prefork를 worker 로 변경하더라도 메모리가 충분하다면 동시에 처리할 수 있는 접속 수는 변하지 않는다.
- prefork를 worker 로 변경하더라도 대량의 컨텍스트 스위치가 없다면(동시에 병렬적으로 대량의 엑세스가 없다면) 효과는 크지 않다.

 

 

prefork 를 worker 로 변경해서 효과적인 부분
- 이용할 수 있는 메모리 용량이 그다지 크지 않은 경우나, 메모리 소비량을 줄이고자 할 경우. 이런 경우 프로세스보다 메모리 소비량이 적은 쓰레드의 이점이 살아난다.
- 컨텍스트 스위치 횟수가 많아서 그만큼의 CPU 리소스를 줄이고자 할 경우, 즉 대량의 엑세스로 인한 CPU 사용줄이 줄이고자 할 경우. 프로세스보다 쓰레드 쪽이 컨텍스트 스위치 비용은 낮으므로 CPU 소비가 줄어든다.
** 메모리 용량이 크지 않으면 오히려 메모리를 늘리는 것이 더 편하지 않을까?
** 그런데 과연 어떨 때 컨텍스트 스위치 횟수가 많다고 할 수 있을까? 튜닝책에서 나오지만 실제로 어떻게 기준을 잡아야 하는지는 모르겠다.

 

 

하나의 클라이언트에 대한 하나의 프로세스/쓰레드
prefork, worker 공통적인 것은 아파치는 클라이언트로부터 온 하나의 요청에 대해 기본적으로 하나의 프로세스 혹은 하나의 쓰레드를 할당해서 처리한다.
따라서 동시에 생성할 수 있는 프로세스/쓰레드 수가 아파치의 성능을 좌우하는 항목이 된다.
-> 프로세스/쓰레드 수를 제어하는 설정항목의 최적해를 찾는 것


ㅇ httpd.conf 설정
아파치의 안전판 MaxClients : 동시에 접속할 수 있는 클라이언트 개수의 상한값

 

1. prefork 의 경우
ServeLImit : 서버수. 이를테면 prefork 에서는 프로세스 수의 상한
MaxClient : 동시에 접속할 수 있는 클라이언트 수의 상한
prefork 에서는 양자가 거의 같은 의미임.

그러면 이 수치를 어떻게 계산할 것인가?

- /proc/PID/status 에서 특정 프로세스가 실제 사용하고 있는 물리 메모리 영역은 VmHWM 항목임. 그러나 리눅스에서는 물리 메모리를 절약하기 위해 부모 프로세스와 자식 프로세스에서 일부 메모리를 공유함. 이러한 공유부분 메모리를 고려해야 함.

VmHWM: Peak resident set size ("high water mark").
VmRSS: Resident set size.

** VmRSS와 VmHWM의 차이는 무얼까? centos linux-2.6.18 커널소스의 Documentation/filesystem/proc.txt 의 내용은 오래되어 이에 대한 설명이 없음. man proc 에도 rss만 설명이 있음. ps에서는 VmRSS 항목이 나옴.

- 부모, 자식프로세스 간 메모리를 공유하는 Copy On Write
fork 에 의해 생성되면 부모와 자식은 서로 다른 메모리 공간에서 동작하고 서로가 간섭하는 일이 없음. 그러나 fork 에 동반해서 부모로부터 자식에게 메모리의 내용을 있는 그대로 복사하지만 매우 비용이 높음. 그래서 리눅스는 fork 를 한 단계에서는 가상 메모리 공간에 매핑된 물리 메모리 영역은 복사하지 않고 부모와 자식 간에 이를 공유함. 부모 혹은 자식이 가상 메모리에 대해 쓰기를 수행하면, 해당 쓰기 작업이 수행된 영역은 더 이상 공유할 수 없으므로 그 때 처음으로 해당 영역과 연관되어 있는 물리영역만 부조 자식 간에 제각기 가지게 됨.

쓰기 작업시에 복사, fork 에 동반한 메모리 복사의 지연처리
p220 그림 4.2.4 가상 메모리의 카이 온 라이트 그림 참고

- Copy on Wirte 로 공유 메모리 사이즈 확인
공유 메모리 영역은 /proc/pid/smaps 의 데이터를 참조함으로써 확인할 수 있지만 데이터량이 많아 스크립트 등으로 확인하는 것이 좋음. RSS 프로세스 전체의 메모리, SHARED 부모 자식 프로세스간에 공유하고 있는 메모리를 확인.

- 메모리 계산 (예제)
전체 메모리량 4GB
httpd 프로세스 하나당 메모리 사용률 100MB
대략 70%는 부모와 공유한다고 했을 때 자식 프로세스 하나당 메모리 사용량은 30MB
OS 가 이용하는 메모리는 512MB
4GB-512MB=3.5GB 를 httpd 에 할당 3,500/30 = 116.66 -> 대략적인 계산이므로 100으로 설정

-MaxRequestsPerChild
Copy On Write 에 의한 메모리 공유는 시간의 경과에 따라 공유율이 하락해감. 아파치에서는 정기적으로 자식 프로세스를 종류시키고 새로운 자식 프로세스를 생성시켜 이러한 상태를 피해감. 이에 대한 설정이 MaxRequestsPerChild 임. 예를 들어 이 설정이 1024이면 하나의 프로세스당 1024개의 요청을 처리하면 해당 프로세스는  1024번째의 요청완료 직후에 자동으로 종류하고, 부모 프로세스가 새로운 자식 프로세스를 준비함.
이 설정은 mod_perl 이나 mod_php 등에서 동작하고 있는 애플리케이션이 메모리 누수(Memory Lock)을 일으키고 있는데도 이를 방치해두고 항상 계속해서 메모리를 소비하도록 할 경우의 응급처치에도 유효

 

2. worker 의 경우
하나의 프로세스 내에 복수의 쓰레드를 생성하고, 쓰레드 하나로 클라이언트 하나를 처리한다.
해당 프로세스를 복수 개 생성한다.
-> 프로세스*프로세스당 쓰레드 만큼의 쓰레드가 동시병행으로 동작

쓰레드는 프로세스의 경우와 달리, 메모리 공간을 쓰레드끼리 완전히 공유한다. 카피 온 라이트와 같은 경우를 생각할 필요가 없다.
하나의 쓰레드당 스택 영역으로 최대 8,192kb의 메모리를 필요로 한다.

MaxClient : 동시에 접속할 수 있는 클라이언트 수의 상한, 프로세스수 * 쓰레드 수
ServeLImit : 프로세스 수의 상한
ThreadLimit : 프로세스당 쓰레드 수의 상한
ThreadsPerChild : 프로세스당 쓰레드 수(ThreadLimit와 거의 같은 의미)

예를 들면 MaxClients 4096 /  ThreadsPerChild 128  = 32 프로세스

따라서 항상 ServerLlimit >= MaxClients / ThreadPerChild 라는 관계를 충족시키도록 조정한다.

여기서도 시스템에 탑재된 메모리량과 쓰레드 하나당 소비 메모리량을 저울질해서 계산한다. (쓰레드는 ps 에서 -L 옵션 이용)

** p60 ServerLimit/ThreadLImit 와 메모리의 관계 참고. 이 두가지는 아파치가 확보하는 공유 메모리 크기에 영향을 미치기때문에 필요 이상으로 높으면 쓸데없이 공유 메모리를 낭비하게 됨.


- 과부하로 MaxClients 를 변경하기 전
표면상으로 MaxClients 상한선에 도달했다고 해서 웹서버에 문제가 있다고 말을 할 수는 없다. 단지 어딘가에 문제가 있음을 나타낸다.
그림 4.2.6과 같이 DB에 과부하가 걸리는 경우에도 이러한 증상이 나타날 수 있다. 아파치 설정을 변경해서 해결할 문제는 아니다.


ㅇ Keep-Alive
경우에 따라서는 Keep-Alive 가 병목현상의 원인이 될 수 있음. p53 2.1절의 리버스 프록시 절 참조. (리버스 프록시에서는 Keep-Alive ON, 리버스 프록시와 백엔드 AP서버 사이는 Keep-Alive OFF)

 

ㅇ 아파치 이외의 선택방안 검토
아파치 장점 : 깔끔하게 모듈화된 범용적인 구조, 높은 확장성. 웹 서버 이상의 네트워크 서버로 볼 때, 아파치 이상으로 다양한 상황에 사용할 수 있는 서버는 많지 않다.
아파치 성능 : 아파치에서 멀티쓰레드와 Single Process Event Drive (SPED) 는 아키텍처 관점에서 각각 일장일단이 있고 어느 한쪽이 압도적으로 뛰어난 것은 아니다.
아파치 내부구현 : 범용적인 구조로 되어 있어서 하나의 요청에 대한 사이클 내에 필요로 하는 리소스가 모두 약간 많음.

- lighttpd
SPEED 채용, 적은 메모리로 대량의 접속을 동시병행적으로 처리하는 것을 주안에 둔 빠른 구현
아파치에 비해 범용성은 떨어지나 CPU 소모는 적음
싱글프로세스이므로 메모리 소비량이 아파치와 비교해 훨씬 적게 듬
아파치의 코어 모듈, mod_rewrite 나 mox_proxy 에 해당하는 기능은 모두 포함
FastCGI 대응, perl/php/rubby 웹애플리케이션을 고속화해서 ap서버로 이용 가능

아파치와 비교해 가장 현저한 차이는 메모리 소비량.
정적인 파일을 대량으로 전송하고자 할 경우 적합. 대량의 파일을 대량의 클라이언트로 반환할 경우에도 최소한의 리소스 소비
동적인 컨텐츠 전송시는 apache+mod_perl(mod_php) 과 lighttpd + FastCGI 조합으로 비교했을 때 그다지 성능차가 없음

Posted by redkite
, |

Apache 2.x Prefork 방식 Worker 방식 성능 비교

 

외국 블로그를 보다가 Apache 2.x 버전에서 Prefork와 Worker 방식의 성능 비교를 올려 놓은 포스트가 있어 소개 한다.

블로그 원문은 여기를 클릭하면은 된다. 원문 보고 싶으신 분들은 링크 클릭해서 보세요. ^^ 참고로 불필요한 부분은 제외 했습니다.

솔라리스 10(06/06 U10)에서 Apache 2.2.4를 하나는 prefork MPM으로(-- with-mpm=prefork) 컴파일하고 다른 하나는 worker MPM으로(--with-mpm=worker)로 컴파일을 했다.

Prefork는 일반적으로 Single CPU 또는 Dual CPU에서 성능이 좋고 Worker는 일반적으로 멀티 CPU 시스템에서 성능이 좋다.

각 MPM은 기본 설정을 사용하였다.

  • Prefork
    <IfModule mpm_prefork_module>
          StartServers                   5
          MinSpareServers            5
          MaxSpareServers          10
          MaxClients                  150
          MaxRequestsPerChild     0
     </IfModule>
  • Worker
    <IfModule mpm_worker_module>
           StartServers                 2
           MaxClients               150
           MinSpareThreads       25
           MaxSpareThreads      75
           ThreadsPerChild         25
           MaxRequestsPerChild   0
    </IfModule>

그리고 테스트(Siege)를 위한 설정은 아래와 같다

  • Concurrent = 10
  • Time = 5M
  • Benchmark = true


Prefork에서 Apache Bench 결과(원문 그대로 사용)

% ./ab -n 10000 -c 10 http://192.168.1.80/index.html
...
Server Software: Apache/2.2.4
Server Hostname: 192.168.1.80
Server Port: 80

Document Path: /index.html

Document Length: 44 bytes
Concurrency Level: 10
Time taken for tests: 478.185521 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 3160000 bytes
HTML transferred: 440000 bytes
Requests per second: 20.91 [#/sec] (mean)
Time per request: 478.185 [ms] (mean)
Time per request: 47.819 [ms] (mean, across all concurrent requests)
Transfer rate: 6.45 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 2 95.4 0 3380
Processing: 1 472 1178.0 2 10139
Waiting: 0 41 389.2 0 1013
Total: 1 475 1182.0 2 10139

Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 3
80% 4
90% 3372
95% 3377
98% 3379
99% 3381
100% 10139 (longest request)


Prefork에서 Siege 결과(원문)
Lifting the server siege... done. 
Transactions: 6045 hits
Availability: 100.00 %
Elapsed time: 300.38 secs
Data transferred: 0.25 MB
Response time: 0.50 secs
Transaction rate: 20.12 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 9.97
Successful transactions: 6045
Failed transactions: 0
Longest transaction: 10.13
Shortest transaction: 0.00



Worker 아파치 벤치(원문)
% ./ab -n 10000 -c 10 http://192.168.1.80/index.html
...
Server Software: Apache/2.2.4
Server Hostname: 192.168.1.80
Server Port: 80

Document Path: /index.html
Document Length: 44 bytes

Concurrency Level: 10
Time taken for tests: 244.283673 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 3160000 bytes
HTML transferred: 440000 bytes
Requests per second: 40.94 [#/sec] (mean)
Time per request: 244.284 [ms] (mean)
Time per request: 24.428 [ms] (mean, across all concurrent requests)
Transfer rate: 12.63 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 75.4 0 3378
Processing: 1 239 870.1 1 11898
Waiting: 0 16 229.6 0 3388
Total: 1 241 872.9 1 11898

Percentage of the requests served within a certain time (ms)
50% 1
66% 2
75% 2
80% 2
90% 4
95% 3373
98% 3379
99% 3380
100% 11898 (longest request)


Worker에서 Siege 결과(원문
Lifting the server siege... done. 
Transactions: 11024 hits
Availability: 100.00 %
Elapsed time: 300.24 secs
Data transferred: 0.46 MB
Response time: 0.27 secs
Transaction rate: 36.72 trans/sec
Throughput: 0.00 MB/sec
Concurrency: 9.91
Successful transactions: 1102
Failed transactions: 0
Longest transaction: 11.92
Shortest transaction: 0.00

MPM을 Worker로 했을때가 Prefork보다 약 두배정도 빠른 결과가 나왔다.

위의 결과를 봤을때 성능상의 이유로 Apache의 MPM을 Worker로 하는가 Prefork로 하는가 하는 결정을 해야될때 Worker방식으로 설정을 하는 것이 고성능을 얻을 수 있을거 같다.

Posted by redkite
, |

요약하자면 worker 방식이 prefork 방식에 비해 평균 2배 가량의 반응시간 단축 효과가 있다고 함

Apache prefork vs. worker

 
Tags:

I compiled 2 different versions of apache 2.2.4 on Solaris 10 (06/06, on a crappy U10, but...) one using the prefork MPM (compile --with-mpm=prefork) and the other using the worker MPM (compile --with-mpm=worker). Prefork is supposed to generally be better for single or dual cpu systems, and worker is supposed to be generally better for multi-CPU systems. The following are the Apache Bench results run against each build on an old Sun Ultra 10 with a single 440mhz CPU and 512m RAM. The server isn't impressive, but it works for bench-testing the MPMs...

I used the default settings for each MPM:

-------------------------------------------------------------
<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxClients          150
    MaxRequestsPerChild   0
</IfModule>

<IfModule mpm_worker_module>
    StartServers          2
    MaxClients          150
    MinSpareThreads      25
    MaxSpareThreads      75
    ThreadsPerChild      25
    MaxRequestsPerChild   0
</IfModule>
-------------------------------------------------------------

and the siege tests were run with the following settings:

-------------------------------------------------------------
concurrent = 10
time = 5M
benchmark = true
-------------------------------------------------------------


Apache Bench results for prefork:

-------------------------------------------------------------
% ./ab -n 10000 -c 10 http://192.168.1.80/index.html

...

Server Software:        Apache/2.2.4
Server Hostname:        192.168.1.80
Server Port:            80

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      10
Time taken for tests:   478.185521 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160000 bytes
HTML transferred:       440000 bytes
Requests per second:    20.91 [#/sec] (mean)
Time per request:       478.185 [ms] (mean)
Time per request:       47.819 [ms] (mean, across all concurrent requests)
Transfer rate:          6.45 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2  95.4      0    3380
Processing:     1  472 1178.0      2   10139
Waiting:        0   41 389.2      0   10138
Total:          1  475 1182.0      2   10139

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      3
  80%      4
  90%   3372
  95%   3377
  98%   3379
  99%   3381
 100%  10139 (longest request)
-------------------------------------------------------------

Siege results for prefork:

-------------------------------------------------------------
Lifting the server siege...      done.                                                    
Transactions:                   6045 hits
Availability:                 100.00 %
Elapsed time:                 300.38 secs
Data transferred:               0.25 MB
Response time:                  0.50 secs
Transaction rate:              20.12 trans/sec
Throughput:                     0.00 MB/sec
Concurrency:                    9.97
Successful transactions:        6045
Failed transactions:               0
Longest transaction:           10.13
Shortest transaction:           0.00
-------------------------------------------------------------

Apache Bench results for worker:

-------------------------------------------------------------
% ./ab -n 10000 -c 10 http://192.168.1.80/index.html

...

Server Software:        Apache/2.2.4
Server Hostname:        192.168.1.80
Server Port:            80

Document Path:          /index.html
Document Length:        44 bytes

Concurrency Level:      10
Time taken for tests:   244.283673 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      3160000 bytes
HTML transferred:       440000 bytes
Requests per second:    40.94 [#/sec] (mean)
Time per request:       244.284 [ms] (mean)
Time per request:       24.428 [ms] (mean, across all concurrent requests)
Transfer rate:          12.63 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1  75.4      0    3378
Processing:     1  239 870.1      1   11898
Waiting:        0   16 229.6      0    3388
Total:          1  241 872.9      1   11898

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      2
  75%      2
  80%      2
  90%      4
  95%   3373
  98%   3379
  99%   3380
 100%  11898 (longest request)
-------------------------------------------------------------

Siege results for worker:

-------------------------------------------------------------
Lifting the server siege...      done.                                                      
Transactions:                  11024 hits
Availability:                 100.00 %
Elapsed time:                 300.24 secs
Data transferred:               0.46 MB
Response time:                  0.27 secs
Transaction rate:              36.72 trans/sec
Throughput:                     0.00 MB/sec
Concurrency:                    9.91
Successful transactions:       11024
Failed transactions:               0
Longest transaction:           11.92
Shortest transaction:           0.00
-------------------------------------------------------------


So for this setup, the worker MPM was almost twice as fast as the prefork.
I'm going to run these same tests on a multi-cpu server and see what the results look like.


My server(2ghz opteron) ran prefork apache and it was sometimes being
overloaded with 500 concurrent processes. The cpu usage was low which was
puzzling. I tried changing over to worker MPM and its been running great.

Unfortunately, PHP5 does not work with the Worker MPM. On my Ubuntu server, PHP5 can only be installed with the Prefork MPM. Meaning that my server, which has 4 dual-core Opterons, is not being used optimally if I've understood correctly :-(

PHP5 can work with MPM Worker too. But you have to use CGI or FastCGI instead of Apache module. I've written some instructions on how to do it: Install Apache2 MPM Worker and PHP5 using mod_fcgid.

Compile PHP after installing your apache and it will quite happily work with the MPM Worker.

Does fcgi is different from cgi, So if i run cgi script i dont want to specify the path anymore. Is it so?

Nice work, thanks.

Have you finished benchmarks with multire core cpu?

I've been dragged away on other projects and haven't had the chance yet.

I installed apache 2.2 on Sun5.9 with worker mpm. The machine has 2G RAM on it and one 1.2Ghz processor. How many MaxClients do you think I can go with? I specified 500 and it is working okay so far.

-SK

A "typical" apache process uses between 5mg and 8mg of RAM.

I found results for big multicore machine on this page: http://www.thrull.com/corner/webserver/prefork-vs-worker/

If you switch from Ubuntu (a medium grade OS) to this (NetBSD/UnixWorld) which supposed to be (an high-end, enterprise Grade OS),
you fill find that:
- Apache with MPM worker deals great with PHP 5.2.9
- It is the fastest ever server (the kernel has no limits as they built in the linux kernel).

I know :-) as I participated into tests...

(see this article, I am talking about)
http://www.unix-world.org/index.php?page=_news_events&id=6730792567

They use the MySQL Enterprise GPL sourcecode :-)
which is different from MySQL Community !
(un unix-world server)

 

Posted by redkite
, |

Apache 튜닝

 

ab를 이용해서 -c(한번에수행할 다중요구수) 값을 1000으로하고, -n(페이지요청수) 값을 1000 으로 하였으며 -t(테스트허용 최대시간)값을 10으로 주는 예이다.
[root@www ~]# ab -c 1000 -n 1000 -t 10 http://koreasaint.com/

Time per request:       745.829 [ms] (mean)


http://www.hpl.hp.com/research/linux/httperf/
[root@www ~]# httperf --server koreasaint.com --port 80 --rate 1000 --num-conns 20000 --hog 
Reply time [ms]: response 9.6 transfer 0.0


Timeout

접속된 클라이언트가 서버에 아무런 요청이 없을 때 어느정도 시간이 지나면 연결을 끊을지를 초단위로 설정한다. 네트웍의 성능이 낮을수록 이 수치를 높게 설정하는 것이 좋다.

 


MaxClients

웹서버 성능에 가장 큰 영향을 주는 것은 메모리다. 방문자의 요청에 응답하기 위해서 프로세스가 생성되는되 이 지시자의 개수만큼만 생성가능하다. 여기서 지정한 개수 이상의 요청이 들어오면 아파치는 요청을 무시한다.

MaxClients 지시어를 조절하여 웹서버가 스왑을 할 정도로 많은 프로세스를 만들지 않도록 해야 한다. 스왑은 요청당 지연시간을 늘리기 때문에 웹서버는 스왑을 하면 안된다. top으로 프로세스 목록을 보고 아파치 프로세스의 평균 메모리 사용량을 알아낸후, 사용가능한 메모리의 양만큼 조절해준다

 


KeepAlive

아파치의 한 프로세스가 접속한 클라이언트의 지속적인 요청작업을 계속해서 처리하게 할 것인지를 결정하는 지시자. 이 지시자의 값을 On으로 되어 있어야 MaxKeepAliveRequests , KeepAliveTimeout 지시자가 유효하게 된다

 


MaxKeepAliveRequests

이전의 KeepAlive 지시어가 On 일때만 유효하다. KeepAlive 를 이용해서  한 프로세스가 접속한 클라인언트의 이어지는 요청을 모두 처리하도록 설정했는데, 이때 무한정 계속 처리하는것이 아니라 이 지시자를 이용해서 처리할 횟수를 지정해준다. MaxKeepAliveRequests 100 처럼 설정해두면 프로세스가 100번의 요청을 처리한후 자신은 죽고 그다음 프로세스가 다시 클라인언트의 요청을 이어서 처리하도록 하는것이다. 방문자가 많은 홈페이지라면 이 값을 좀 올려두는것이 좋다

 


KeepAliveTimeout

이전의 KeepAlive 지시어가 On 일때만 유효하다. KeepAlive 를 사용한다면 프로세스들은 이미 열린 연결에서 추가 요청을 기다리며 대기중이다.

KeepAliveTimeout 15 처럼 설정해두면 클라이언트가 15초동안 아무요청이 없으면 프로세스의 연결을 끊는다. 이 값을 60 초 이상으로 올리면 사용자의 요청을 기다리며 아무일을 하지않는 프로세스가 60초동안 떠있게 되는것이다. 자신의 네트웍대역과 부하에 따라 적절히 조절하자. 기본값 15 로도 무방하다

 


StartServers

아파치 시작시에 실행시킬 프로세스의 개수. 뒤에나오는 MinSpareServers, MaxSpareServers 등의 지시자에 의해서 프로세스는 생성되기도 하고 죽기도 하므로 큰 의미를 가지는것은 아니다.

 


MinSpareServers

항상 대기하고 있을 프로세스의 최소개수. 여기서 지정한 숫자보다 적은 프로세스가 대기되어 있다면 아파치는 가능한 이 숫자를 유지하기위해 노력한다.

 


MaxSpareServers

항상 대기하고 있을 프로세스의 최대개수. 여기서 지정한 숫자보다 많은 프로세스가 대기되어 있다면 아파치는 가능한 이 숫자를 유지하기위해 노력한다.

 


MaxRequestsPerChild

하나의 프로세스당 최대 처리할 수 있는 방문자의 요청횟수

서버사양이 좋다면 이 값을 높여 두는것이 시스템의 부하조절과 자원낭비를 방지하는데 좋다.

 


HostnameLookups

웹서버의 로그(access_log)에 보면 클라이언트의 IP가 기록되어있는데 이 지시자를 On으로 설정하면 IP주소를 도메인명으로 기록하기위해서 노력을 하게된다.

아파치 1.3 이전에 HostnameLookups의 기본값은 On이였다.

이말은 접속을 요청하면 DNS를 검색해서 접속자의 호스트명을 알아내어야 한다는것이다,. 아파치 1.3에서 이 설정의 기본값이 Off로 변경되었다.

아파치의 성능을 생각한다면 반드시 Off 로 설정하기 바란다.

만일 로그파일의 주소를 호스트명으로 변환할 필요가 있다면 아파치에 포함된 logresolve 프로그램을 사용해서 나중에 할수있으니 실제 사용하는 웹서버가 아닌 다른 컴퓨터에서 로그파일을 후처리하길 바란다.

 


다른 설정에서 DNS 질의 고려

Allow from domain이나 Deny from domain 지시어를 사용한다면 (즉, IP 주소가 아닌 호스트명이나 도메인명을 사용한다면) 부득이 중복-역 DNS 검색을 (역검색을 한후 악의로 변경되었는지 확인하기위해 다시 검색) 해야 한다. 그러므로 성능을 높이기 위해 이런 지시어에는 가능하면 이름대신 IP 주소를 사용하자

 


FollowSymLinks와 SymLinksIfOwnerMatch

가능하면 심볼릭링크를 허용하지 않는것이 보안상 좋다. 하지만 꼭 써야한다면 Options SymLinksIfOwnerMatch 보다는 Options FollowSymLinks를 사용하라

Options SymLinksIfOwnerMatch 일 경우 아파치는 심볼릭 링크를 검사하기위해 시스템호출을 한번 더 해야 한다. 좋은 성능을 얻으려면 SymLinksIfOwnerMatch는 피하자

 


AllowOverride

AllowOverride 는 이전에 설정된 아파치 환경설정을 무시하고 새로운 설정을 적용하는 방법에 대한 설정이다. AccessFileName 을 별도로 설정하지 않았다면 아파치는 .htaccess 파일을 디렉토리 접근인증에 사용한다.

설정할수 있는 지시자는 다음과 같다.

 


AuthConfig 

AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, require 등과 같은 클라이언트 인증지시자의 사용을 허용.

 

 

FileInfo

AccessFileName 으로 지정한 파일에 대하여 AddEncoding, AddLanguage, AddType, DefaultType, ErrorDocument, LanguagePriority 등과같은 문서유형을 제어하는 지시자 사용을 허용

 

 

Indexes

AccessFileName 으로 지정한 파일에 대하여 AddDescription, AddIcon, AddIconByEncoding, DirectoryIndex, FancyIndexing 등과같은 디렉토리 인덱싱을 제어하는 지시자 사용을 허용

 

 

Limit

AccessFileName 으로 지정한 파일에 대하여 allow, deny, order 같은 호스트접근을 제어하는 지시자사용을 허용

 

 

Options

AccessFileName 으로 지정한 파일에 대하여 Options 지시자를 이용한 재설정을 허용

 

 

All

위에서 이야기한 모든 것을 허용

 

 

None

AccessFileName 으로 지정한 파일을 무시. 어떠한 설정도 재설정 할수 없다.

 


만일 overrides를 허용한다면 아파치는 파일명의 각 부분마다 AccessFileName 으로 지정한 파일(대부분 .htaccess)을 열길 시도한다. 예를 들어 설정은 아래와 같고,

 


DocumentRoot /www/htdocs

<Directory />

AllowOverride all

</Directory>

 


/index.html URI에 대한 요청이 있다고 가정하자.

아파치는 /.htaccess, /www/.htaccess, /www/htdocs/.htaccess를 매번 열려고 시도한다. 최고의 성능을 얻으려면 항상 AllowOverride None을 사용하자.

 


EnableMMAP

커널에서 메모리매핑(mmap)을 지원한다면 아파치가 웹문서를 로딩하기 위하여 내부문서를 읽을때에 파일을 메모리 매핑하여 처리한다. 따라서 아파치의 성능이 크게 향상될수 있다.

그러나 메모리대응이 서버의 성능을 떨어트리고 심지어 안정성을 해치는 경우가 있고 smp Solaris 서버에서 아파치 2.0은 종종 mmap을 사용하지 않을때가 더 빠르다. 또한 NFS 마운트한 파일시스템에 있는 파일을 메모리 대응하는 도중에 다른 NFS 클라이언트에 있는 프로세스가 파일을 지우거나 파일크기를 줄이면, 웹서버 프로세스가 다음 번에 메모리대응한 파일내용을 읽을때 bus error가 발생할 수 있다.

위의 조건에 해당하면 전송하는 파일을 메모리대응하지 않도록 EnableMMAP off를 사용해야 한다.

 


EnableSendfile

아파치는 운영체제가 sendfile을 지원하면 커널 sendfile을 사용하여 정적 파일을 서비스하는 경우 전송할 파일을 직접 읽지않을 수 있다. sendfile을 사용하면 read와 send를 따로 할 필요가 없어서 매우 빨라진다.

그러나 sendfile을 사용하면 웹서버의 안정성을 해치게되는 경우가 있고, 커널은 자신의 캐쉬를 사용하여 NFS로 마운트한 파일을 안정적으로 서비스할 수 없는 경우가 있으므로 EnableSendfile off를 사용해서 파일을 sendfile 전송하지 않도록 할수 있다.

 

Posted by redkite
, |

  

 

 

Part 1.  Installation

……….……………………..…….………………………

3

 

1. 설치전 유의사항

………………..…………….…………….………………

4

 

2. Install 절차 (Unix환경)

……………….…………….………………….…………

7

3. UnInstall 절차

……………..….….………….……………….…………

13

 

 

 

 

Part 2.  주요 환경 설정

…………………..…………….……………………….

14

 

1. 버전 확인

…………………….…….……………….……………

15

2. Document 설정

…….……………..….….……………….……………

15

3. Directory Indexing

…………………..…………….……………….…..…

15

4. Log rotate 설정

….……………..….…….……………….……………

16

5. JDK 설정

.………………..….…….……………….……………

19

6. JSP/Servlet 설정

….……………..….…….……………….……………

20

7. CGI 설정

..…………………..…….……………….……………

20

8. PHP 설정

..…………………..…….……………….……………

21

9. 인증서 설치

………………………….……………….…………….

24

10. WebLogic 연동

..………………………….……………….……………

33

11. password 변경하기

………………………….……………….…………….

35

Part 3.  Tuning

………………………………….………………………

36

 

 

 

 

Part 4.  Q&A

………………………………….………………………

41

 

 

 

 

 

 


 

 

 

Part

1I

 

 

 

 

 

 

 

 

 

 

 

       Installation

 

 

 

 

 


 

웹서버 제품 설치전 요구사항 목록, Install 절차,

그리고 Uninstall에 대해 제시합니다.

 

 

 

 

 

 

I. 설치 전 유의사항

 

 

 

 

 

 

 

 

 

 

 

 

 


 

(1) 지원 플랫폼

Sun One Web Server가 지원되는 플랫폼은 다음과 같습니다.

  S1WS 4.1

Operating System

Architecture

Required Memory

Required Disk Space

Compaq Tru64 4.0d, 4.0e*, 4.0f* 

Alpha

64 MB minimum

130 MB minimum

Hewlett-Packard HP-UX 11.0, 11.0 64-bit* 

PA-RISC

64 MB minimum

90 MB minimum

Silicon Graphics** SGI IRIX 6.5.6 

MIPS

64 MB minimum

110 MB minimum

Sun Solaris 2.6, 7*, 8 

SPARC

64 MB minimum

130 MB minimum

Windows NT 4.0 

Pentium

64 MB minimum

100 MB minimum

RedHat Linux 2.2.12 with glibc 2.1.2 (RedHat 6.1) 

x86

64 MB minimum

90 MB minimum

IBM AIX 4.3.3 

Power PC

64 MB minimum

90 MB minimum

 

  S1WS 6.0

Operating System

Architecture

Required Memory

Required Disk Space

Hewlett-Packard HP-UX

11.0, 11.0 64 bit , 11i

PA-RISC

at least 256 MB

at least 110 MB

IBM AIX 4.3.3, 5.1

Power PC

at least 256 MB

at least 110 MB

Sun Solaris2.6, 7, 8 , 9

UltraSPARC

at least 256 MB

at least 110 MB

Microsoft Windows NT 4.0SP6a

Windows 2000 Server SP2

Pentium

at least 512 MB

at least 2GB

Red Hat Linux6.2

Red Hat Linux 7.1 2.96-79

X86

at least 256 MB

at least 110 MB

 

 

(2) 패치 목록

  S1WS 4.1

Solaris

Solaris 2.6 : 105181-11  105210-17  105568-13  105633-21

105669-04  106040-11  106495-01  106842-03  106841-01

106409-01 (for traditional Chinese fonts and the JDK)

107733

Solaris 7 : 106541-12  106980-04  108376-08

HP-UX Patches

PHCO_19047  PHCO_19666  PHCO_20765  PHCO_20882

PHKL_18543   PHKL_20016  PHKL_20079   PHKL_20674

PHKL_21003   PHNE_20008  PHNE_20735  PHSS_16587

Windows NT Service Packs

Windows NT 4.0 SP6A

Compaq Tru64 Patches

Patch kit 3,  Patch kit 4,  Patch kit 5, Patch kit 6

 

  S1WS 6.0

Solaris

Solaris 2.6 : 105591-09

Solaris 7 : Use the latest Solaris patches for Solaris 7.

Solaris 8: 108528-16

HP-UX Patches

In addition to using the General-Release Patch Bundles (XSWGR1100), the following operating system patch (applicable and specific to HPUX11i, 11.11 only) must be installed: PHNE_23645.

Windows NT Service Packs

Windows NT 4.0 SP6A

AIX

AIX 4.3.3 : Patches 01 to 08 are required.

AIX 5.1 : Patches 01 to 02 are required..

 

(3)  브라우저 요구사항

-          Netscape Communicator 4.74 이거나 그 이상

-          Microsoft Internet Explorer 5.0 (NT일 경우5.0 or higher)

 

(4) 연동 가능한 JDK 버전

  S1WS 4.1

Solaris 2.6, 7*, 8 (SPARC )

JDK 1.2.2_01 or higher

HP-UX 11.0, 11.0 64-bit* (PA-RISC )

JDK 1.2.2.02

Windows NT 4.0 (Pentium)

JDK of 1.2.2_01 or higher

IBM AIX 4.3.3 (Power PC)

JDK 1.2.2.

Compaq  Tru64 4.0d, 4.0e*, 4.0f* (Alpha)

JDK 1.2.2-3 or higher

Linux 2.2.12 with glibc 2.1.2 (RedHat 6.1) (x86)

JDK of 1.2.2 or higher

Silicon Graphics** SGI IRIX 6.5.6 (MIPS)

 

 

 

  S1WS 6.0 (JDK1.3.1 연동 가능)

 

Solaris 2.6, 7, 8, 9 (UltraSPARC )

Solaris VM Java version 1.2.2 (build Solaris_JDK_1.2.2_010, native threads, sunwjit)

HP-UX 11.0, 11.0 64-bit, 11i (PA-RISC )

Java version 1.2.2.10 Classic VM (build 1.2.2.10-01/09/14-PA_RISC2.0, native threads, HP) 

Windows NT 4.0 SP6a, Windows 2000 Server SP2(Pentium )

Java version 1.2.2 Classic VM (build JDK-1.2.2_010, native threads, symcjit) 

Red Hat Linux 6.2 ,

kernel 2.2.14-12,  glibc 2.1.3-15 

Red Hat Linux 7.1 2.96-79,

glibc-2.2.2-10, libncurses.so.4

(X86)

Java version 1.2.2 Classic VM (build Linux_JDK_1.2.2_RCA, native threads, sunwjit) 

 

(5)  기타 요구사항

 

-          Web Server를 동작시킬 사용자를 생성해야 하는데, 보안을 위해서 아무런 권한을 갖지 않은 user와 group을 생성해야 하는데 보통 nsuser user 와 nsgroup group 을 생성하도록 권장합니다.

-          Unique한 port번호를 선택합니다. : 사용하고자 하는 포트 번호가 unique한 것인지 확인 합니다. Administration port는 디폴트로 8888포트이고 web server의 디폴트 포트는80입니다. 만약 디폴트 포트를 사용하지 않고 임의로 정하려 한다면 server를 설치 하기 전에 사용하고자 하는 포트가 사용 중인지 확인하여야 합니다.


 

2. Install 절차 (unix 환경)

 

 

 

 


 

(1) 설치사용자 선택

Sun ONE Web Server를 설치하기 전 root로 로그인 하여야 합니다.. Root로 로그인 해야 한다.

-  1024보다 아래의 포트로는 Sun ONE Web Server를 설치할 수 없습니다.

- 서버를 설치하는 방법중 Expression installation이 있는데 root로 로그인 하지 않으면 Expression installation을 할 수 없습니다.

 

(2) 설치파일 Unpacking

1. 설치 파일을 둘 임시 디렉토리를 생성합니다.

2. 이 디렉토리에 압축된 설치 파일을 copy 합니다.

3. 압축을 풉니다.

- CD 일 경우 : tar –xvf filename.tar

- Download 받았을 경우 : gzip –dc filename.tar.gz | tar xvf -

4. 압축을 풀고 그 디렉토리에 다음 파일들이 있는지 확인 합니다.

: LICENSE.txt , README.txt , setup , and  setup.inf  ……

 

 

(3) 설치 절차

 

Install하는 과정에서, 3가지 installation방법 중에서 하나를 선택할 수 있습니다. : Express, Typical Or Custom . 대부분 Typical or Custom으로 설치하고 또 권장하고 있습니다. Express로 설치하려면 반드시 root로 로그인 해야 합니다.

 

 

Typical or Custom Installation

 

1.      설치파일의 압축을 풀어놓은 디렉토리로 이동합니다.

2.      설치를 시작하기 위해 ./setup을 타이핑 합니다.

3.       아래 표가 설치되는 과정을 나타낸 것입니다.

[lovet jhchoi:~/install/iws6.0 ]ls

./   README.txt  install.inf  setup.inf  template.inf 

../  WebServer/  installWrapper* LICENSE.txt setup*

    template.inf_backup

 

[love jhchoi:~/install/iws6.0 ]./setup

설치파일의 압축을 풀어놓은 디렉토리로 이동하고 설치를 시작한다. :./setup

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Welcome to the iPlanet Web Server installation program. This program will install iPlanet Server Products and the iPlanet Console on your computer.

It is recommended that you have "root" privilege to install the software

 

Tips for using the installation program:

 

-Pess "Enter" to choose the default and go to the next screen

-Type "Control-B" to go back to the previous screen

-Type "Control-C" to cancel the installation program

-You can enter multiple items using commas to separate them. For example: 1, 2, 3

 

Would you like to continue with installation? [Yes]:

 

install을 계속하기위해 yes한다.

 

- Enter : default 를 받아들이는 옵션

- Ctrl+B : install중 전화면으로

돌아간다.

- Ctrl+C : install 을 중단한다.

- 다양한 값들을 ,로 구분한다.

(for example 1,2,3 )

-                  

 

 

 

Sun Netscape Alliance

iPlanet  Web Server  Installation/Uninstallation

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

BY INSTALLING THIS SOFTWARE YOU ARE CONSENTING TO BE BOUND BY

AND ARE BECOMING A PARTY TO THE AGREEMENT FOUND IN THE

LICENSE.TXT FILE. IF YOU DO NOT AGREE TO ALL OF THE TERMS

OF THIS AGREEMENT, PLEASE DO NOT INSTALL OR USE THIS SOFTWARE.

 

Do you agree to the license terms? [No]: y

 License에 동의할 것인지를 묻는다. No를 선택하면 설치를 중단한다

 

License을 읽고자 한다면 install을 중단하고 설치 디렉토리에 있는 LICENSE.txt를 읽고 다시 install 한다.

 

 

 

 

Sun Netscape Alliance

iPlanet  Web Server  Installation/Uninstallation

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

Choose an installation type:

 

1. Express installation

  Allows you to quickly install the servers using the most

  common options and pre-defined defaults. Useful for quick

  evaluation of the products.

2. Typical installation

   Allows you to specify common defaults and options.

3. Custom installation

   Allows you to specify more advanced options. This is

   recommended for experienced server administrators only.

 

To accept the default shown in brackets, press the Enter key.

Choose an installation type [2]:

 install type 을 묻는다.

 

Install type으로 Express, Typical

그리고 Custom이 있는데,

대부분 Typical or Custom으로 설치하고 또 권장하고 있다.

 

Express로 설치하려면 반드시 root로 로그인 해야 한다.

 

(디폴트 값인 typical을 선택한다)

 

 

Sun Netscape Alliance

        iPlanet Web Server Installation/Uninstallation

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

This program will extract the server files and install them

into a directory you specify. That directory is called the

server root in the product documentation and will contain

the server programs, the Administration Server, and the server

configuration files.

 

To accept the default shown in brackets, press the Enter key.

Install location [/usr/iplanet/servers]:

 웹 서버가 설치될 디렉토리를 묻는다.

/usr/netscape/servers라고 하면

 

웹 서버는

/usr/netscape/servers에 설치된다.

 

 

 

Sun Netscape Alliance

      iPlanet Web Server Installation/Uninstallation

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

iPlanet Web Server components:

 

Components with a number in () contain additional

subcomponents which you can select using subsequent screens.

 

1. iPlanet Web Server, Enterprise Edition (5)

 

Specify the components you wish to install [All]:

모든 components를 선택한다.

Press Enter.

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

iPlanet Web Server, Enterprise Edition components:

 

Components with a number in () contain additional

Subcomponents which you can select using subsequent

screens.

 

    1. Server Core

    2. Java Runtime Environment

    3. Java Support

    4. Search and Indexing Support

    5. SNMP Support

Specify the components you wish to install [1, 2, 3, 4, 5]:

install할 subcomponents를 선택한다.추후에 필요한 것은 다시 설치 가능하다.

Press enter!

1.Server Core: Administration

Server와 첫번째 iws의 instance를 설치하는 것

2.Java Runtime Environment :

java를 사용할 계획이라면 JRE or JDK를 반드시 설치해야 한다.

3.Java Support : Java Servlet을 사용할 계획이라면 이 subcomponent

를 설치한다.

4.Search and Indexing Support.

5.SNMP Support.: server를 모니터하기 위해 SNMP를 사용할 계획이라면 이것을 설치해야 한다.

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

 Enter the fully qualified domain name of the computer

on which you're installing server software. Using the form

<hostname>.<domainname>

Example: eros.airius.com.

 

To accept the default shown in brackets, press the Enter key.

 

Computer name [love.daou.co.kr]:

host domain name이다.

 지정하거나 혹은 디폴트 값을 받아 들인다.

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Choose a Unix user and group to represent the iPlanet server

in the user directory.  The iPlanet server will run as this user.

It is recommended that this user should have no privileges

in the computer network system.  The Administration Server

will give this group some permissions in the server root

to perform server-specific operations.

 

If you have not yet created a user and group for the iPlanet

server,create this user and group using your native UNIX

system utilities.

To accept the default shown in brackets, press the Return key.

System User [nobody]:nsuser

 iPlanet Web Server를 동작시킬 시스템상의 등록된 사용자를 넣는다. 이때 사용되는 사용자 계정은 시스템 내에서 다른 어떠한 권한도 가지고 있지 않은 계정이어야

한다.                 

앞에서 생성한 nsuser를 입력한다.

 

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Choose a Unix user and group to represent the iPlanet server

in the user directory.  The iPlanet server will run as this user.

It is recommended that this user should have no privileges

in the computer network system.  The Administration Server

will give this group some permissions in the server root

to perform server-specific operations.

If you have not yet created a user and group for the iPlanet

server,create this user and group using your native UNIX

system utilities.

To accept the default shown in brackets, press the Return key.

 

System User [nsuser]:

System Group[nobody];nsgroup

 iPlanet Web Server를 동작시킬 시스템상의 등록된 사용자 그룹을 넣는다. 이때 사용되는 사용자 그룹은 시스템 내에서 다른 어떠한 권한도 가지고 있지 않은 그룹이어야

한다.                 

앞에서 생성한 nsgroup을 입력한다

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

The iWS Administration Server is separate from the other web servers on the system and should not be confused with the Mission Control Admin Server.  It is recommended that the iWS Administration Server run with a different user id than those used by the other web servers on the machine.

The Administration Server user is the only user able to write web server configuration files.  If the iWS Administration Server is run as "root",,the administration GUI can be used to start and stop web servers.

 

Run iWS Administration Server as [root]:

 Administration Server를 운영할 사용자를 입력한다. 서버 관리자는 새로운 서버를 설치할 수도 있고 설치된 서버를 실행 시킬 수도 있어야 한다. 만일 파일 시스템으로의 접근권한을 갖고 있지 않은 사용자를 설정한다면 새로운 서버의 설치 또는 실행은 성공하지 못할 것이다.

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

The iWS Administration Server requires its own administrative user name and password for GUI access.  When you access the iWS Administration Server GUI, it will prompt you for the administrative user name and password.

Please select a user name and password now.

 

iWS Admin Server User Name [admin]:

 인증하기 위한 Admin 의 name을 입력한다.

웹 브라우저로 웹 서버에 접근할 때 로그인 창이 뜨는데 그때

입력하는 user_name과 password 이다

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

The iWS Administration Server requires its own administrative user name and password for GUI access.  When you access the iWS Administration Server GUI, it will prompt you for the

administrative user name and password.

Please select a user name and password now.

 

iWS Admin Server User Name [admin]:

iWS Admin Server Password:

iWS Admin Server Password (again):

인증하기 위한 Admin 의 패스워드를 입력한다.

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

The iWS Administration Server also listens to a different port (with

restricted access).  Pick a port number between 1024 and 65535 on which to run your iWS Administration Server.  It must be different than the Mission Control Admin Port and your web

server port.

 

iWS Admin Server Port [8888]:

 Admin server의 포트 번호를 입력한다. (1024 ~ 65535 사이의 포트 번호를 입력한다.)Default는 8888이고 이미 사용되고 있는 포트 번호는 사용할 수 없다.

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Pick a port number between 1024 and 65535 on which to run your Web Server.

You should NOT use a port number on which you plan to run other servers.

 

Web Server Port [80]:

 Web Service(HTTP) 포트를 지정한다. 기본포트는 80번이다

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Enter content root for the Web Server.

 

Web Server Content Root [/usr/iplanet/servers/docs];

 Web server의 content file들의 root 디렉토리를 묻는 것이다. Content file들의 디렉토리를 default가 아닌 다른 곳으로 하고자 한다면 그 디렉토리의 절대 경로를 여기에 적어준다

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Java support in the Web Server requires either a Java Runtime

Environment (JRE) or a Java Development Kit (JDK) of version 1.2 or greater.

 

While a default JRE is provided, you may use any JDK with the Web Server.

 

Do you want to use your own JDK [No]:

설치 되어있는 JDK의 경로를 잡아줄 것인지를 묻는다. 여기서 설정하는 것도 가능하고, Server설치가 끝난 후 경로 설정을 하는 것도 가능

하다.

 

-jsp를 사용한다면 반드시 JDK를 설치해야한다.

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Java support in the Web Server requires either a Java Runtime

Environment (JRE) or a Java Development Kit (JDK) of version 1.2 or greater.

 

You have either opted to use your own JDK or decided not to install  the default JRE, in which case you must provide your

own JDK. 

Please enter the absolute path to your JDK directory.

 

JDK Directory:

JDK가 설치 되어있는 경로를 묻는 것이다. (JDK는 이미 설치 되어있어야 한다.)

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

On most systems, the JDK libraries can be found in the /jre/lib

subdirectory of the JDK directory.  Unless your system has special requirments, hit enter and leave this entry blank.

 

JDK LIBPATH:

JDK의 LIBPATH

JDK디렉토리 아래 디폴트 경로에 있다면 Enter !

 

(libraries가 다른 경로에 있다면

패스를 적어주어야 한다.)

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

On most systems, the classes for the JDK libraries can be found in the /lib subdirectory of the JDK directory.  Unless your

system has special requirments, hit enter and leave this entry

blank.

 

JDK CLASSPATH:

JDK의 CLASSPATH

JDK디렉토리 아래 디폴트 경로에 있다면 Enter !

 

(CLASSPATH가 다른 경로에 있다면 패스를 적어주어야 한다.)

 

 

Sun Netscape Alliance

iPlanet Web Server Installation/Uninstallation

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

Extracting Server Core...

Extracting Java Runtime Environment...

Extracting Java Support...

Extracting Search and Indexing Support...

Extracting SNMP Support...

Extracting Upgrade Files...

 

                               

 

Server Core installed successfully.

mmJava Runtime Environment installed successfully.

mmJava Support installed successfully.

mmSearch and Indexing Support installed successfully.

mmSNMP Support installed successfully.

mmm

Press Return to continue...

이 화면이 보이면 install이 끝난것이다.

 

4.      설치가 끝나면 iPlanet Web Server가 설치된 디렉토리(server-root)로 이동합니다.

5.      /server-root/https-admserv 로 가서 Adminserver를 start 합니다.

# [Server-root/https-admserv] : ./start

6.      URL을 써서 설치한 iPlanet Web Server로 이동합니다.

http://server_name:administration_port

user name과 password를 입력합니다.

 

 


 

 

3. Uninstall 절차 (unix환경)

 

 


 

(1) UnInstall 절차

 

1.server root ( 설치된 디렉토리)로 가서 ./uninstall 을 실행합니다.

2.uninstall할 모든 components를 선택하고 Enter .

 

NOTE  uninstall program은 서버의 모든 파일을 지우는 것은 아닙니다. 예를 들어 key, certificate, 환경파일, 로그들, ACL파일들 그리고 document root등은 지워지지 않으므로 uninstall한 후 수동으로 지워주어야 합니다.

 

 

 

 

 

 

 


 

 

 

Part

2I

 

 

 

 

 

 

 

 

 

 

 

    주요 환경 설정치

 

 

 

 

 


 

웹서버 버전확인, 도큐먼트설정, 로그 설정, JDK 설정, JSP/Servlet설정, CGI설정, PHP설정, 인증서 설치, Weblogic연동방법에 대해 제시합니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

I. 버전확인

 

(1) 브라우져에서 확인하는 방법

Admin server에 접속한 뒤 Select Server에서 서버를 고른 후 Manage를 버튼을 누르면 Server On/Off 창으로 넘어갑니다. 그 곳에서 About this server 라는 hyperlink를 누르면 자세한 버전 정보를 확인할 수 있습니다.

 

(2) error 로그에서 확인하는 방법

웹 서버를 start할 경우 서버 버전과 관련된 정보를 error log에 기록하므로 logs 디렉토리의 errors 화일을 통해 확인할 수 있습니다.

 

(3) telnet command에서 확인하는 방법

- 3.x 버전 : 웹서버 설치 root 디렉토리/bin/https/ns-httpd -vi
- 4.x 버전 : 웹서버 설치 root 디렉토리/bin/https/bin/ns-httpd -v
- 6.x 버전 : 웹서버 설치 root 디렉토리/bin/https/bin/ns-httpd -v
- 6.x 버전 : 웹서버 root 디렉토리/start –version

 

2. Document 설정

 

(1) S1WS 4.1 일 경우

Server Manager화면의 Contents Mgmt 탭 – Primary Document Directory 메뉴에서 Primary Document의 경로를 변경 할 수 있습니다.

 

 (2) S1WS 6.0 일 경우

Class Manager화면의 Contents Mgmt 탭 – Primary Document Directory 메뉴에서 Primary Document의 경로를 변경 할 수 있습니다.

 

3. Directory Indexing

Server Manager화면의 Contents Mgmt 탭 – Document Preference 메뉴에서

(6.0일 경우 Class Manager화면의 Contents Mgmt 탭 - Document Preference)

 

Index Filenames :  이 부분에 처음에 보여질 index 페이지를 설정 할 수 있습니다. 이곳에 index.html을 등록 하시면 index.html 페이지가 처음 불려지게 됩니다.

index.html뒤에 , 로 구분하여 home.html을 등록해 주면 index.html을 찾지 못했을 경우 index.html다음에 등록된 home.html을 찾게 됩니다.

처음 보여질 페이지를 index.jsp 나 기타 다른 페이지로 하고자 할 경우  Index

Filenames : 이 부분에 등록 하면 됩니다.

 

Index Filenames : 부분에 등록된 파일을 찾을 수 없을 경우

아래의 Directory Indexing부분의 설정에 따라 보여지는 내용이 달라 집니다.

Fancy 나 Simple로 설정하실 경우 Index Filenames : 부분에 등록된 파일을 찾을 수 없을 경우에 Document root 디렉토리에 있는 파일 항목들을 보여주게 됩니다.

 

그러나 None으로 설정 하시면 파일들을 나열해서 보여 주지 않고, 대신 특정 웹 페이지를 보이도록 하실 수 있습니다.

None로 설정 하시고 File to use for error response when indexing is none: 부분에 보여줄 에러 페이지를 등록 합니다.( 절대 경로로 등록 합니다.) 이 부분에 error.html을 등록 하셨다면 Index Filenames : 부분에 등록된 파일을 찾을 수 없을 경우 파일들을 다 보여 주지 않고  error.html을 보여주게 됩니다.

 

 

4. Log rotate 설정

 

웹 서버 로그를 rotate시키는 방법은 Internal 데몬방식과 Cron-Based 방식 2개가 있습니다.

 

(1) internal 데몬 로그 rotate

 

S1WS 4.1일 경우 access로그만 rotate됩니다. 6.0에서는 access 와 error 모두 rotate 됩니다.  설정하는 절차는 다음과 같습니다.

 

1) Server Manager화면으로 갑니다.

2) Status 탭을 누르시고 왼쪽의 메뉴 중 Archive Log를 누르시면 아래와 같은 화면이 나옵니다. (6.0 일 경우 server manager / logs / Archive log에서 설정하며 방법은 4.1과 동일 합니다.)

3) Internal daemon log rotation 을 선택하시고 하루 중 로그를 rotate시킬 시간을 정하신 후 rotate되는 간격을 설정합니다. Rotation interval의 default값은 30분입니다.  ( 예: rotate start time 1:30 am rotate interval 1440이라 하였을 경우 하루 중 오전 1시 30분에 로그를 rotate하여 20020106.access와 같은 형태로 로그 파일을 생성하고 그 후 하루 간격으로  로그를 rotate하여 access  남깁니다.)

4) OK 버튼을 누릅니다.

5) 오른쪽 상단의 apply버튼을 누른 후 apply change합니다.

( 6.0 일 경우 Load Configuration 하여도 적용 됩니다.)

 

(2) Cron-Based 로그 rotate

 

S1WS 4.1, S1WS6.0 모두 access 와 error log 가 rotate 됩니다.

1) Cron based log rotation을 선택 하시고 rotate시킬 시간대를 선택합니다.

( 예 : 12:00 am을 선택 하시면 하루 중 12 :00 am에만 로그가 rotate됩니다.

하루 중 12:00 시와 2:00시에 rotate시키고자 한다면 12시를 선택한 후

ctrl 버튼을 누르고 2:00을 선택하시면 됩니다. )

그리고 특정 요일에는 rotate시키지 않으신 다면 특정 요일에 대한 체크를

풀어 주시면 됩니다.

 

2) OK 버튼을 누릅니다.  아래와 같은 화면으로 이동 합니다.

3) Server Manager링크를 클릭 합니다.  아래 화면으로 이동하게 됩니다.

Start 버튼을 눌러 cron 데몬을 on시킵니다.

오른쪽 상단의 apply버튼을 누른 후 apply change합니다

 

 

5. JDK 설정

Servlet은 웹서버에 내장된 jre만으로 실행이 가능합니다. 그러나 JSP를 실행시켜야 할 경우에는 jdk를 반드시 설치해야 하며, 설치된 jdk를 웹서버에 연동시켜 주어야합니다.

 

방법 :

Admin Server에서 Global Settings 탭을 선택하고 Configure JRE/JDK Paths 항목을 열어 JDK콤보 버튼을 클릭하고 JDK가 설치된 패스를 입력한 후 OK버튼을 클릭합니다.

https-admserv에서 stop/start해야 적용 됩니다.

 

예:

/usr/java1.2.2 에 JDK가 설치되었다면 JDK Path: 항목에 "/usr/java1.2.2" 를 입력하고 아래 lib path와 Class path는 공란으로 둡니다.

주의1 :

웹서버에서 JDK 패스 설정시 base directory (JDK가 설치된 처음디렉토리 ex:/usr/java1.2.2) 아래에 있는 기타 디렉토리를 입력하거나 특정 클레스 파일을 설정했을 경우 JSP가 정상적으로 동작하지 않을 수 있습니다.

잘못된 패스설정의 예

* /usr/java1.2.2/lib

* /usr/java1.2.2/bin

* /usr/java1.2.2/tools.jar

 

반드시 jdk가 설치된 디렉토리까지만 잡아 주셔야 합니다.  .

예) /usr/java1.2.2 까지만..

 

 

주의 2:

JDK 연동 정보는 https-admserv에 들어 갑니다..

만약 JDK를 잘못 연동 하였을 경우 웹 서버가 start되지 않을 수 있습니다.

따라서 JDK 연동 전에 start-jvm 파일을 백업 받아 놓으시고 만약 JDK가 연동 정보가 잘못되어 start 되지 않을 경우 백업해 놓은 start-jvm으로 rollback 시킬 수 있도록 합니다..

 

 

6. JSP/Servlet 설정

1. JSP실행 하기

1) JSP를 실행하기 위해서는 JDK를 설치 하여 웹 서버와 연동 하여야 합니다.

2) JDK가 제대로 연동 되었다면 JSP파일들은 Document Directory 어디에 두어도  상관없이 실행 됩니다.

 

2. Servlet 실행 하기

Servlet 은 웹 서버에 내장된 JRE 만으로도 실행 되므로 JDK를 설치 하지 않아도 됩니다. 단, Servlet 파일들이 존재하는 디렉토리를 Servlet 디렉토리로 등록해 주어야 합니다.

- Legacy Servlet 탭 – Configure Servlet Directory

(S1WS4.1일 경우 Servlets 탭 – Servlet 디렉토리) 에서  servlet 파일들이 존재 하는 디렉토리를 등록합니다.

 

 

7. CGI 설정 

cgi파일을 실행할때 , 이 파일이 cgi파일임을 인식하는  2가지 있습니다. 

1. programs 탭의 CGI Directory 에다 cgi-bin 디렉토리를 만들고 여기에 cgi 파일들을 두면 이 디렉토리 아래에 있는 모든 파일들을 cgi로 인식하여 실행하게 됩니다.

2.

1) preference 탭의 MIME types에 magnus-internal/cgi cgi,exe,bat 으로 설정되어 있는지 확인 합니다.

2) Programs 탭의 CGI File Type 의 Activate CGI as a file type? 을 yes로 설정합니다. 
이렇게 하면 확장자가 .cgi나 exe , bat인 파일들은 모두 cgi로 인식하겠다는 것이므로 cgi 가 어느 디렉토리에 있든지 확장자만 제대로 되어있다면 cgi로 인식하여 실행됩니다. 
그러므로 같은 디렉토리에 cgi파일과 기타 다른 파일들이 같이 있어도 됩니다.

 

 

8. PHP 설정

PHP 와 Netscape Enterprise Server 3.x / iPlanet WebServer 4.x, 6.0 연동

(Solaris 기준)

 

(1) php3.x와 연동하기 (WebServer 3.x와 4.x 동일)

 

1) 아래의 표를 참고하여 PHP와 Redirect를 모두 다운로드 합니다.

 

관련사이트

다운로드

PHP

http://www.php.net/downloads.php

php 3.0.18

redirect

http://swt-www.informatik.uni-hamburg.de/howto/php3.html

Redirect


2) tar.gz로 되어있는 php의 압축을 풉니다.

(예를 들어  /usr/local/bin/php_install 에 압축을 풉니다.) 

3) 압축을 푼 디렉토리에 가서 ./configure(자동) 또는 /.setup(수동)중 하나를 실행하여 환경 구성 합니다.

 

4) make 와 make install로 컴파일 및 설치를 합니다.

 

5) 설치가 끝나면 /usr/local/bin/php_/php-3.0.18에 php3.ini-dist라는 파일이 있는데 이것을 /usr/local/lib/ 디렉토리에 php.ini라는 파일의 이름으로 복사 후 php.ini를 수정하는데 아래와 같이 PHP 파일을 사용할 디렉토리(웹서버의 Document Root등)를 지정합니다.

     예) doc_root=/usr/local/bin/php/examples 

 

6) redirect.tar 압축을 풀고 Makefile을 열고 설치된 웹서버의 nsapi 경로를 아래와 같이 지정한 뒤 저장합니다.

INCLUDEDIR=/웹서버설치디렉토리/include            (web server 3.x)

         INCLUDEDIR=/웹서버설치디렉토리/plugins/include   (web server 4.x)

         CC_CMD=cc –DSOLARIS                                    (컴파일러가 cc)

         CC_CMD=gcc –DSOLARIS                                  (컴파일러가 gcc)

 

7) make 라고 실행하면 redirect-cgi.c 파일이 redirect_cgi.so로 컴파일 되면서 현재 위치에 생성됩니다. (이때  cc 혹은 gcc 컴파일러가 없으면 안됩니다.)

 

8) 생성된 redirect_cgi.so를 6번에서 설정된 INCLUDEDIR의 위치에 복사합니다.

 

9) 이제 웹서버의 브라우저에 들어가셔서 Programs 탭 밑에 CGI File Type 에 가셔서 Activate CGI as a file type? 스위치를 on으로 설정하고 save and apply 를 합니다.

 

10) Server preference밑에 Mine types에 가셔서 Content-Type란에 magnus-internal/php 라고 적어 주시고 File Suffix 란에 pthml,php3 라고 적어 주십시오. ( 또는 /웹서버설치디렉토리/https-<servername>/config/mime.types 파일을 열고 수정합니다.)

 

11)   /웹서버설치디렉토리/https-<servername>/config/obj.conf 파일을 열고 Init fn=load-types mime-types=mime.types의 아래줄에 다음과 같이 추가합니다. 이때 shlib는 redirect_cgi.so가 위치한 곳인 INCLUDEDIR을 지정합니다.

Init fn="load-modules" shlib="/INCLUDEDIR/redirect_cgi.so"  funcs=

"redirect_cgi"

 

12) ObjecType fn="type-by-extension" 이라는 줄 밑에 다음과 같이 edit 하십시오.

 

ObjectType fn="redirect_cgi" cgi_path="/usr/local/bin/php" type=

"magnus-Internal/php"

 

13) 웹 브라우져를 통해 Admin 서버에 들어가 웹 서버를 선택한 후 오른쪽 위에 Apply 버튼 선택 후 다시 Save&Apply하고 다시 웹 서버를 stop/start하면 php 화일이 정상적으로 수행되는지 확인하십시오.

 

(2) php4.x와 연동하기 (WebServer 3.x와 4.x 동일, 6.0은 아래 7번 주의)

 

1) 컴파일 전에 gcc를 설치하여 다음과 같이 library path를 잡아주십시오.

) c shell일 경우 .cshrc 파일 내에 아래와 같이 2줄을 설정합니다.

setenv LD_LIBRARY_PATH /gcc/설치/디렉토리/

setenv LD_FLAGS -L/gcc/설치/디렉토리/


2) php를 down받아 tar.gz로 되어있는 php의 압축을 풉니다.

 

3) 컴파일하기 위해 다음과 같은 옵션을 사용합니다.


예)  
/opt/netscape/server4 에 web server를 install 한 경우 :

  ./configure --with-mysql=/usr/local/mysql --with-nsapi=/opt
/netscape/server4 --enable-track-vars --enable-libgcc 

Mysql 사용시

4)  make;make install을 합니다.

 

5) 위의 과정을 수행하면  libphp4.so  파일이 /opt/netscape/server4/bin 에 성됩니다. (위의 경로로 install 한 경우)

6) /opt/netscape/server4/httpd-<servername>/config/mime.types 파일을 열어 add하세요   type=magnus-internal/x-httpd-php    exts=php

 

7) /opt/netscape/server4/httpd-<servername>/config/obj.conf 파일을 열어 편집합니다.   (WebServer Version이 6.0일 경우는 아래의 회색 부분 “load-types”부분만 편집한다.

(/opt/netscape/server4/httpd-<servername>/config/magnus.conf)

Init f n=”load-types” mime-types=”mime.types” (다음에 추가 )

Init fn="load-modules"
funcs="php4_init,php4_close,php4_execute,php4_auth_trans" (공백 없음)
shlib="/usr/netscape/server4/bin/libphp4.so"
Init fn=php4_init errorString="Failed to initialize PHP!"


ObjectType fn=”force-type” type=”text/plain” (다음에 추가)

Service fn="php4_execute" type="magnus-internal/x-httpd-php"


(맨 마지막 줄에 추가)

<Object name=”x-httpd-php”>

ObjectType fn="force-type" type="magnus-internal/x-httpd-php"
Service fn="php4_execute"

</Object>

 

8) 웹서버를 stop/start 후 php화일이 정상적으로 수행되는지 확인하세요.

 

 

9.인증서 설치

 

web server에 SSL을 설정하는 전체과정

 

1. 서버의 키 페어(공용, 전용키)를 생성합니다. (CSR 생성)

2. 인증 기관에 인증서 발급을 요청 합니다.

3. 인증 기관에서 발급받은 인증 서를 웹 서버에 설치합니다.

4. 웹 서버에 설치한 인증서를 Enable 하기 (SSL 설정)

 

** 설치전 알아 둘 사항 **

 

서버 인증서의 종류는 글로벌서버인증서(Global Server Certificate)와 시큐어 서버인증서(Secure Server Certificate)로 나뉘어집니다.

 

- 글로벌서버인증서는 128bit로 SSL통신을 하기 위해서는 클라이언트 브라우저가 128bit를 지원해야 하며, 지원하지 않는 브라우저는 통신이 되지 않습니다. 단 Step-UP 기술을 지원하는 Netscape 클라이언트(Netscape Navigator 4.0이상/explore 5.5이상 )나 SGC(Server Gated Cryptography) 확장을 사용하는 클라이언트 응용프로그램을 사용해야 합니다.

 

- 시큐어 서버인증서는 서버와 클라이언트 모두 128비트를 지원해야 128비트 통신이 가능하며 둘 중 하나가 128bit를 지원 않는다면 브라우저 bit수에 의존적인 통신을 합니다.

 

- 인증서는 http://www.crosscert.com 에서 발급 받으실 수 있습니다.

 

 

1.  CSR 생성 하기

우선 Browser에서 http://Servername:AdminPort로 관리 창으로 접속해서, SSL을 적용시킬 서버를 선택하고 manage버튼을 눌러 server manager화면으로 이동 합니다.

또는  SSL통신을 할 새로운 서버를 추가하여 SSL을 설정하실 수 있습니다.

(SSL통신을 하는 서버의 기본 포트는 443 포트입니다.)

  

1) 서버의 Key-Pair(비밀키)를 생성합니다.

Server manager화면에서 Security 탭을 선택 하시고 서버의 key-pair를 생성하기 위해 Create Database 메뉴를 선택합니다.

 

l       Security Tab의 Create Database link에서 Database Password 항목에 비밀번

호를 입력 합니다. 자리 수는 최소 8자리이어야 합니다. 입력은 보안을 위해 * 로

표시됩니다. Password (again) 항목에 확인을 위해 동일한 비밀번호를 다시 입력

합니다.

l       Ok를 click 합니다.

l       이제 Key-Pair(비밀키)가 생성이 되었습니다. 확인하려면 Telnet으로 접속해서,

웹 서버 설치디렉토리 이하 alias라는 디렉토리에 들어가면 https-HostName-

InstanceName-key3.db와 https-HostName-InstanceName-cert7.db와

secmod.db라는 파일이 생성된 것을 확인할 수 있습니다.

 

 

 

 개인키 백업

 

개인키(Private Key)란 인증기관에 인증서를 신청하기 위해 인증요청서(CSR)를 생성할때, 만들어지는 개인 비밀 키 입니다.

CSR에는 개인 키의 내용이 포함되어져 인증 서를 신청하게 되며, 인증기관에서는 개인 키의 내용이 포함된 인증 서를 발급해 주게 됩니다.

따라서 인증 서를 신청한 회사는 개인 키와 발급된 인증 서를 함께 설치해야만 SSL서비스를 제대로 운용할 수 있습니다.

 

개인키는 CSR을 생성할 때 만들어진 개인 키를 그대로 사용하셔야 하며, 임의로 다시 만들 수 없습니다. 따라서 CSR을 생성하고 나서 바로 개인 키를 백업해 두셔야 합니다.

서버 설치 디렉토리 아래 alias라는 디렉토리 아래 https-HostName-InstanceName- key3.db와 https-HostName-InstanceName-cert7.db 로 개인키가 생성 됩니다.

이 키를 백업해 두시면 됩니다.

 

 

2) 서버에서 CSR(현재 서버의 인증에 필요한 정보를 가지는 암호화된 문서)을 생성합니다.

l     Security Tab의 Request a Certificate link에서 New certificate를 선택합니다.

l     Submit to Certificate Authority via에서 CA Email Address를 선택한 뒤, 관리자의 E-mail을 기재 합니다.

l     Select the module to us with this certificate에서 Cryptographic Module은

internal(software)상태로 두고, Key Pair File Password에 Key-Pair(비밀키)와 동

일한 비밀번호를 기재합니다.

l     Requestor Name에는 관리자의 이름을 영문으로 기재합니다.

l     Telephone number에는 관리자의 연락처를 기재합니다.

l     Common name에는 Domain name을 기재를 합니다. 이 부분은 특히 중요합

니다. SSL을 설정할 서버의 domain name과 여기에 기재된 domain name이 일치

하지 않으면 인증서는 설치되나 서버가 제대로 서비스 되지 않습니다.

l     Organization에는 회사명을 영문으로 기재합니다.

l     Organization Unit에는 부서명을 영문으로 기재합니다.

l     Locality에는 자세한 주소를 영문으로 기재를 합니다.

l     State or Province는 우리나라는 해당 없으므로 공란으로 둡니다.

l     Country에는 국가 코드(예를 들어 대한민국은 KR)를 기재합니다.

l      ok를 click 합니다.

l     위의 절차대로 OK를 누르면 CSR이 생성됩니다.

 

 

)

-----BEGIN NEW CERTIFICATE REQUEST----
MIIBCTCBtAIBADBPMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHRmxvcmlkYTEYMBYGA1UEChMPRXllcyBvbiBUaGUgV2ViMRQwEgYDVQQDFAt3d3cuZXR3Lm5ldDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCeojtjnHqg0GTxp+XZ56RaSe1iZWpumXjU6Sx7v1FdXzsY1oLOQa090Jtnu1WsQRHh0yDS+45oncjKm1zCG/IZAgMBAAGgADANBgkqhkiG9w0BAQQFAANBAFBj9g+NiUh8YWPrFGntgf4miUd/wqUshptjJy4PjdsD3ugy
5svvuh3G//PpGh2aYXIjHpJXTUBQyzxSEIINYtc=
-----END NEW CERTIFICATE REQUEST-----

 

위의 CSR을 복사하여 thawte나 verisign 홈페이지에서 등록신청 할 때 넣어 줍니

.

 

3) 인증 기관(thawte)에 접속해서 인증 서를 발급 신청

인증기관(http://www.crosscert.com )에 접속해서 테스트 ID 혹은 실제 ID를 발급 신청할 경우 CSR을 요구합니다. 이때  앞에서 생성했던 CSR을 붙이고 다음에 관리자의 정보나 결제방식과 법인 등록번호 등을 기재해서 신청을 마치면, 신청한 E-mail로 등록 확인서와 PIN# 번호가 오며 이 번호로 등록 신청여부를 알 수 있습니다.

 

 

2.  인증기관에서 인증 서 발급 받기

www.crosscert.com  접속하여 발급 받고자 하는 인증서를 선택합니다.

1) 인증서 신청 ( 서버 인증서 신청 단계 미리 보기 입니다. )

2) 신청하기 전에 아래의 내용을 검토하시고 다음 단계로 넘어 갑니다.

3) 인증서를 신청하기 전 도메인이 등록 되어 있는지 확인하십시오.

4) 인증서를 설치하고자 하는 서버의 CSR이 생성되어 있어야 인증서 신청이 가능 합니다.   CSR을 이미 생성 하였는지 확인하는 단계입니다.

5) 서버에서 생성한 CSR을 아래의 필드에 넣습니다.

----BEGIN 부터 END ---까지 넣어야 하며, 뒤에 공백 혹은 빈 라인이 들어가지 않아야 합니다.

6) CSR에서 추출한 정보가 맞는 확인하시고, 아래의 공백에 인증서를 신청하는 곳의 정확한 정보를 입력합니다.

7) 등록이 완료되었으니 내용을 확인하시고, 발급을 원한다면 승인버튼을 누릅니다.

8) 인증서 신청이 완료 되었습니다. 인증서는 신청 후 인증서가 발급되기까지 아래의 확인 심사 작업이 진행 되므로 약 2~3일 걸릴 수 있습니다.

 

3. 발급 받은 인증 서를 웹 서버 설치 하기

 

l     Security Tab의 Install Certificate link에서 Certificate For 항목에서 This Server를 선택합니다.

l     Key Pair File Password에서 key-pair 생성시 입력했던 비밀번호를 입력합니다.

l     Certificate Name에는 This Server를 선택했기 때문에 입력하지 않아도 됩니다.

l     Message text (with headers)라는 section에 e-mail로 받은 Digital Server ID를 넣어 줍니다.

CSR과 마찬가지로 Header 부분의  -----BEGIN CERTIFICATE----- 부분과 마지막의 -----END CERTIFICATE----- 까지 넣어 주셔야 합니다.

l OK를 누르면 확인을 위해 Certificate Information이 나오고 Add Server Certificate 버튼을 누르면 등록이 됩니다.

 

 

4.  Secure Socket Layer(SSL) 적용과 사용

 

4-1. SSL 적용

1) SSL 적용

SSL을 설정 할  서버의 server manager화면에서 preference 메뉴에서 Edit Listen Socket을 선택합니다.SSL을 설정 할 포트에 대해 security를 on으로 설정합니다.  (SSL의 기본 포트는 443 포트입니다.)

 

443 포트에 대해 security 가 on되어 있다면 443포트 Listen socket을 사용하는 virtual Server들은 SSL 통신을 하게 됩니다.

 

만약 글로벌 인증 서를 설치하였을 경우 40bit혹은 56 bit의 브라우저에서도

SSL통신이 가능하도록 설정하여야 합니다.

위의 그림에서처럼 Listen Socket의 SSL을 on 하면 Attributes링크가 생깁니다. Attributes을 누르면 아래와 같은 화면이 나오고  아래 화면에서

 SSL3/TLS를 눌러 40,56 bit에 대해 활성화 시켜 줍니다.

                                                                                                                       

2) SSL 사용

 

l SSL이 적용되면 서버를 start 할 때 마다 key-pair password를 입력해야 합니다.

- 서버 시작 시 암호를 매번 암호를 적어야 하는 불편을 해결하기 위해서는 start script 에 ./$PRODUCT_BIN –d $PRODUCT_SUBDIR/config $@ 이라는 부분의 바로 뒤에 </server-설치root/alias/pass 라고 적어 주시면 전체라인이 ./$PRODUCT_BIN –d $PRODUCT_SUBDIR/config  $@ <server-설치root/alias/pass 이 됩니다.

그리고 pass라는 파일을 만들어 key-pair password를 적어주면 됩니다.

 

- 혹은 start파일을 열어 ./$PRODUCT_BIN –d $PRODUCT_SUBDIR/config $@ 를 다음과 같이 수정 합니다.

echo  “패스워드”|./$PRODUCT_BIN –d $PRODUCT_SUBDIR/config $@

 

l  SSL 이 적용된 서버는 URL 상에서 http대신 https를 사용하여 주면 됩니다.

https://host.domain:port# 

https의 default port number인 443 을 사용 할 경우 URL에 포트를 생략하여 주셔도 됩니다.

 

 

4-2.  한 개의 도메인으로 여러 개의 웹서버 사용

 

Verisign에는 같은 도메인 이름으로 여러 개의 웹 서버를 동시에 사용하려면 웹 서버 마다 각각의 인증서를 받을 것을 추천하고 있지만 host.domanname 이름이 같으면 하나의 인증서를  발급 하여 여러 개의 웹 서버에게 설치하여 동시에 사용할 수 있습니다.

 Key-pair 설정시 server_root/alias/ 디렉토리에 https-<webservername>-hostname-key3.db라는 파일이 생성되고 인증서 설치시 server_root/alias/https-<webservername>-hostname-cert7.db라는 파일이 생성됩니다.  이 파일을 복사하여  https-<사용할 서버이름>-hostname-key3.db와 https-<사용할 서버이름>-hostname-cert7.db로 만들면 됩니다.

 

 

4-3.  인증서 삭제

 

브라우저의 웹 서버 관리자 창에서 인증서를 삭제하고자 하는 웹 서버 인스턴스를 선택하여 Security| Manage Certificate을 클릭합니다.

Server Name에 Server-Cert와 type에 Own이라고 되어 있는 곳에 클릭하여 Delete Certificate 버튼을 클릭합니다.

 

 

 

10. WebLogic 연동

 

1) iPlanet API 파일 복사하기

Wlserver6.0\bin 디렉터리 안의  libproxy.so(sun 기준임, hp일 경우

libproxy.sl, nt일 경우 proxy36.dll) 을 IPLANET의 PLUGINS 디렉터리에 복사

합니다.

 

2) magnus.conf 에  다음을 추가 합니다.

Init fn=”load-moules” funcs=”wl-proxy, wl-init” Shlib=/netscape

/plugins /SHARED_LIBRARY

Init fn=”wl-init”

 

)

Init fn=”load-moules” funcs=”wl-proxy, wl-init”Shlib=/netscape/plugins

/libproxy.so

Init fn=”wl-init”

 

3) obj.conf 에 다음을 추가 합니다.

<Object name="weblogic" ppath="*/weblogic/*">

Service fn=wl-proxy WebLogicHost=203.231.15.91 WebLogicPort=7001

PathTrim="/weblogic"

</Object>

<Object name="si" ppath="*/servletimages/*">

Service fn=wl-proxy WebLogicHost=203.231.15.91 WebLogicPort=7001

</Object>

 

<Object name=default>

NameTrans fn="NSServletNameTrans" name="servlet"

NameTrans fn="pfx2dir" from="/servlet" dir="/home/

webserver/iws60sp2/docs/servlet" name="ServletByExt"

NameTrans fn=pfx2dir from=/mc-icons dir="/home/webserver/iws60sp2/ns-icons" name="es-internal"

NameTrans fn="pfx2dir" from="/manual" dir="/home/webserver/

iws60sp2/manual/https" name="es-internal"

NameTrans fn=document-root root="$docroot"

Service method=(GET|HEAD|POST|PUT) type=text/jsp fn=wl-proxy <- 연결

WebLogicHost=203.231.15.91 WebLogicPort=7001

PathCheck fn=unix-uri-clean

PathCheck fn="check-acl" acl="default"

PathCheck fn=find-pathinfo

PathCheck fn=find-index index-names="index.html,home.html"

ObjectType fn=type-by-extension

ObjectType fn=force-type type=text/plain

Service type="magnus-internal/jsp" fn="NSServletService"

Service method=(GET|HEAD) type=magnus-internal/imagemap fn=imagemap

Service method=(GET|HEAD) type=magnus-internal/directory fn=index-

common

Service method=(GET|HEAD|POST) type=*~magnus-internal/* fn=send-file

AddLog fn=flex-log name="access"

</Object>

 

<Object name=cgi>

ObjectType fn=force-type type=magnus-internal/cgi

Service fn=send-cgi user="$user" group="$group" chroot="$chroot" dir="$dir" nice="$nice"

</Object>

 

<Object name="servlet">

ObjectType fn=force-type type=text/html

Service fn="NSServletService"

</Object>

 

<Object name="jsp092">

ObjectType fn="type-by-extension"

ObjectType fn="change-type" type="magnus-internal/jsp092" if-type="

magnus-internal/jsp"

Service fn="NSServletService" type="magnus-internal/jsp092"

</Object>

 

<Object name="ServletByExt">

ObjectType fn=force-type type=magnus-internal/servlet

Service type="magnus-internal/servlet" fn="NSServletService"

</Object>

 

<Object name="es-internal">

PathCheck fn="check-acl" acl="es-internal"

</Object>

**** tunnel 설정 하지 않을 경우에는 이 부분을 생략 합니다. ****

<Object name="tunnel" ppath="*/HTTPClnt*">

Service fn=wl-proxy WebLogicHost=203.231.15.91 WebLogicPort=7001

</Object>

 

4) MIME type 수정 하기

IPLANET 디렉터리에서 사용하고자 하는 서버 디렉터리에 있는 config디렉터리에 있는 mime.types파일을 수정합니다.

/maguns-internal/jsp   exts=jsp를   text/jsp    exts=jsp로 수정한다.

magnus.conf, obj.conf, mime.types 를 수정 한 후  서버를 stop/start 합니다. iPlanet 의 jsp/servlet을 disable 시킵니다.  관리 브라우져를 열고 Server

Manager화면의 java 탭을 선택 합니다. Enable Java Globally 와 Enable Java for class defaultclass 를 disable 합니다.

 

 

11. Password 변경하기

command line에서 web server 설치 root에 있는 https-adminserv/config 디렉토리로 이동하신 다음, vi 편집기로 admpw를 여시면 아래와 같은 형태의 내용을 볼 수 있습니다.

 

admin:{SHA}0DPiKuNIrrVmD8IUCuw1hQxNqZc=

내용 중에 "admin:"뒤에 있는 암호화된 문자들을 지우고 server를 restart 시킨 다음 admin으로 접속할 때 password를 지정하지 않고 접속하면 됩니다.
접속 후 초기화면 상단에 있는 Preferences 탭을 누르신 다음 왼쪽 3번째 메뉴의 Superuser Access Control에 들어가시면 그 곳에서 admin password를 입력하여 Administrator Server의 password를 재설정 할 수 있습니다.


 

 

 

Part

3I

 

 

 

 

 

 

 

 

 

 

 

         Tunning

 

 

 

 

 


 

웹서버의 성능향상을 위한  튜닝 방법에 대해 제시합니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

1. 웹서버 튜닝

 

웹 서버의 최적화된 성능을 위해 기본적으로 확인, setting 해야 하는 항목들입니다.

 

1) OS 패치

OS 패치 제대로 되어 있는지 반드시 확인 합니다.

 

2) OS 커널 파라메터

os의 커널 파라메터 튜닝 – os별 커널 파라메터는 http://docs.iplanet.com에서 확인 하실 수 있습니다. OS엔지니어에게 문의하셔서 적정값으로 셋팅하시기를 바랍니다.

성능 벤치 마킹을 위한 솔라리스 튜닝 

Parameter

Default Value

Tuning Value

File

rlim_fd_max

1024

8192

/etc/system

rlim_fd_cur

64

8192

sq_max_size

2

0

tcp_time_wait_interval

240000

30000

/etc/rc2.d/S69inet

tcp_conn_request_max_q

128

1024

tcp_conn_request_max_q0

1024

4096

tcp_ip_abort_interval

480000

60000

tcp_keepalive_interval

7200000

900000

tcp_rexmit_interval_initial

3000

3000

tcp_rexmit_interval_max

240000

10000

tcp_rexmit_interval_min

200

3000

tcp_smallest_anon_port

32768

1024

tcp_slow_start_initial

1

2

tcp_xmit_hiwat

8129

32768

tcp_recv_hiwat

8129

32768

적용 명령어 :

#set rlim_fd_max=8192 : /etc/system

#ndd -set /dev/tcp tcp_close_wait_interval 60000 : /etc/rc2.d/S69inet

성능 벤치 마킹을 위한 HP-UX 튜닝 

Parameter

Default Value

Tuning Value

File

maxfiles

2048

4096

/stand/system

maxfiles_lim

2048

4096

tcp_time_wait_interval

60000

60000

/etc/rc.confing.d/nddconf

tcp_conn_req_max

20

1024

tcp_ip_abort_interval

600000

60000

tcp_keepalive_interval

72000000

900000

tcp_rexmit_interval_initial

1500

1500

tcp_rexmit_interval_max

60000

60000

tcp_rexmit_interval_min

500

500

tcp_xmit_hiwater_def

32768

32768

tcp_recv_hiwater_def

32768

32768

 

*nkthread

2048

8192

/stand/system

max_thread_proc

1024

2048

*maxuser와 변경에 따라 반영됨

start 스크립터

#!/bin/sh

ulimit –n 1024

 

성능 벤치 마킹을 위한 AIX 튜닝 

Parameter

Default Value

Tuning Value

File

rfc1323

0

0

/etc/rc.net

sb_max

1048576

1048576

tcp_sendspace

16384

65536

tcp_recvspace

16384

65536

udp_sendspace

9216

65536

udp_recvspace

41920

327680

Ipqmaxlen

100

512

관련 명령어 :

#/usr/sbin/no –a : 디스플레이

#/usr/sbin/no -o  rfc1323=0 : 수정

 

3) File 디스크립터

시스템의 filedescriptor수가 1024 이상이 되는지 확인 하십시오.

ulimit –a 하시어 확인 하실 수 있고(혹은 장비의 (ndd /dev/tcp) tcp_conn_

req_max 값을 확인)  , 1024이하일 경우

- /https-서비스 서버/ 디렉토리의 start 파일내에

ulimit -n 1024로 설정합니다

- /etc/system 파일에서 설정할 수 있습니다. 이 경우 os를 reboot 해야 합

니다.

 

4) 웹 서버 튜닝 항목

https-인스턴스명/config/magnus.conf  내의 항목들 입니다.

n        Rqthrottle

이 값은 S1WS6.0경우 default 128 , iws4.x 512로 처리 가능한 동시 request 수 입니다. 사용자가 많은 사이트 일 경우 이 값을 늘려 동시 처리 가능한 request수를 늘려 주도록 합니다.

 

n        MaxProcs

S1WS는 one process, multi Thread 방식 입니다.  그러나 MaxProcs 로 여러 개의 프로세스를 동시에 수행하도록 구성할 수 있습니다. 이렇게 함으로써 웹 서버의 성능을 증가 시킬 수 있습니다. MaxProcs 2 라고 설정 하면 one Process 가 아니라 2개의 Process로 실행됩니다. 그러나 iPlanet 의 모든 확장프로그램들은 Single Process mode로 개발되어 Multiple Process mode를 지원하지 못합니다. 예로 Search Plug-in은 Multiple Process mode에서는 사용할 수 없고, Java application 을 수행 할 경우에는 Multiple Process mode를 사용 할 수 없습니다.

MaxProcs  X  : X는 process 개수를 뜻하며, 설정 할 수 있는 범위는 최대 cpu *2 입니다.

 

n        KeepAliveTimeout

HTTP 1.0의 기본동작 방법은 세션 연결 후 자료전송이 끝나는 대로 세션을 끊도록 구성되어 있습니다.  이는 사용자가 여러 개의 정보를 전송 시에 재접속을 위한 오버헤드가 과도하게 발생하는 문제점이 있어 이를 개선하고자 KeepAlive라는 “접속유지”방법을 사용합니다. 이 방법은 세션 연결 후 파일전송이 끝나면 Timeout시간동안 세션을 유지함으로써 재 전송 시 접속을 위한 오버헤드를 감소시켜줍니다.(HTTP1.0은 옵션/HTTP1.1에서는 기본으로 동작합니다.) 이 항목은 해당 인스턴스의 Performance Tuning 메뉴의 Persistent Connection항목을 수정할 수 있으며, magnus.conf파일의 KeepAliveThreads 항목을 수정할 수도 있습니다.

KeepAliveTimeout은 Keep-Alive로 세션 연결 후 파일전송이 완료되고 얼마동안 세션을 유지 할 것인지를 나타내는 시간 값을 보여줍니다. 이 시간이 초과되면 세션연결은 해지 됩니다. 이 값은 default로 30초 입니다. 사용자가 많을 경우 이 값을 적게 잡아 주어 새로운 connection이 빨리 맺어 지도록 해 주어야 합니다. 그러나 이 값을 0으로 설정하면 Connection Less 상태가 되어 재 전송 시 접속 을 위한 오버헤드가 증가 하게 됩니다.(사용자가 많을 경우 이 값을 10초 정도로 설정 합니다.)

 

n        웹 서버에서 java application을 서비스 할 경우

https-인스턴스명/config/jvm12.conf 의 jvm.maxHeapSize값을 256M로 늘려 줍니다. ( 파일 내 단위는 byte 입니다.)

 


 

 

 

 

 

Part

4

 

 

 

 

 

 

 

 

 

 

 

         Q & A

 

 

 

 

 


 

웹서버 운영시 자주 발생되는 항목에 대한 FAQ를 제시합니다.

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

[Q-1] 웹 서버가 start되지 않을 경우

[Answer]

 1) logs 디렉토리의 user/group이 install시 입력한 user/group과 같은지 확인

하고, 접근 권한을 확인합니다.

 chown –R myuser:mygroup ./logs

 chmod 777 ./logs

2)  logs 디렉토리 아래 pid란 파일이 있는지 확인합니다.

만약 있다면 삭제한 후 restart 합니다.

Server가 start 되면 logs 디렉토리 아래 pid란 파일이 생성 됩니다.

Server를 stop 되면 logs 디렉토리 아래 pid란 파일은 지워 지는데,이전에 server가  비정상적으로 종료 되면 pid가 지워지지 않고 남아 있을 수 있으며, 이때 start를 시키려고 하면 pid가 이미 존재하기 때문에 start가 되지 않습니다.

 

    3)  아무런 메시지가 뜨지 않고 다음 프롬프트로 넘어갈 때

root로 서버를 start시키지 않았을 경우 (1024 포트 이하는 root 권한으로만 관리가 가능하므로)  이러한 상황이 될 수 있으므로 접속 권한을 체크해 보시기 바랍니다.

 

    4) 서버가 start 되지 않으면서 stop 하면 not running으로 나올 때

       ps –ef |grep server-root/https-myserver 로 daemon을 확인합니다.

  ./uxwdog 와 ns-httpd 데몬은 항상 짝으로 떠있어야 합니다.

  (admin server 에 한해서 웹서버 3.6에서는 ns-admin –d 혼자 떠있는게 정상임) 그러므로, 이 때에는 ./uxwdog 데몬을 kill –9로 내리고 서버를 다시 start 하도록 합니다.

 

 

[Q-2] [https-hostname]: pclose() failed. (2: unknown early startup error)

[https-hostname]: failure: watchdog could not connect

to notification port (Connection refused)

[Answer]

error를 수정하기위해서는 Web_server_root/https-[Server Id]/logs로 접근하여 "wdnotify" file을 삭제합니다.

이러한 파일이 생성 되는 이유는 웹서버를 start할때 /logs/wdnotify와 uxwdog 프로세스가 기동 되면서 생성되게 됩니다.

uxwdog이 안정적으로 기동되면 wdnotify가 없어지면서 /logs/pid에 uxwdog 프로세서 번호를 남기고 파일이 삭제되게 되는데, 기동이 정상적으로 되지 않을 경우 wdnotify는 /logs/wdnotify파일을 생성하게 된다. 이럴 경우 웹 서버는

이미 웹 서버가 실행중인 것으로 인식하고 기동하지 않게 됩니다.

 

* "uxwdog" daemon은 httpd 프로세서들이 잘 실행되는지 감시하고 시스템 장애등

의 문제로 인하여 다운된다면 httpd 프로세스를 다시 기동 시켜주는 역할을 합니

.

 

 

[Q-3] pclose() failed. (2:unknown early startup error)

Config of server nonce cache failed(-8185)

[Answer]

/tmp 디렉토리에 사용이 가능한 공간을 확보해야 합니다.

 

 

[Q-4] could not log PID to PidLog /ServerRoot/logs/pid (Permission denied)

혹은 daemon: “can’t log pid to <server-root>/https-myserver/logs/pid

[Answer]

접근 권한 문제로 logs 디렉토리에 쓸 수 없을 때 발생 합니다.

    Chmod 777 logs

 

 

[Q-5] info:successful server startup

    failure:Terminating Service:Failure: Could not open statistics file ( Error Number is unknown)

    pclose() failed. (2 unknown early startup error)

    warning: statistics disabled (IIIegal access)

    Netscape-Enterprise/3.6.3

    Seminit failed (Illegal access)

    Startup failure: could not bind to port 80 (permission denied)

    Server exit: status 255

[Answer]

Server가 start 할 때 daemonstat.* 이라는 임시 파일을 /tmp에 생성하는데, 이때 서버가 이 파일을 만들거나, 파일 위에 쓰거나, 조작할 수 없을 때 발생할 수 있는 error입니다.  /tmp 디렉토리가 full나지 않았는지, /tmp 디렉토리의 permission이 777이 아닌지 확인 하십시오.  또는, 서버가 실행 중이지 않을 때에도  /tmp 에 daemonstat.* 파일이 있는 경우는 그 파일을 지워주고 서버를 start 시키십시오.

 

 

[Q-6] info: successful server startup

    info: Netscape-enterprise/3.6

    failure : flex-rotate: error opening must cycle logfile server-root/https-myserver/logs/access before changing format ( No such file or directory)

[Answer]

이 현상은 access log의 format line이 손상되었을 때 발생합니다.  해결 방법은 다음과 같습니다.  access 파일을 지워주면 서버가 다시 start 할 때 access 파일을 생성하면서 정상적으로 start 됩니다.

 

 

[Q-7] ld.so.1: ns-httpd: fatal: relocation error: file

  /opt/iws6/bin/https/lib/libns-httpd40.so: symbol __0dK__RT_CLASSG__vtbl:

    referenced symbol not found

[Answer]

S1WS 6.0은 설치 전 jre패치를 반드시 해야 합니다.  jre패치가 제대로 되어있지 않다면 웹서버는 설치가 되나 start되지 않는 상황이 발생합니다.

 

 

[Q-8] "Too many open files" 라는 에러가 발생할 경우.. 

[Answer]

ulimit -a(csh일 경우)하여 file descriptor를 확인하고 64라면 file descriptor의 수를 늘려 줍니다.

- /etc/system 파일을 열고 rlim_fd_cur=1024 을 입력 한 후 reboot 합니다.

- 웹 서버의 start script을 열고 #!/bin.sh바로 아래 줄에 ulimit -n 1024 을 입력합니다.

 

 

[Q-9] "failure error accepting connection -5993 specified network name is no longer available" 

[Answer]

Network name is no longer available” 는 socket이 닫혔다는 NT 메시지로 이것은 unix에서 "connection reset by peer”메시지와 같습니다.

메시지는 페이지와 파일들을 다운로딩 하는 중에 STOP버튼을 눌렀을 때 혹은

클라이언트 쪽에서 connection을 drop시켰을 때 일어나는 것으로( i.e:

브라우저를  닫을 때) 이 메시지는 심각한 것이 아닙니다.

 

 

[Q-10] perl로 된 CGI scriptor를 실행시 다음과 같은 에러가 발생되는 경우

cgi-parse-output reports: the CGI program /path/foo.cgi did not produce

a valid header (program terminated without a valid CGI header; check for core dump or other abnormal termination)

 [Answer]

위 에러의 원인은 cgi script 의 결과가 만들어질 때 header line이 발생되기 전에 system() call에 의해 발생된 어떤 output 이 먼저 만들어져서 생기는 문제로 위 문제의 해결 방법은 다음과 같습니다.

script 의 가장 윗 부분에 다음과 같이 적어 주십시오.

$l=1;

이렇게 해주면 어떠한 output 이든지 즉시 메모리에서 flush 되므로 문제가 해결될 것입니다.

 

 

[Q-11] warning (11928): SimpleSessionManager: cannot create a new session 
as the limit on maximum number of sessions has already been reached:(1000)

failure (11928): Internal error: exception

thrown from the servlet service function (uri=/main.jsp):

java.lang.NullPointerException, Stack: java.lang.NullPointerException

   at _0002fmain_0002ejspmain_jsp_0._jspService(Compiled Code)

   at org.apache.jasper.runtime.HttpJspBase.service(Compiled Code)

at javax.servlet.http.HttpServlet.service(Compiled Code)

atom.netscape.server.http.servlet.NSServletRunner.Service(Compiled Code)

 [Answer]

 세션 갯수가 시스템 디폴트 값을 초과한 경우 발생하는 문제로 single proce mode일경우 config 디렉토리 내의servlets.properties 또는 contexts.properties  화일을 아래와 같이 수정하여 session갯수를 늘려주고 time outreapinterval 줄여 적당한 값을 setting하면 됩니다.

default 값은 maxSessions=1000,timeOut=1800,reapinterval=600입니다.

 

servlets.properties file

servlets.sessionmgr=com.netscape.server.http.session.SimpleSessionManager

servlets.sessionmgr.initArgs=maxSessions=2500,timeOut=1000,reapinterval=300

 

contexts.properties file

context.global.sessionmgr=com.netscape.server.http.session.SimpleSessionManager

context.global.sessionmgr.initArgs=maxSessions=2500,timeOut=1000,reapinterval=300

 

그리고 OutofMemory와 관련해서는 config 디렉토리내의 jvm12.conf 화일에서 jvm.maxHeapSize 값을 128M 또는 256M 이상으로 setting 하면 됩니다.

 

 

 

[Q-11] resource Temporarily Unavailable

 [Answer]

process  socket  IO call  일으킬때 처리가 늦어지면 process  block 되면서 그런 메시지를 뿌립니다. 메세지는 warning 이지 error 아니고,OS  kernal parameter tuning 하여 해결할  있습니다.

 

[Q-12] 웹서버 Start시 다음 메시지가 나온다.

failure ( 2726): StartThread failed to create thread

failure ( 2726): NSPR error code = -5974

failure ( 2726): NSPR error code = 11

failure ( 2726): error msg = Insufficient resources

 [Answer]

위 문제는 시스템 resource 부족 문제로서 system kernel 부분에 몇 가지를 수정하시면 이 문제는 없어 집니다.  그전에 먼저 os를 tuning 해 주시고, 마지막으로 아래의 system kernel 값을 변경하시면 됩니다.

 

max_thread_proc   -->   2048

nkthread          -->   8192 이상

 (한번에 시스템에서 허용하는 커널 스레드의 최대값)

 

 

[Q-13]  hp-ux에서 - Error mmap()ing....

failure (18170): file-cache-create: Error mmap()ing

    file /local/suitespot/docs-advantage/index.html (Not enough space)

 [Answer]

위 문제와 관련 해결을 위해서는 웹 서버에 다음과 같은 셋팅을 해주어야 합니다.

/web-server-root/https-[ID]/config/magnus.conf 파일내에 MapFlags 2 라는

line을 추가해야 합니다.

 

 

[Q-14] exe 파일이 제대로 다운로드 되지 않을 때

 [Answer]

MIME TYPE에서 application/octet-stream --> exe로 설정하십시오.

 

 

[Q-15]  System.out.println이 로그에 남지 않는 문제

 [Answer]

다음과 같은 방법으로 수행하면 foregroud로 수행하여 servlet output을

redirect 할 수 있습니다 .

방법1:

1) 다음과 같이 terminal에서 수행합니다.
./stop
./start –shell

2) 위를 수행하면 command의 위치가 /server_root/bin/https/bin 디렉토리로 이동합니다. 여기에서 다음 command를 입력합니다.
./ns-httpd -d /server_root/https-server_id/config 이렇게 하면 foregroud 상태가 되고 system.out과 System.err를 콘솔에 찍게 됩니다.

방법2:
 
Servlet / JSP 코드에 다음을 사용하여 error log에 찍을 수 있습니다.

  *************************************************
  ServletContext cont = this.getServletContext();
  cont.log("Write this String");
  *************************************************

  위와 같이 삽입하면 Write this String이 error log에 찍히게 됩니다.


< NT에서 System.out.println을 찍는 방법 >

 S1WS 4.1일 경우 /server-root/https-서버명/config/obj.conf, S1WS6.0일 경우 /server-root/https-서버명/config/magnus.conf 파일에 아래의  라인을 입력합니다.

1) Init fn="nt-console-init" stderr=" stderr" stdout="stdout" EarlyInit="yes" stderr과 stdout에는 System.err.println과 System.out.print가 찍혀질 파일을 입력합니다.

예를 들어 System.err.println결과와 System.out.println을

C:/iPlanet/Servers/https-sky/logs/errors 파일에 찍도록 하기 위해서는
Init fn="nt-console-init" stderr="C:/iPlanet/Servers/https-sky/logs/errors" 
stdout="C:/iPlanet/Servers/https-jhchoi/logs/errors" EarlyInit="yes"
와 같이 설정 하면 됩니다.

2) Init fn="nt-console-init" stderr=console stdout = console

EarlyInit="yes" 

웹 서버를 재 실행합니다. 

 

Posted by redkite
, |

0001. JVM Lock

Enterprise Java는 거대한 동기화 머신이다.

Thread Dump
Java에서 Thread 동기화 문제를 분석하는 가장 기본적인 툴은 Thread Dump를 분석하는 것이다. Java Application의 Thread Dump는 아래 방법으로 얻을 수 있다.

Thread Dump는 기본적으로 현재 사용 중인 Thread의 상태와 Stack Trace를 출력해준다. 더불어 JVM의 종류에 따라 더욱 풍부한 정보를 같이 제공한다.

Simple Application
아래에 Thread 동기화 문제를 일으키는 간단한 두 개의 예제가 있다.

Case1: Synchronized에 의한 동기화
public class dump_test {
static Object lock = new Object();
public static void main(String[] args) {
new Thread2().start();
try { Thread.sleep(10); } catch(Exception ex) {}
new Thread1().start();
new Thread1().start();
new Thread1().start();
}
}

class Thread1 extends Thread {
int idx = 1;
public void run() {
while(true) {
synchronized(dump_test.lock) { // <-- Thread1은 synchronized 블록으로 인해 Thread2의 작업이 끝나기를 기다린다.
System.out.println(idx++ + " loopn");
}
}
}
}


class Thread2 extends Thread {
public void run() {
while(true) {
synchronized(dump_test.lock) { // <-- Thread2는 synchronized 블록을 이용해 긴(Long) 작업을 수행한다.
for(int idx=0; idx
}
}
}
}

Case2: wait/notify에 의한 동기화
public class dump_test2 {
static Object lock = new Object();
public static void main(String[] args) {
new Thread2().start();
try { Thread.sleep(10); } catch(Exception ex) {}
new Thread1().start();
new Thread1().start();
new Thread1().start();
}
}


class Thread1 extends Thread {
int idx = 1;
public void run() {
while(true) {
synchronized(dump_test2.lock) {
System.out.println(idx++ + " loopn");
try { dump_test2.lock.wait(); } catch(Exception ex) {} // <-- wait 메소드를 이용해 notify가 이루어지기를 기다린다.
}
}
}
}


class Thread2 extends Thread {
public void run() {
while(true) {
for(int idx=0; idx<90000000; idx++) {}
synchronized(dump_test2.lock) {
dump_test2.lock.notify();
// <-- notify 메소드를 이용해 WAITING 상태의 Thread를 깨운다.
}
}
}
}

Case1(Synchronized)에서는 Thread1이 BLOCKED 상태에 있게 되며, Case2(Wait/Notify)에서는 Thread1이 WATING 상태에 있게 된다. Java에서 명시적으로 Thread를 동기화시키는 방법은 이 두개의 Case 뿐이다. Thread Pool 동기화에의 의한 Thread 대기, JDBC Connection Pool 동기화에 의한 Thread 대기, EJB Cache/Pool 동기화에 의한 Thread 대기 등 모든 Thread 대기가 이 두 개의 Case로 다 해석 가능하다. 따라서 이 두 Case의 원리만 정확하게 파악하면 어떤 복잡한 Case라도 어렵지 않게 해석이 가능하다.

위의 두 가지 경우가 세 개의 주요 JVM인 Sun HotSpot JVM, IBM JVM, JRockit JVM에서 각각 어떻게 관찰되는지 Thread Dump를 통해 관찰해보자.

Sun HotSpot JVM

Case1: Synchronized에 의한 동기화

아래 Thread Dump는 Sun HotSpot VM에서 Synchronized에 의한 Thread 블로킹이 발생하는 도중의 Thread dump 결과다.
-----------------------------------------------------------------------------------------
Full thread dump Java HotSpot(TM) 64-Bit Server VM (1.5.0_04-b05 mixed mode):

"DestroyJavaVM" prio=1 tid=0x0000000040115580 nid=0x1e18 waiting on condition [0x0000000000000000..0x0000007fbfffd380]

"Thread-3" prio=1 tid=0x0000002afedbd330 nid=0x1e27 waiting for monitor entry [0x00000000410c9000..0x00000000410c9bb0]
at Thread1.run(dump_test.java:22)
- waiting to lock <0x0000002af44195c8> (a java.lang.Object)

"Thread-2" prio=1 tid=0x0000002afeda6900 nid=0x1e26 waiting for monitor entry [0x0000000040fc8000..0x0000000040fc8c30]
at Thread1.run(dump_test.java:22)
- waiting to lock <0x0000002af44195c8> (a java.lang.Object)

"Thread-1" prio=1 tid=0x0000002afeda5fe0 nid=0x1e25 waiting for monitor entry [0x0000000040ec7000..0x0000000040ec7cb0]
at Thread1.run(dump_test.java:22)
- waiting to lock <0x0000002af44195c8> (a java.lang.Object)

"Thread-0" prio=1 tid=0x0000002afeda3520 nid=0x1e24 runnable [0x0000000040dc6000..0x0000000040dc6d30]
at Thread2.run(dump_test.java:38)
- waiting to lock <0x0000002af44195c8> (a java.lang.Object)
...
----------------------------------------------------------------------------------------

Thread-1, Thread-2, Thread-3이 "waiting for monitor entry" 상태, 즉 Monitor에 들어가기 위해 기다리고 있는 상태로 대기 중이다. 즉, "synchronized" 문에 의해 블로킹되어 있음을 의미한다. 이 경우 Thread.getState() 메소드는 BLOCKED 값을 리턴한다. 반면 Thread-0는 현재 "runnable" 상태로 일을 하고 있는 중이다.

또한 Thread-0과 Thread1,2,3 이 동일한 Lock Object(0x0000002af44195c8)에 대해 경합을 하고 있음을 알 수 있다. 즉 동일한 dump_test.lock 오브젝트에 대해 락 경합을 벌이고 있다.


Case2: Wait/Nofity에 의한 동기화

아래 Thread Dump는 Sun HotSpot VM에서 Wait/Notify에 의한 Thread 블로킹이 발생하는 도중의 Thread dump 결과다.
---------------------------------------------------------------------------------------------------

Full thread dump Java HotSpot(TM) 64-Bit Server VM (1.5.0_04-b05 mixed mode):

"DestroyJavaVM" prio=1 tid=0x0000000040115580 nid=0x1c6c waiting on condition [0x0000000000000000..0x0000007fbfffd380]

"Thread-3" prio=1 tid=0x0000002afedb7020 nid=0x1c7b in Object.wait() [0x00000000410c9000..0x00000000410c9db0]
at java.lang.Object.wait(Native Method)
- waiting on <0x0000002af4442a98> (a java.lang.Object)
at java.lang.Object.wait(Object.java:474)
at Thread1.run(dump_test2.java:23)
- locked <0x0000002af4442a98> (a java.lang.Object)

"Thread-2"
prio=1 tid=0x0000002afedb5830 nid=0x1c7a in Object.wait() [0x0000000040fc8000..0x0000000040fc8e30]
at java.lang.Object.wait(Native Method)
- waiting on <0x0000002af4442a98> (a java.lang.Object)
at java.lang.Object.wait(Object.java:474)
at Thread1.run(dump_test2.java:23)
- locked <0x0000002af4442a98> (a java.lang.Object)

"Thread-1" prio=1 tid=0x0000002afeda6d10 nid=0x1c79 in Object.wait() [0x0000000040ec7000..0x0000000040ec7eb0]
at java.lang.Object.wait(Native Method)
- waiting on <0x0000002af4442a98> (a java.lang.Object)
at java.lang.Object.wait(Object.java:474)
at Thread1.run(dump_test2.java:23)
- locked <0x0000002af4442a98> (a java.lang.Object)

"Thread-0" prio=1 tid=0x0000002afeda3550 nid=0x1c78 runnable [0x0000000040dc6000..0x0000000040dc6b30]
at Thread2.run(dump_test2.java:36)
...
-----------------------------------------------------------------------------------------

Synchronized에 의한 Thread 블로킹의 사례와 달리, Thread1,2,3 이 "in Object.wait()" 상태에서 대기하고 있다. 즉 BLOCKED 상태가 아닌 WAITING 상태에서 대기하고 있다.
여 기서 특별히 주의해야할 것은 Thread1,2,3을 실제로 블로킹하고 있는 Thread가 정확하게 어떤 Thread인지 직관적으로 알 수 없다는 것이다. Thread1,2,3은 비록 대기상태에 있지만, 이는 블로킹에 의한 것이 아니라 단지 Notify가 오기를 기다릴(Wait)뿐이기 때문이다. BLOCKED 상태와 WAITING 상태의 정확한 차이를 이해해야 한다.

(참고) BLOCKED 상태와 WAITING 상태의 정확한 차이를 이해하려면 다음 코드가 의미하는 바를 이해할 필요가 있다.

synchronized(lockObject) {
lockObject.wait();
doSomething();
}

위의 코드가 의미하는 바는 다음과 같다.

  1. lockObject의 Monitor에 우선 들어간다.
  2. lockObject에 대한 점유권을 놓고 Monitor의 Wait Set(대기 리스트)에서 대기한다.
  3. 다른 Thread가 Notify를 해주면 Wait Set에서 나와서 다시 lockObject를 점유한다. 만일 다른 Thread가 이미 lockObject를 점유했다면 다시 Wait Set에서 대기한다.
  4. lockObject를 점유한 채 doSomething()을 수행하고, lockObject의 Monitor에서 빠져나온다.

즉, lockObject.wait() 메소드 호출을 통해 대기하고 있는 상태에서는 이미 lockObject에 대한 점유권을 포기한(Release) 상태이기 때문에 BLOCKED 상태가 아닌 WAITING 상태로 분류된다. 반면 Sycnrhonized 문장에 의해 Monitor에 아직 들어가지도 못한 상태에서는 BLOCKED 상태로 분류된다.

위 의 두 Case의 차이를 정확하게 이해하면 Thread Dump를 좀 더 명확하게 해석할 수 있다. 즉, 현재 어떤 종류의 동기화 기법에 의해 Thread 동기화 문제가 발생하고 있는지 파악할 수 있으며, 그에 따른 적절한 해결책을 제시할 수 있다.

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

다음 글에 계속...

PS)
첨부된 파일은 Thread 동기화 문제를 유발하는 두 개의 Case에 대한 Java Source 파일과 Sun HotSpot JVM, IBM JVM, JRockit JVM에서의 Thread Dump 결과들이다.

Posted by redkite
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함