각 툴에 대한 설명

1) elasticsearch => JAVA Lucene기반의 검색엔진

   URL : http://www.elasticsearch.org/

   Github : https://github.com/elasticsearch/elasticsearch


2) logstash => 실시간으로 다양한 로그를 가져와서 elasticsearch 넣어주는 역할

   URL :  http://logstash.net/

   Github : https://github.com/elasticsearch/logstash

   ※ logstash 경우 꼭 elasticsearch와 연동하지 않더라도 다양한 어플리케이션 로그를 input으로 받아서 다른 저장소로 전달하는 ouput 작업을 하기 위해서 쓰기 좋은 듯하다.


3) Kibana => elasticsearch와 연동해서 시각적으로 볼 수 있게 해주는 툴 node.js기반임

   URL :  http://www.elasticsearch.org/overview/kibana/

   Github : https://github.com/elasticsearch/kibana


설치 및 실행가이드

1. JAVA설치 - elasticsearch 사용하기 위해서 필요

$ yum install java
==================================================
 Package                              Arch        
==================================================
Installing:
 java-1.7.0-openjdk                   x86_64      
Installing for dependencies:
 flac                                 x86_64      
 giflib                               x86_64      
 jpackage-utils                       noarch      
 libasyncns                           x86_64      
 libsndfile                           x86_64      
 pulseaudio-libs                      x86_64      
 ttmkfdir                             x86_64      
 tzdata-java                          noarch      
 xorg-x11-fonts-Type1                 noarch      
Transaction Summary
==================================================
Install      10 Package(s)


2. elasticsearch 설치 및 실행

$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.4.tar.gz
$ tar xvfz elasticsearch-1.4.4.tar.gz
$ cd elasticsearch-1.4.4/bin
$ ./elasticsearch -d
$ ps aux | grep elasticsearch 

※ 옵션 -d 데몬으로 백그라운드실행


※ ElasticSearch 모니터링 추가 Plugin 설치 

$ ./plugin -install mobz/elasticsearch-head

=> URL : http://localhost:9200/_plugin/head/


$ ./plugin -install lukas-vlcek/bigdesk 

=> URL :  http://localhost:9200/_plugin/bigdesk/


$ ./plugin -install lmenezes/elasticsearch-kopf

=> URL :  http://localhost:9200/_plugin/kopf/


3. Logstash 설치

$ wget https://download.elasticsearch.org/logstash/logstash/logstash-1.4.2.tar.gz
$ tar xvfz logstash-1.4.2.tar.gz


※ 테스트 Nginx Access Log 추가

  참고사이트 : http://www.bravo-kernel.com/2014/12/setting-up-logstash-1-4-2-to-forward-nginx-logs-to-elasticsearch/


1) nginx.conf 로그구조 수정 후 Nginx 재시작

http {
    log_format main '$http_host '
                    '$remote_addr [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time '
                    '$upstream_response_time';
    access_log  /var/log/nginx/access.log  main;
}


2) nginx 패턴 추가

$ vi ./logstash-1.4.2/patterns/nginx 
NGUSERNAME [a-zA-Z\.\@\-\+_%]+
NGUSER %{NGUSERNAME}
NGINXACCESS %{IPORHOST:http_host} %{IPORHOST:clientip} \[%{HTTPDATE:timestamp}\] \"(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent} %{NUMBER:request_time:float} %{NUMBER:upstream_time:float}
NGINXACCESS %{IPORHOST:http_host} %{IPORHOST:clientip} \[%{HTTPDATE:timestamp}\] \"(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent} %{NUMBER:request_time:float

3) Nginx logstash conf 생성

$ vi ./logstash-1.4.2/log_list/nginx.conf

====================================================== input { file { path => "/var/log/nginx/access.log" } } filter { mutate { replace => { "type" => "nginx_access" } } grok { match => { "message" => "%{NGINXACCESS}" } } date { match => [ "timestamp" , "dd/MMM/YYYY:HH:mm:ss Z" ] } geoip { source => "clientip" } } output { elasticsearch { host => localhost port => 9200 protocol => http } stdout { codec => rubydebug } }

※ 데이터 읽어와서 NGINXACCESS 매칭해서 elasticsearch로 보내는 설정정보이다

   elasticsearch 외에도 logstash의 경우 다양한 input output방식으로 데이터를 실시간 전달가능하다.

※ protocol 디폴트가 node이므로 버젼에 따라서 Kibana 사용할려면 http 설정해줘야될 경우도 있다

자세한 내용 참고 : http://logstash.net/docs/1.4.2/outputs/elasticsearch


4) conf TEST 옵션으로 확인
$ ../bin/logstash -f nginx.conf -t
Configuration OK


5) logstash 실행

$ ../bin/logstash -f nginx.conf
{
         "message" => "192.168.25.111 192.0.0.30 [02/Mar/2015:15:10:37 +0900] \"GET /favicon.ico HTTP/1.1\" 404 3652 \"-\" \"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17\" 0.000 -",
        "@version" => "1",
      "@timestamp" => "2015-03-02T06:10:37.000Z",
            "host" => "testServer01",
            "path" => "/var/log/nginx/access.log",
            "type" => "nginx_access",
       "http_host" => "192.168.25.111",
        "clientip" => "192.0.0.30",
       "timestamp" => "02/Mar/2015:15:10:37 +0900",
            "verb" => "GET",
         "request" => "/favicon.ico",
     "httpversion" => "1.1",
        "response" => "404",
           "bytes" => "3652",
        "referrer" => "\"-\"",
           "agent" => "\"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17\"",
    "request_time" => 0.0
}


※ elasticsearch-head 설치했다면 http://localhost:9200/_plugin/head/ 데이터 확인


4. Kibana 설치

$ wget https://download.elasticsearch.org/kibana/kibana/kibana-4.0.0-linux-x64.tar.gz
$ tar xvfz kibana-4.0.0-linux-x64.tar.gz 
$ cd kibana-4.0.0-linux-x64

1) config 수정 ( port 및 elasticsearch_url 등)

$ vi config/kibana.yml ====================================================== # Kibana is served by a back end server. This controls which port to use. port: 5601 # The Elasticsearch instance to use for all your queries. elasticsearch_url: "http://localhost:9200"

※ 설치법 찾아보면 kibana_index: "logstash-*" 인덱스 수정하라고 하는 듯한데 logstash-*로 인덱스 잡아주면 아래 에러 나면서 사이트 접속이 안됨.....

Fatal Error Courier Fetch Error: unhandled error Error: Request to Elasticsearch failed: {"_index":"logstash-*","_type":"config","_id":"4.0.0","error":"[logstash-*] missing"}

   그래서 kibana_index: ".kibana" 그대로 유지하였더니 잘됨... 보니까 kibana_index란 셋팅하는 대쉬보드 정보 저장하는 저장소의 정보인듯함... 검색 인덱스 셋팅은 kibana 접속후에 아래와같이 Configure an index pattern에서 index 추가하면됨

2) 최종적으로 웹브라우져 켜서 config 에 설정한 port 로 접속하면됨

 - http://server_ip:5601 


※ visualization 과 Dashboard 설정하는 부분은 나중에 시간있을때 추가하는걸로~!!




Posted by 시니^^
Programming/node.js2015. 2. 26. 21:15

node.js socket.io의 cluster 사용 참고사항


기본적으로 클라이언트가 transports: ['websocket'] 기반으로만 사용한다면 문제가 되지 않는다

하지만 XHR Polling 또는 JSONP Polling 사용시에는 

{"code":1,"message":"Session ID unknown"}

문제가 발생한다

폴링은 여러번 요청을 보내는데 여러 process중에 같은 process로 붙을 수 없어서 Session ID 찾을수 없는 듯하다


그래서

http://socket.io/docs/using-multiple-nodes/ 

메뉴얼 사이트에 보면 제시하는 방법이


1. NginX configuration

node.js에서 제공되는 cluster를 사용하지 않고 NginX를 앞단에 둔다

그리고 upstream 을 통해서 프록시 서버를 둔다 그리고 ip_hash 를 설정해서 같은 ip의 경우 같은 포트(즉같은프로세스)를 보도록 해서 문제를 해결한다

※ node.js socket.io는 데몬을 각각 포트별로 여러개 띄워야된다.


2. Using Node.JS Cluster

추가로 node.js Cluster 사용시에는 https://github.com/indutny/sticky-session 

(나도 아직 테스트 제대로 해보지 않았음)


3. Passing events between nodes

그리고 클러스터 구성시에 유저들간의 메세지(이벤트) 전달은 https://github.com/automattic/socket.io-redis

socket.io-redis이용해서 가능한 방법을 제공해주고있다

테스트해보니까 다른 node 프로세스로 붙어있지만 아래 명령어 실행시 이상없이 잘 동작한다.

socket.broadcast.emit  / 자신제외 전체유저

io.sockets.in(socket_id).emit / 특정유저에게메세지전달 

socket.broadcast.to(room_id).emit / 같은 룸에 입장된 유저에게 메세지전달

추가로 용량 처리가 많을 경우 detect_buffers 옵션을 true 해줘야됨

var redis  = require("redis");
var redisAdapter = require('socket.io-redis');
var pub = redis.createClient("/tmp/redis.sock",{ detect_buffers: true });
var sub = redis.createClient("/tmp/redis.sock",{ detect_buffers: true });
io.adapter( redisAdapter({pubClient: pub, subClient: sub}) );



※ socket.io 서비스 하기 위해서 유저별 socket.id를 관리하는 redis 와 서비스 비지니스 로직에 적절한 cluster 기능을 잘 구성해서 사용할 듯합니다.



해당 이슈로써 https://github.com/Automattic/socket.io/issues/1503 어느정도 방안에 대한 댓글을 볼수있다.


아래와 같은 것들도 있는 듯하다 아무쪼록 서비스 방향에 결정되면 좀더 연구해봐야될듯함

https://github.com/TopCloud/socketcluster

https://devcenter.heroku.com/articles/node-sessions 


Posted by 시니^^
Programming/node.js2015. 2. 4. 11:33

node.js  Net 라이브러리 이용한 TCP 서버만들기


※ 자세한 내용은 아래 메뉴얼 참고

- http://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener


1. Server Code

var net = require('net'),fs = require("fs");
var sockFile = '/tmp/nodejs.sock';

var server = net.createServer(function(client) { 
  console.log('client connected');
  //client.write('hello\r\n'); //클라이언트에게 최초 접속시 데이터전달

  //클라이언트에게 받은 데이터
  client.on('data',function(data){ 
      console.log('client In Data : '+data);
      var sendData = 'hello '+data;
      console.log('client Send Data : '+sendData);
      client.write(sendData); //클라이언트에게 추가로 데이터를 보냄
  });

  client.on('end', function() {
    console.log('client disconnected');
  });

  //client.on('data') 이벤트에서 client.write된 데이터와 클라이언트에서 받은 데이터해서 클라이언트에게 보냄
  //client.pipe(client);
});

server.on('error', function (e) {
    //unix sock 사용시
    if (e.code == 'EADDRINUSE') {
        var clientSocket = new net.Socket();
        // handle error trying to talk to server
        clientSocket.on('error', function(e) { 
             // No other server listening
            if (e.code == 'ECONNREFUSED') { 
                fs.unlinkSync(sockFile);
                 //'listening' listener
                server.listen(sockFile, function() {
                    console.log('server recovered');
                });
            }
        });
        clientSocket.connect({path: sockFile}, function() { 
            console.log('Server running, giving up...');
            process.exit();
        });
    }
});

//server.listen(sockFile, function() { //UNIX domain sockets  사용시 
server.listen(8124, function() { //'listening' listener
    console.log('PID ['+process.pid+'] TCP Server listening');
});


2. Client Code

var net = require('net');

//var client = net.connect({path: '/tmp/nodejs.sock'},function() { // UNIX domain sockets  사용시 
var client = net.connect({port: 8124},function() { //'connect' listener
  console.log('connected to server!');
  var data  = 'world!';
  console.log('serve send data : '+data);
  client.write(data);
});

//서버로 부터 받은 데이터
client.on('data', function(data) {
  console.log('serve get data : '+data.toString());
  client.end();
});

client.on('end', function() {
  console.log('disconnected from server');
});

client.on('error', function(err) {
  console.log(err);
});


Posted by 시니^^