hbase를 실행하던 중 namenode 로그에 "IOException : File jobtracker.info could only be replicated to 0 nodes, instead of 1  " 이 발생되었다.




2013-04-19 15:19:28,097 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:1001237 cause:java.io.IOException: File /path/jobtracker.info could only be replicated to 0 nodes, instead of 1

2013-04-19 15:19:28,099 INFO org.apache.hadoop.ipc.Server: IPC Server handler 2 on 9000, call addBlock(/path/jobtracker.info, DFSClient_1729624478, null) from 127.0.0.1:38279: error: java.io.IOException: File /path/jobtracker.info could only be replicated to 0 nodes, instead of 1



이 문제를 해결하려면, namenode 로그를 보고 두가지를 확인한다. 나는 2번 내부 로컬 설정 이슈때문인것으로 확인했고. namenode 에러가 발생하지 않았다. 


1) iptables 방화벽

2) 내부 로컬 설정 


1)번의 경우, iptable 리스트를 확인하거나, 

systemctl disable iptables.service 을 실행하여 문제를 해결


2)번의 경우 localhost라는 것을 아예 쓰지 않고, ip 또는 /etc/hosts 설정의 서버를 활용한다. 


core-site.xml 파일의 경우, localhost로 설정했는데. ip로 변경한다. 

<AS-IS>

<configuration>

    <property>

        <name>fs.default.name</name>

        <value>hdfs://localhost:9000</value>

    </property>

</configuration>



<TO-BE>

<configuration>

    <property>

        <name>fs.default.name</name>

        <value>hdfs://1.1.1.1:9000</value>

    </property>

</configuration>







'nosql' 카테고리의 다른 글

[hbase] Phoenix ?  (0) 2013.04.22
[hbase] coprocessor 사용시 모든 테이블 동기화  (0) 2013.04.22
[hbase] 0.95.0 (아님 0.98.0) 에 적용될 mlockall  (0) 2013.04.09
[hbase] Hbase API 서버 사용  (0) 2013.04.08
[hbase] hbase & ruby  (0) 2013.04.08
Posted by '김용환'
,


1. 서론


hbase 에 java VM agent를 추가하여 region 서버 프로세스의 메모리 address를 lock할 수 있도록 기능을 추가할 예정이다. 이를 mlock_all이라 불렀다. 

상당히 실험적인 코드이며, 


2013년 4월 8일 현재 0.94.x 버전이 stable한 버전에는 포함되어 있지는 않지만, 

차기버전인 0.95 (아님 0.98부터??) 부터는 mlockall을 사용할 예정인데, 잠깐 훝어본다.


관련 자료


https://issues.apache.org/jira/browse/HBASE-4391?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel





2. mlockall 의미


user app에서 할당한 메모리영역을 RAM에 계속 있도록 개런티해주는 c함수이다. 


http://linux.die.net/man/2/mlockall


mlockall() locks all pages mapped into the address space of the calling process. This includes the pages of the code, data and stack segment, as well as shared libraries, user space kernel data, shared memory, and memory-mapped files. All mapped pages are guaranteed to be resident in RAM when the call returns successfully; the pages are guaranteed to stay in RAM until later unlocked.






3. 관련 내용 


(1) 배경


주어진 물리 메모리보다 많은 job들을 하다보면 Swapping이 일어나는데, 이 때문에 Region Server 이 문제가 되거나 Zookeeper의 connection을 잃어버리기도 한다. swapping없이 메모리를 RAM에서만 쓰도록 하게 할 수 있도록 mlockall을 쓰게 한다. 

 



(2) 데몬 실행 방법

hbase 소스를 다운받아 -Pnative 을 추가한 pom build시 libmlockall_agent.so 파일이 생성된다. 


옵션에 agentpath에 해당 모듈과 = 단위로 parsing할 수 있도록 정보를 넣는다. 

export HBASE_REGIONSERVER_OPTS="-agentpath:./libmlockall_agent.so=user=hbase" 


root권한으로 hbase region server을 실행시킨다.  

hbase --mlock user=hbase regionserver start 


만약 root권한이 아니면 다음과 같은 로그가 발생된다.

Unable to boost memlock resource limit: Operation not permitted



* 설명 

root권한으로 hbase를 실행시키지만  setuid를 hbase user로 낮춘다. 




(3)  구현

JNI에서 JVMTI를 이용했다.


소스.

http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/native/src/mlockall_agent/mlockall_agent.c?view=markup&pathrev=1353289


/*

 * Licensed to the Apache Software Foundation (ASF) under one or more

 * contributor license agreements.  See the NOTICE file distributed with

 * this work for additional information regarding copyright ownership.

 * The ASF licenses this file to You under the Apache License, Version 2.0

 * (the "License"); you may not use this file except in compliance with

 * the License.  You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


/**

 * mlockall_agent is a simple VM Agent that allows to lock the address space of 

 * the process. This avoids the process' memory eviction under pressure.

 *

 * One example is when on the same machine you run the Region Server and 

 * some map-reduce tasks, some unused data in the region server may get swapped 

 * and this affects the region server performance.

 * 

 * You can load the agent by adding it as a jvm option:

 * export HBASE_REGIONSERVER_OPTS="-agentpath:./libmlockall_agent.so=user=hbase"

 */


#include <libgen.h>

#include <grp.h>

#include <pwd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/mman.h>

#include <sys/resource.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include "jvmti.h"


typedef struct opts {

  char *setuid_user;

} opts_t;


#define PREFIX "mlockall_agent: "

#define LOG(fmt, ...) { fprintf(stderr, PREFIX fmt, #__VA_ARGS__); }


static int parse_options (const char *options, opts_t *parsed) {

  char *optr, *opts_dup;

  char *save2 = NULL;

  char *save = NULL;

  char *key, *val;

  int ret = 0;

  char *tok;


  memset(parsed, 0, sizeof(opts_t));

  if ((opts_dup = strdup(options)) == NULL)

    return(-1);


  optr = opts_dup;

  while ((tok = strtok_r(optr, ",", &save)) != NULL) {

    optr = NULL;

    save2 = NULL;


    key = strtok_r(tok, "=", &save2);    

    val = strtok_r(NULL, "=", &save2);

    if (!strcmp(key, "user")) {

      parsed->setuid_user = strdup(val);

    } else {

      LOG("Unknown agent parameter '%s'\n", key);

      ret = 1;

    }

  }


  free(opts_dup);

  return(ret);

}


static void warn_unless_root() {

  if (geteuid() != 0) {

    LOG("(this may be because java was not run as root!)\n");

  }

}


JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *init_str, void *reserved) {

  struct passwd *pwd = NULL;

  opts_t opts;


  if (parse_options(init_str, &opts)) {

    return(1);

  }


  // Check that the target user for setuid is specified if current user is root

  if (opts.setuid_user == NULL) {

    LOG("Unable to setuid: specify a target username as the agent option user=<username>\n");

    return(1);

  }


  // Check that this user exists

  if ((pwd = getpwnam(opts.setuid_user)) == NULL) {

    LOG("Unable to setuid: could not find user '%s'\n", opts.setuid_user);

    return(1);

  }


  // Boost the mlock limit up to infinity

  struct rlimit lim;

  lim.rlim_max = RLIM_INFINITY;

  lim.rlim_cur = lim.rlim_max;

  if (setrlimit(RLIMIT_MEMLOCK, &lim)) {

    perror(PREFIX "Unable to boost memlock resource limit");

    warn_unless_root();

    return(1);

  }


  // Actually lock our memory, including future allocations.

  if (mlockall(MCL_CURRENT | MCL_FUTURE)) {

    perror(PREFIX "Unable to lock memory.");

    warn_unless_root();

    return(1);

  }


  // Drop down to the user's supplemental group list

  if (initgroups(opts.setuid_user, pwd->pw_gid)) {

    perror(PREFIX "Unable to initgroups");

    warn_unless_root();

    return(1);

  }

 

  // And primary group ID

  if (setgid(pwd->pw_gid)) {

    perror(PREFIX "Unable to setgid");

    warn_unless_root();

    return(1);

  }


  // And user ID

  if (setuid(pwd->pw_uid)) {

    perror(PREFIX "Unable to setuid");

    warn_unless_root();

    return(1);

  }


  LOG("Successfully locked memory and setuid to %s\n", opts.setuid_user);

  return(0);

}





4. 참고

elastic search에도 비슷한 내용이 들어가 있다.


http://www.elasticsearch.org/guide/reference/setup/installation/



Memory Settings

There is an option to use mlockall to try and lock the process address space so it won’t be swapped. For this to work, the bootstrap.mlockall should be set to true and it is recommended to set both the min and max memory allocation to be the same.

In order to see if this works or not, set the common.jna logging to DEBUG level. A solution to “Unknown mlockall error 0” can be to set ulimit -l unlimited.

Note, this is experimental feature, and might cause the JVM or shell session to exit if failing to allocate the memory (because not enough memory is available on the machine).





Posted by '김용환'
,




hbase 명령어의 help에 나와있듯이 여러 방법으로 API 가 접근가능하다. 



/nosql/hbase-0.94.6/bin$ ./hbase

Usage: hbase <command>

where <command> an option from one of these categories:

PROCESS MANAGEMENT

 rest             run an HBase REST server

  thrift           run the HBase Thrift server

  thrift2          run the HBase Thrift2 server

  avro             run an HBase Avro server



참조할 Hbase Java API의 주소는 다음과 같다. java api와 아래 api 서버들을 비교하면 좋을듯 하다. 

http://hbase.apache.org/apidocs/




1. rest

rest 방식일때는 start 앞 rest를 써야 한다. 만약 rest 없이 start하면 접근하지 않는다. port를 넣지 않을때는 8080이 디폴트 포트가 된다.


./bin/hbase rest start -p <port> 


특이사항은 http 요청시 header 사항 xml, plain, json, protobuf 타입으로 지정해서 요청할 수 있다. 

http://wiki.apache.org/hadoop/Hbase/Stargate

http://blog.cloudera.com/blog/2013/03/how-to-use-the-apache-hbase-rest-interface-part-1/


XML 스키마 정보는 다음을 참조한다. 

http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/resources/org/apache/hadoop/hbase/rest/XMLSchema.xsd?view=markup


rest 관련 hbase 설정은 다음과 같다. (http://hbase.apache.org/book/config.files.html)

hbase.rest.threads.max

The maximum number of threads of the REST server thread pool. Threads in the pool are reused to process REST requests. This controls the maximum number of requests processed concurrently. It may help to control the memory used by the REST server to avoid OOM issues. If the thread pool is full, incoming requests will be queued up and wait for some free threads. The default is 100.

Default: 100

hbase.rest.threads.min

The minimum number of threads of the REST server thread pool. The thread pool always has at least these number of threads so the REST server is ready to serve incoming requests. The default is 2.

Default: 2








2. thrift


다음과 깉이 실행하여 thrift gateway 서버를 띄운다. 

bin/hbase thrift start


디폴트 포트는 9090 이다. (아마도..^^;;)


thrift 원본 파일은 다음과 같다. 

http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift?view=markup


thrift 관련 hbase 설정은 다음과 같다. (http://hbase.apache.org/book/config.files.html)

hbase.thrift.minWorkerThreads

The "core size" of the thread pool. New threads are created on every connection until this many threads are created.

Default: 16

hbase.thrift.maxWorkerThreads

The maximum size of the thread pool. When the pending request queue overflows, new threads are created until their number reaches this number. After that, the server starts dropping connections.

Default: 1000

hbase.thrift.maxQueuedRequests

The maximum number of pending Thrift connections waiting in the queue. If there are no idle threads in the pool, the server queues requests. Only when the queue overflows, new threads are added, up to hbase.thrift.maxQueuedRequests threads.

Default: 1000




3. thrift2


hbase 0.94부터 만들어졌다. (https://issues.apache.org/jira/browse/HBASE-1744)


다음과 깉이 실행하여 thrift2 gateway 서버를 띄운다. 

bin/hbase thrift2 start


thrift api가 old하고 java api와 비슷하지 않지만, thrift2는 concurrent를 지원하는 구조이다. 

http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/thrift2/generated/package-summary.html





4. avro

0.95부터는 deprecated될 예정이다. 

https://issues.apache.org/jira/browse/HBASE-6553




5.  c/c++ 

https://github.com/facebook/native-cpp-hbase-client





Posted by '김용환'
,

[hbase] hbase & ruby

nosql 2013. 4. 8. 13:42



hbase의 shell는 ruby를 사용한다. 


 ./bin/hbase shell을 실행한 shell이 hbase-0.94.6/lib/ruby/shell.rb 소스로 연결되어 있었다. 참고로 0.94.6 hbase 에서는 jruby-complete-1.6.5.jar 를 사용하고 있다. 


$ vi bin/hbase

# figure out which class to run

if [ "$COMMAND" = "shell" ] ; then

  # eg export JRUBY_HOME=/usr/local/share/jruby

  if [ "$JRUBY_HOME" != "" ] ; then

    CLASSPATH="$JRUBY_HOME/lib/jruby.jar:$CLASSPATH"

    HBASE_OPTS="$HBASE_OPTS -Djruby.home=$JRUBY_HOME -Djruby.lib=$JRUBY_HOME/lib"

  fi

  CLASS="org.jruby.Main -X+O ${JRUBY_OPTS} ${HBASE_HOME}/bin/hirb.rb"


hirb.rb 소스를 보니. irb라는 대화형 루비 Shell이라는 모듈을 import해서 쓰고 있다.

/lib/ruby 디렉토리 및 /src/main/ruby/lib밑의 ruby 모듈을 읽어 ruby 스크립트를 실행시킨다.


따라서. /lib/ruby/shell/commands/ 밑의 다양한 ruby 스크트를 일고 shell command가 가능하도록 되어 있다. 


스크립트를 rb 파일을 읽고 쓰는 구조라 확장할 수 있을 것 같다는 생각이 들어 구글검색하니.. '확장 가능'하다. 

아래 링크의 예처럼 customized 된 ruby script를 load하여 쓸 수 있다. 

http://www.srikanthps.com/2011/07/power-of-ruby-and-hbase-shell.html




* NoMethodError 발생

hbase 실행시 만약 아래와 같은 Error가 발생할때는 JRUBY_HOME 을 살펴봐야한다. hbase 의 설정인 JRUBY_HOME path때문에 이슈가 발생된 것이기 때문에 Path를 없애고 실행시켜보면 된다. 



NoMethodError: undefined method `getTerminal' for Java::Jline::Terminal:Module

refresh_width



Posted by '김용환'
,


1. 먼저 mac에 hadoop 1.0.4 을 설치하고, hdf로 동작되는지 확인 (hbase 0.94.6이랑 맞는 pair 버전)

http://blrunner.com/29


2, Zookeeper 설치

2181포트를 띄우도록 함


3. hbase 0.94.6설치 / 설정 변경 


설치 - http://knight76.tistory.com/entry/Hbase-mac-install-mac%EC%97%90-hbase-mac-%EC%84%A4%EC%B9%98

설정을 변경


1) 설정 수정

conf/hbase-site.xml  수정


<?xml version="1.0"?>

<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>


<configuration>


        <property>

                <name>hbase.rootdir</name>

                <value>hdfs://127.0.0.1:9000/hbase</value>

                <description></description>

        </property>

        <property>

                <name>hbase.cluster.distributed</name>

                <value>true</value>

        </property>


        <property>

                <name>hbase.zookeeper.property.dataDir</name>

                <value>/nosql/zookeeper</value>

        </property>


        <property>

                <name>hbase.zookeeper.quorum</name>

                <value>127.0.0.1</value>

        </property>


        <property>

                <name>hbase.zookeeper.property.clientPort</name>

                <value>2181</value>

        </property>


        <property>

                <name>hbase.regionserver.info.bindAddress</name>

                <value>127.0.0.1</value>

        </property>


</configuration>




conf/hbase-env.sh 수정


export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home

export HBASE_LOG_DIR=${HBASE_HOME}/logs

export HBASE_MANAGES_ZK=true



2)실행

master 실행

% bin/start-hbase.sh


master backup 실행

% bin/local-master-backup.sh start 1


region server 실행

$ ./local-regionservers.sh start 1


3) 데몬 확인

$ ps -ef | grep master | grep hbase

... org.apache.hadoop.hbase.master.HMaster start

..  org.apache.hadoop.hbase.master.HMaster -D hbase.master.port=60001 -D hbase.master.info.port=60011 --backup start


$ ps -ef | grep region | grep hbase

.. org.apache.hadoop.hbase.regionserver.HRegionServer start

.. org.apache.hadoop.hbase.regionserver.HRegionServer -D hbase.regionserver.port=60201 -D hbase.regionserver.info.port=60301 start


4. Java Test Code로 확인

1) 소스
package com.google.sample.hbase;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.Bytes;

public class HBaseTest {
public static void main(String[] args) {
Configuration config = HBaseConfiguration.create();
config.set("hbase.master", "127.0.0.1"); 
    // config.set("hbase.zookeeper.quorum", "127.0.0.1");   // 이것도 되는지 확인
try {
HBaseAdmin hBaseAdmin = new HBaseAdmin(config);

if (hBaseAdmin.isTableAvailable("key1") == false) {
HTableDescriptor tableDs = new HTableDescriptor("key1");
tableDs.addFamily(new HColumnDescriptor("cf"));
hBaseAdmin.createTable(tableDs);
} else {
hBaseAdmin.disableTable("key1");
hBaseAdmin.deleteTable("key1");

HTableDescriptor tableDs = new HTableDescriptor("key1");
tableDs.addFamily(new HColumnDescriptor("cf"));
hBaseAdmin.createTable(tableDs);
}
HTable hTable = new HTable(config, "key1");
Put p = new Put(Bytes.toBytes("row1"));
p.add(Bytes.toBytes("cf"), Bytes.toBytes("a"), Bytes.toBytes("value1"));
hTable.put(p);
p = new Put(Bytes.toBytes("row2"));
p.add(Bytes.toBytes("cf"), Bytes.toBytes("b"), Bytes.toBytes("value2"));
hTable.put(p);
p = new Put(Bytes.toBytes("row3"));
p.add(Bytes.toBytes("cf"), Bytes.toBytes("c"), Bytes.toBytes("value3"));
hTable.put(p);
Scan s = new Scan();
ResultScanner scanner = hTable.getScanner(s);
try {
for (Result rowResult = scanner.next(); rowResult != null; rowResult = scanner.next()) {
System.out.println("row: " + rowResult);
}
} finally {
scanner.close();
}
hTable.close();
hBaseAdmin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}


잘도는 지 확인 

row: keyvalues={row1/cf:a/1365158122457/Put/vlen=6/ts=0}

row: keyvalues={row2/cf:b/1365158122476/Put/vlen=6/ts=0}

row: keyvalues={row3/cf:c/1365158122478/Put/vlen=6/ts=0}




Posted by '김용환'
,


아래와 같은 Exception이 발견되거든, hbase에 맞는 Spring 버전을 다시 체크해야 한다.



Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hbaseConfiguration': Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: NULL



아래 버전은 확실히 됨

  • hbase : 0.92.1,  0.94.6
  • spring data hadoop : 1.0.0.RELEASE
  • hadoop-core 1.0.4
  • spring version : 3.0.7.RELEASE, 3.1.0.RELEASE, 3.2.0.RELEASE 

(그러나 3.2.2.RELEASE는 안됨)

Posted by '김용환'
,


MAC 북(10.8)에서 hdfs가 아닌 file단위로 저장하게 해서 standalone으로 설치했다. 

간단한 구성이지만 hbase api를 이해할 수 있다. 


1. hbase 설치

hbase download url에서 설치

(http://www.apache.org/dyn/closer.cgi/hbase/ )

최신 버전은 0.94.6 이고, hbase/lib에 있는 hadoop은 1.0.4 이용  




2. 환경 수정


$ vi conf/hbase-env.sh


#export JAVA_HOME=/usr/java/jdk1.6.0/

export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home





$ vi conf/hbase-site.xml  


<configuration>

                <property>

                 <name>hbase.rootdir</name>

                 <value>file:///nosql/hbase/rootdir</value>

                 <description>The directory shared by region servers.

                 </description>

               </property>


</configuration>





3.hbase 데몬 실행


$ bin/start-hbase.sh


starting master, logging to /nosql/hbase-0.94.6/bin/../logs/hbase-knight-master.local.out





4. shell 테스트


$ ./bin/hbase shell


HBase Shell; enter 'help<RETURN>' for list of supported commands.

Type "exit<RETURN>" to leave the HBase Shell

Version 0.94.6, r1456690, Thu Mar 14 16:32:05 PDT 2013



hbase(main):002:0> create 'key1','cf'

0 row(s) in 1.0420 seconds


hbase(main):004:0> put 'key1','row1', 'cf:a', 'value1'

0 row(s) in 0.0530 seconds


hbase(main):005:0> put 'key1', 'row2', 'cf:b', 'value2

0 row(s) in 0.0190 seconds


hbase(main):006:0> put 'key1', 'row3', 'cf:c', 'value3'

0 row(s) in 0.0210 seconds


hbase(main):007:0> scan key1

NameError: undefined local variable or method `key1' for #<Object:0x3b4d679>


hbase(main):008:0> scan 'key1'

ROW                                                                   COLUMN+CELL                                                                                                                                                                                               

 row1                                                                 column=cf:a, timestamp=1365045469807, value=value1                                                                                                                                                        

 row2                                                                 column=cf:b, timestamp=1365045488451, value=value2                                                                                                                                                        

 row3                                                                 column=cf:c, timestamp=1365045506088, value=value3                                                                                                                                                        

3 row(s) in 0.0510 seconds


hbase(main):009:0> get 'key1', 'row1'

COLUMN                                                                CELL                                                                                                                                                                                                      

 cf:a                                                                 timestamp=1365045469807, value=value1                                                                                                                                                                     

1 row(s) in 0.0260 seconds


hbase(main):010:0> get 'key1'


ERROR: wrong number of arguments (1 for 2)


Here is some help for this command:

Get row or cell contents; pass table name, row, and optionally

a dictionary of column(s), timestamp, timerange and versions. Examples:


  hbase> get 't1', 'r1'

  hbase> get 't1', 'r1', {TIMERANGE => [ts1, ts2]}

  hbase> get 't1', 'r1', {COLUMN => 'c1'}

  hbase> get 't1', 'r1', {COLUMN => ['c1', 'c2', 'c3']}

  hbase> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => ts1}

  hbase> get 't1', 'r1', {COLUMN => 'c1', TIMERANGE => [ts1, ts2], VERSIONS => 4}

  hbase> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => ts1, VERSIONS => 4}

  hbase> get 't1', 'r1', {FILTER => "ValueFilter(=, 'binary:abc')"}

  hbase> get 't1', 'r1', 'c1'

  hbase> get 't1', 'r1', 'c1', 'c2'

  hbase> get 't1', 'r1', ['c1', 'c2']


hbase(main):011:0> disable 'key1'

0 row(s) in 7.0560 seconds


hbase(main):013:0> drop 'key1'

0 row(s) in 1.0570 seconds


hbase(main):015:0> exit




5. 사용 jar 확인


$ ps -ef | grep java


  502  5999     1   0  2:21PM ttys001    0:01.92 /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/bin/java -XX:OnOutOfMemoryError=kill -9 %p -Xmx1000m -XX:+UseConcMarkSweepGC -Dhbase.log.dir=/nosql/hbase-0.94.6/bin/../logs -Dhbase.log.file=hbase-knight-master.local.log -Dhbase.home.dir=/nosql/hbase-0.94.6/bin/.. -Dhbase.id.str=knight -Dhbase.root.logger=INFO,DRFA -Djava.library.path=/nosql/hbase-0.94.6/bin/../lib/native/Mac_OS_X-x86_64-64 -Dhbase.security.logger=INFO,DRFAS -classpath /nosql/hbase-0.94.6/bin/../conf:/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/lib/tools.jar:/nosql/hbase-0.94.6/bin/..:/nosql/hbase-0.94.6/bin/../hbase-0.94.6-tests.jar:/nosql/hbase-0.94.6/bin/../hbase-0.94.6.jar:/nosql/hbase-0.94.6/bin/../lib/activation-1.1.jar:/nosql/hbase-0.94.6/bin/../lib/asm-3.1.jar:/nosql/hbase-0.94.6/bin/../lib/avro-1.5.3.jar:/nosql/hbase-0.94.6/bin/../lib/avro-ipc-1.5.3.jar:/nosql/hbase-0.94.6/bin/../lib/commons-beanutils-1.7.0.jar:/nosql/hbase-0.94.6/bin/../lib/commons-beanutils-core-1.8.0.jar:/nosql/hbase-0.94.6/bin/../lib/commons-cli-1.2.jar:/nosql/hbase-0.94.6/bin/../lib/commons-codec-1.4.jar:/nosql/hbase-0.94.6/bin/../lib/commons-collections-3.2.1.jar:/nosql/hbase-0.94.6/bin/../lib/commons-configuration-1.6.jar:/nosql/hbase-0.94.6/bin/../lib/commons-digester-1.8.jar:/nosql/hbase-0.94.6/bin/../lib/commons-el-1.0.jar:/nosql/hbase-0.94.6/bin/../lib/commons-httpclient-3.1.jar:/nosql/hbase-0.94.6/bin/../lib/commons-io-2.1.jar:/nosql/hbase-0.94.6/bin/../lib/commons-lang-2.5.jar:/nosql/hbase-0.94.6/bin/../lib/commons-logging-1.1.1.jar:/nosql/hbase-0.94.6/bin/../lib/commons-math-2.1.jar:/nosql/hbase-0.94.6/bin/../lib/commons-net-1.4.1.jar:/nosql/hbase-0.94.6/bin/../lib/core-3.1.1.jar:/nosql/hbase-0.94.6/bin/../lib/guava-11.0.2.jar:/nosql/hbase-0.94.6/bin/../lib/hadoop-core-1.0.4.jar:/nosql/hbase-0.94.6/bin/../lib/high-scale-lib-1.1.1.jar:/nosql/hbase-0.94.6/bin/../lib/httpclient-4.1.2.jar:/nosql/hbase-0.94.6/bin/../lib/httpcore-4.1.3.jar:/nosql/hbase-0.94.6/bin/../lib/jackson-core-asl-1.8.8.jar:/nosql/hbase-0.94.6/bin/../lib/jackson-jaxrs-1.8.8.jar:/nosql/hbase-0.94.6/bin/../lib/jackson-mapper-asl-1.8.8.jar:/nosql/hbase-0.94.6/bin/../lib/jackson-xc-1.8.8.jar:/nosql/hbase-0.94.6/bin/../lib/jamon-runtime-2.3.1.jar:/nosql/hbase-0.94.6/bin/../lib/jasper-compiler-5.5.23.jar:/nosql/hbase-0.94.6/bin/../lib/jasper-runtime-5.5.23.jar:/nosql/hbase-0.94.6/bin/../lib/jaxb-api-2.1.jar:/nosql/hbase-0.94.6/bin/../lib/jaxb-impl-2.2.3-1.jar:/nosql/hbase-0.94.6/bin/../lib/jersey-core-1.8.jar:/nosql/hbase-0.94.6/bin/../lib/jersey-json-1.8.jar:/nosql/hbase-0.94.6/bin/../lib/jersey-server-1.8.jar:/nosql/hbase-0.94.6/bin/../lib/jettison-1.1.jar:/nosql/hbase-0.94.6/bin/../lib/jetty-6.1.26.jar:/nosql/hbase-0.94.6/bin/../lib/jetty-util-6.1.26.jar:/nosql/hbase-0.94.6/bin/../lib/jruby-complete-1.6.5.jar:/nosql/hbase-0.94.6/bin/../lib/jsp-2.1-6.1.14.jar:/nosql/hbase-0.94.6/bin/../lib/jsp-api-2.1-6.1.14.jar:/nosql/hbase-0.94.6/bin/../lib/jsr305-1.3.9.jar:/nosql/hbase-0.94.6/bin/../lib/junit-4.10-HBASE-1.jar:/nosql/hbase-0.94.6/bin/../lib/libthrift-0.8.0.jar:/nosql/hbase-0.94.6/bin/../lib/log4j-1.2.16.jar:/nosql/hbase-0.94.6/bin/../lib/metrics-core-2.1.2.jar:/nosql/hbase-0.94.6/bin/../lib/netty-3.2.4.Final.jar:/nosql/hbase-0.94.6/bin/../lib/protobuf-java-2.4.0a.jar:/nosql/hbase-0.94.6/bin/../lib/servlet-api-2.5-6.1.14.jar:/nosql/hbase-0.94.6/bin/../lib/slf4j-api-1.4.3.jar:/nosql/hbase-0.94.6/bin/../lib/slf4j-log4j12-1.4.3.jar:/nosql/hbase-0.94.6/bin/../lib/snappy-java-1.0.3.2.jar:/nosql/hbase-0.94.6/bin/../lib/stax-api-1.0.1.jar:/nosql/hbase-0.94.6/bin/../lib/velocity-1.7.jar:/nosql/hbase-0.94.6/bin/../lib/xmlenc-0.52.jar:/nosql/hbase-0.94.6/bin/../lib/zookeeper-3.4.5.jar: org.apache.hadoop.hbase.master.HMaster start




6. 종료


$ bin/stop-hbase.sh 

stopping hbase................





<웹확인>

http://localhost:60010/master-status




* 이슈 (개인적인 생각)

mac 에서 standalone으로 설치하면 hadoop client api를 쉽게 쓸 수 있으나, hdfs 프로토콜로 연결해야 하는 spring data 규격에는 맞지 않는듯 하다. spring data hadoop 소스를 가지고 테스트를 했는데. standalone으로 설치한 hbase connection실패가 계속 일어난다. 따라서 hadoop 을 설치해서 hbase에서 hdfs설정이 가능케 하는 것이 그나마 개발환경이 편할듯 싶다.  


Posted by '김용환'
,


<여러 버전 테스트시 유의사항>

설치 서버의 /tmp 위치를 dfs 파일시스템 디렉토리로 사용한다. 윈도우에서는 설치 디스크 드라이브를 따라감
만약 cygwin을 d:\에 설치했으면, d:\tmp 에 있다.
각 버전별로 디렉토리를 인식이 잘 안될 수 있으니, namenode 실행시 문제가 생기면 dfs 파일시스템인 /tmp 를 완전히 지우고 시작해야 한다.
bin/hadoop datanode -format 해서 새로 생성되게 하고 나서 bin/hadoop datanode를 실행한다.


* 0.20.2 버전 테스트시
잘됨

* 0.20.203.0 버전 테스트시

bin/hadoop tasktracker실행시 문제 발생.

11/08/22 19:01:37 ERROR mapred.TaskTracker: Can not start task tracker because j
ava.io.IOException: Failed to set permissions of path: /tmp/hadoop-nhn/mapred/lo
cal/ttprivate to 0700

살펴보는게 귀찮아서 패스..

* 0.21.0 버전 테스트시
classpath 에 새로운 정책이 수행되었나 보다. warning은 뜨지만, 기존처럼 계속 사용할 수 있다.


<설치 참고 싸이트>

http://hadoop.apache.org/common/docs/stable/single_node_setup.html

http://cardia.tistory.com/entry/Hadoop-0202-%EC%84%A4%EC%B9%98-%EB%B0%8F-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95

http://v-lad.org/Tutorials/Hadoop/00%20-%20Intro.html

http://developer.yahoo.com/hadoop/tutorial/module3.html

<설치 순서>
1. cygwin 설치. open ssh 연결 (cygwin을 워낙 잘쓰는 편이라서 자세한 내용 생략)
2. cygwin 에서 hadoop 다운로드(http://www.apache.org/dyn/closer.cgi/hadoop/common/)
3. hadoop 0.21.0 또는 0.20.2 버전 다운로드해서 "cygwin 설치디렉토리/home/계정명/"에 설치
4. cygwin 접속
5. cygwin에서 ssh 설정

(중간 중간에 yes / no 설정 잘하기)

$ ssh-host-config
*** Info: Generating /etc/ssh_host_key
*** Info: Generating /etc/ssh_host_rsa_key
*** Info: Generating /etc/ssh_host_dsa_key
*** Info: Generating /etc/ssh_host_ecdsa_key
*** Info: Creating default /etc/ssh_config file
*** Info: Creating default /etc/sshd_config file
*** Info: Privilege separation is set to yes by default since OpenSSH 3.3.
*** Info: However, this requires a non-privileged account called 'sshd'.
*** Info: For more info on privilege separation read /usr/share/doc/openssh/READ
ME.privsep.
*** Query: Should privilege separation be used? (yes/no) no
*** Info: Updating /etc/sshd_config file


*** Warning: The following functions require administrator privileges!

*** Query: Do you want to install sshd as a service?
*** Query: (Say "no" if it is already installed as a service) (yes/no) yes
*** Query: Enter the value of CYGWIN for the daemon: [] yes
*** Info: On Windows Server 2003, Windows Vista, and above, the
*** Info: SYSTEM account cannot setuid to other users -- a capability
*** Info: sshd requires.  You need to have or to create a privileged
*** Info: account.  This script will help you do so.

*** Info: You appear to be running Windows XP 64bit, Windows 2003 Server,
*** Info: or later.  On these systems, it's not possible to use the LocalSystem
*** Info: account for services that can change the user id without an
*** Info: explicit password (such as passwordless logins [e.g. public key
*** Info: authentication] via sshd).

*** Info: If you want to enable that functionality, it's required to create
*** Info: a new account with special privileges (unless a similar account
*** Info: already exists). This account is then used to run these special
*** Info: servers.

*** Info: Note that creating a new user requires that the current account
*** Info: have Administrator privileges itself.

*** Info: No privileged account could be found.

*** Info: This script plans to use 'cyg_server'.
*** Info: 'cyg_server' will only be used by registered services.
*** Query: Do you want to use a different name? (yes/no) yes
*** Query: Enter the new user name: ntsec
*** Query: Reenter: ntsec

*** Query: Create new privileged user account 'ntsec'? (yes/no) no
*** ERROR: There was a serious problem creating a privileged user.
*** Query: Do you want to proceed anyway? (yes/no) yes
*** Warning: Expected privileged user 'ntsec' does not exist.
*** Warning: Defaulting to 'SYSTEM'

*** Info: The sshd service has been installed under the LocalSystem
*** Info: account (also known as SYSTEM). To start the service now, call
*** Info: `net start sshd' or `cygrunsrv -S sshd'.  Otherwise, it
*** Info: will start automatically after the next reboot.

*** Info: Host configuration finished. Have fun!




데몬 실행하고, 키생성 하고, 테스트
$ net start sshd
CYGWIN sshd 서비스를 시작합니다..
CYGWIN sshd 서비스가 잘 시작되었습니다.

$ ssh-keygen

$ cd ~/.ssh

$ cat id_rsa.pub >> authorized_keys

$ ssh localhost
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is 71:6d:7b:51:aa:8a:2f:c1:c2:30:44:d1:b7:e0:f8:0e.
Are you sure you want to continue connecting (yes/no)?

$ ssh localhost
nhn@localhost's password:

$ logout
Connection to localhost closed.


데몬으로 실행되는지 확인 (제어판-관리도구-서비스 보면, cygwin sshd 라고 서비스가 데몬으로 실행중인지 볼 수 있음)



6. jdk 위치 수정
conf/hadoop-env.sh 파일
export JAVA_HOME="/cygdrive/c/Progra~1/Java/jdk1.6.0_24

7. 하둡 설정 파일 수정 (conf 디렉토리 밑)


conf/core-site.xml:

<configuration>
    <property>
        <name>fs.default.name</name>
        <value>hdfs://localhost:9000</value>
    </property>
</configuration>



conf/hdfs-site.xml:

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>


 


conf/mapred-site.xml:

<configuration>
    <property>
        <name>mapred.job.tracker</name>
        <value>localhost:9001</value>
    </property>
</configuration>

8. 데몬 실행
cygwin 창을 띄우고, 하나씩 실행

$ bin/hadoop namenode
$ bin/hadoop secondarynamenode
$ bin/hadoop jobtracker
$ bin/hadoop datanode
$ bin/hadoop tasktracker


9. 테스트 실행

$ bin/hadoop dfs -put conf input

$ bin/hadoop jar hadoop-mapred-examples-0.21.0.jar grep input output 'dfs[a-z]+'



그리고, 어드민포트에 접근해서 정상적으로 작동되는지 확인한다.

0.21 버전에서는 아래와 같이 출력된다.
http://localhost:50070/dfshealth.jsp




http://localhost:50030/jobtracker.jsp



 







Posted by '김용환'
,


bin/hadoop namenode -format 시에 자꾸 에러가 발생했다.

원인은 conf/core-site.xml 파일에
아래 내용을 추가하지 않았다.

$ cat conf/hdfs-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<!-- Put site-specific property overrides in this file. -->

<configuration>
     <property>
         <name>dfs.replication</name>
         <value>1</value>
     </property>
</configuration>



잘 된 모습 확인



$ bin/hadoop namenode -format
11/08/22 18:08:58 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG:   host = nhn-PC/10.64.49.213
STARTUP_MSG:   args = [-format]
STARTUP_MSG:   version = 0.20.203.0
STARTUP_MSG:   build = http://svn.apache.org/repos/asf/hadoop/common/branches/br
anch-0.20-security-203 -r 1099333; compiled by 'oom' on Wed May  4 07:57:50 PDT
2011
************************************************************/
Re-format filesystem in \tmp\hadoop-nhn\dfs\name ? (Y or N) Y 입력
11/08/22 18:09:00 INFO util.GSet: VM type       = 32-bit
11/08/22 18:09:00 INFO util.GSet: 2% max memory = 19.33375 MB
11/08/22 18:09:00 INFO util.GSet: capacity      = 2^22 = 4194304 entries
11/08/22 18:09:00 INFO util.GSet: recommended=4194304, actual=4194304
11/08/22 18:09:00 INFO namenode.FSNamesystem: fsOwner=nhn
11/08/22 18:09:00 INFO namenode.FSNamesystem: supergroup=supergroup
11/08/22 18:09:00 INFO namenode.FSNamesystem: isPermissionEnabled=true
11/08/22 18:09:00 INFO namenode.FSNamesystem: dfs.block.invalidate.limit=100
11/08/22 18:09:00 INFO namenode.FSNamesystem: isAccessTokenEnabled=false accessK
eyUpdateInterval=0 min(s), accessTokenLifetime=0 min(s)
11/08/22 18:09:00 INFO namenode.NameNode: Caching file names occuring more than
10 times
11/08/22 18:09:00 INFO common.Storage: Image file of size 109 saved in 0 seconds
.
11/08/22 18:09:01 INFO common.Storage: Storage directory \tmp\hadoop-nhn\dfs\nam
e has been successfully formatted.
11/08/22 18:09:01 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at nhn-PC/10.64.49.213
************************************************************/



 

Posted by '김용환'
,

Redis 소개

nosql 2011. 8. 18. 16:59


<내용 다운로드>
 


<슬라이드>







<관련내용>


내가 알던 캐쉬 솔루션
- memcached 기반
- mysql 기반

But, 현실은 이 둘로 만족 못해.
그 이유는 mysql의 persistent, 데이터 크기와 memcache의 1mb데이터 크기 이슈가 있다.

다양한 데이터를 지원하고,  replication도 수직/수평으로 되고, 1mb 이상 데이터를 마음대로 쓰고, 속도나 여러 언어에서 사용할 수 있는 그런 캐쉬 솔루션을 원했다.


Redis?
- Vmware (2010.3.15 스폰서)에서 밀고 있음
-Remote Dictionary Server의 약자
-Key-value store, Cache
-사용하는 곳: Github, blizzard, digg, stackoverflow
-최신 버전 : 2.2.12 (stable) 2011/08/17
-http://redis.io/


장점
- Persistence
- Speed (간단한 데이터 2백만 건을 1.28초에 저장)
- Data Structure
- Atomic Operation (tx)
- Sharding / Replication 의 용이
- Pub/sub / notification (message queue 또는 comet)  - real time
- String(1G), Hash, List, Set, Sorted Set(score필요), intersection, union, difference
- In-memory
- 데이터 TTL, Expire
- Node.js를 포함하는 클라이언트가 다양한 언어에서 구현.
- operation cost : O(1)
- Multiple Instance에 접속해서 item를 수집(select)후 옮길(move) 수 있음(locking지원)

단점 / 이슈
- Ram mode에서는 이슈는 없지만, VM mode 를 이용해서 메모리 관리할 때 속도가 많이 느려짐
- In-memory라 메모리보다 큰 데이터는 적합하지 않을 수 있음(VM 모드를 사용할 때는 메모리 제한이 없음) -> 2.4부터 VM 모드 deprecated
Persistence 의 snapshotting 이용시 I/O 이슈가 있음
- 소스 컴파일 설치
- Sharding을 클라이언트에서 잘 지정할 필요가 있음
- Replication시 blocking됨 (2.4부터 non-blocking하면서 속도개선)

왜 Redis를 주목하는가?
- Vmware의 CloudFoundry Stroage 엔진으로 사용 (mysql, mongoDB와 함께 선정).
- 성능은 memcached와 비슷 함 (리얼 환경에 따라 달라질 수 있음)
- Non blocking IO, Single Threaded
- epoll, kqueue and select 이용
- Libevent (이벤트 처리 오픈 소스) 를 이용하는 대신 자체 구현.
 => Dependent가 없음. 심플해지는 코드
- Single-thread Server
- ANSI C 구현
- 임베디드 / 서버에서 porting이 편함
- Portable 코드!
- 2.4부터는 비동기로 Replication 구성이 가능

* Node.js + redis 사용하는 사례들이 최근에 늘고 있음
* 2011년 안으로 Redis clustering을 구현할 예정    (처음부터 분산 테이블을 목표로 만들어졌기 때문에 이 부분이 구현되면 엄청난 일이 벌어질 듯..)



2.4 Release 내용들
http://antirez.com/post/everything-about-redis-24
Redis Main 개발자 블로그
- 속도개선
- Replication시 non-blocking으로 동작
- jemalloc 추가
- set또는 list에 multi adding 기능
- 그외짜잘한 성능/기선 개선




간단한 데모
http://try.redis-db.com
2.0.2 version 이라서 그 이상의 버전에서 제공하는 API를 활용할 수 없음
- mset 버그 있음..




설치/실행 방법


// 설치 (http://redis.io/download)
$ wget http://redis.googlecode.com/files/redis-2.2.12.tar.gz
$ tar xzf redis-2.2.12.tar.gz
$ cd redis-2.2.12
$ make

// 데몬 실행
$ cd src
$ cd redis-server
(daemon).. Log..



 

// 클라이언트 실행 - 다른 쉘에서 실행
$ cd 소스설치/src ; redis-cli
redis> set foo bar
OK
redis> get foo
"bar"




예제 코드

> set hello world
"OK"
> get hello
"world"



 

 
 >  set a 1
‘1’
> expire a 100
true
> get a
"`1"
> get a
"`1“
(100초 뒤)
> get a
null

 

> set foo 0
"OK"
> incr foo
1
> incr foo
2
> incr foo
3
> get foo
"3“
> decr foo
2

  

> set hello world
"OK"
> get hello
"world"
> exists hello
true
> type hello
"string"
> rename hello olleh
"OK"
> get olleh
"world"
> del olleh
1
> get olleh
null


 

 

> set a 1
"OK"
> set b 2
"OK"
> set c 3
"OK"
> mget a b c
["1","2","3"]


 

 

> sadd seta foo
true
> sadd seta bar
true
> sadd setb foo
true
> sinter seta setb
["foo"]

 





 

> lpush list a
1
> lpush list b
2
> lpush list c
3
> lpush list d
4
> lrange list 0 2
["d","c","b"]
> lrange list 0 3
["d","c","b","a"]
> lrange list 2 3
["b","a"]

 


 


 

> sadd set 1
true
> sadd set 2
true
> sadd set 3
true
> smembers set
["3","1","2"]

  

> zadd ss 1 aa
true
> zadd ss 10 zz
true
> zadd ss 9 yy
true
> zadd ss 2 bb
true
> zrange ss 0 -1
["aa","bb","yy","zz"]

 

 > hset user:1 name x
true
> hset user:1 lastname y
true
> hset user:2 name aa
true
> hget user:1
wrong number of arguments (1 for 2)
> hget user:1 name
"x"
> hgetall user:1
{"name":"x","lastname":"y"}
> hget user:2
wrong number of arguments (1 for 2)
> hget user:2 name
"aa"

  

> multi
"OK"
> lpush clist a
"QUEUED"
> lpush clist b
"QUEUED"
> lpush clist c
"QUEUED"
> lrange clist 0 -1
"QUEUED"
> exec
[1,2,3,["c","b","a"]]

  


> multi
"OK"
> lpush dlist a
"QUEUED"
> lpush dlist b
"QUEUED"
> discard
"OK"


 

 pub/sub 코드

1. subscribe 함

[test /home/www/redis/redis-2.2.12/src]# ./redis-cli
redis 127.0.0.1:6379> psubscribe news.article.*;
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "news.*;"
3) (integer) 1


 


2. publish 함

redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set article.tech.1000 "Google"
QUEUED
redis 127.0.0.1:6379> sadd article.tech 1000
QUEUED
redis 127.0.0.1:6379> publish news.article.tech 1000
QUEUED
redis 127.0.0.1:6379> exec
1) OK
2) (integer) 1
3) (integer) 0



3. subscribe 하던 부분에서 subscription 받음

1) "pmessage"
2) "news.article.*"
3) "news.article.tech"
4) "1000"






java client API - jedis (가장 괜찮은 것 같음)

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>




가장 좋은 java 클라이언트 라이브러리
- https://github.com/xetorthio/jedis
- 자바의 Map, Set 같은 Collection과 연동되어 사용 가능
- Sharding이 지원되다고 적혀있지만, 테스트는 해보지 않음

 

@Controller
@RequestMapping("/restful")
@ResponseStatus(value = HttpStatus.ACCEPTED)
public class RestfulController {

@RequestMapping(value = "/set/key/{key}/value/{value}", method = RequestMethod.GET)
public String getString(@PathVariable String key, @PathVariable String value, ModelMap model) {
System.out.println("key : " + key);
System.out.println("value : " + value);

Jedis jedis = new Jedis("1.1.1.1");
jedis.set(key, value);
String kValue = jedis.get(key);

model.addAttribute("key", key);
model.addAttribute("value", kValue);
return "test";
}
}




 
운영상 장점
- 백업은 리얼타임으로 진행
-0 Master – Slave Replication이 수직/수평적으로 scale 가능
- (지금 당장은 없지만) 올해 안으로 Clustering 기능 추가 예정
https://github.com/antirez/redis/blob/master/design-documents/REDIS-CLUSTER
- 대형 데이터 cache용 용도로 생각
 memcached는 크기가 큰 데이터에 취약
- Slave 구성시 서버를 내리지 않고 사용가능. Replication 순서
slave asks for SYNC
master BGSAVE, slave waits
master BGSAVE finished, the initial bulk data (the .rdb file) is transfered to slave
master accumulates all the new differences for the slave
master finishes sending the whole initial rdb file to slave
master start feeding the slave with the accumulated buffer, and with anything new arriving from clients, if they are writes.




운영상 이슈 & 편리
- 메모리에 있는 데이터들을 File system으로 덤프
   1) Snapshotting  (디폴트)
자식 프로세스 실행(fork)하고 자식프로세스가 임시(new) RDB파일 만들고, 그것을 다 저장하면 예전(old) 파일 이름으로 교체 (copy-on-write)
속도 이슈로 인해서 많이 고민했음

   2) Append-only file (AOF)  - 괜찮은 방법
2.0과 2.2가 절차가 다름.
만약 Snapshotting 하다가 Kill 되거나 비정상적 종료에 대비해서 실행 로그들을 따로 저장(Log Rewriting)하여 만약 재시작시 상태를 유지하기 위해서 AOF 파일을 읽음
자식 프로세스 실행(fork)하고, 자식 프로세스는 임시 AOF 파일을 저장한다. 부모 프로세스는 in-memory buffer에 새로 변경된 내용을 계산한다. 자식 프로세스는 쓰기 작업이 완료후에 부모 프로세스는 in-memory buffer의 내용을 AOF 파일에 저장한다. 새로운 파일로 교체.


 

운영상 편리
AOF를 이용한다면, 서버 관점에서는 정지시간 없이 Redis 재시작 / 업그레이드 가능 (서버 편함)
환경
설정 정보 변경시 재실행
새로운 버전의 redis 서버 재실행
포트 변경 필요,
서버의 포트를 변경하기 때문에 client의 서버 접속 포트를 수정하고 재시작 필요. (client 불편)
=> 오히려 이거 불편. 기존 방법 사용 필요




운영에 대한 모니터링툴  지원
https://scoutapp.com/plugin_urls/271-redis-monitoring
운영상, cache hit에 대한 정확한 내용은 필요없음. 요청오면 요청 그대로 보내주는 걸로..




운영상 불편할 점
- consistent hashing 을 지원하는 client를 이용해야 distribute 가능
- Sharding을 일일이 클라이언트 API를 이용해서 해줘야 함. API에서 반드시 지원


용도
- Ehcache 와 같이 expire 해도 되는 item 용도
- counter
- 최근 30개를 순서대로
- 랭킹 정보
- 일반 캐쉬 용도


Arcus 개발팀 Redis 한계를 지적한 부분 (SDEC 2011.6)
Radis 1.2 검토 대비 최신 버전 2.2 비교

- Sorted set에는 no (offset, count) option
 => 최신 버전에서는 offset, count 기능 추가
- No capped collection
=> 용량제한이 있으며, FIFO기능을 갖고 있는 고성능의 테이블을 capped collection이라고 함. 원래 Redis 지원 안함. 원래 빠르게 개발하면 의미가 없어짐
- Not enough cache statistics
- Cannot control memory use
 => info 명령어를 이용해서 간단하게 메모리 사용량 측정 가능


공부했던 레퍼런스 자료들

http://redis.io/   , http://redis.io/topics/faq
http://simonwillison.net/static/2010/redis-tutorial/
http://www.slideshare.net/tag/redis/
http://blog.mjrusso.com/2010/10/17/redis-from-the-ground-up.html
http://www.slideshare.net/Cyworld/004-cto
http://pauladamsmith.com/articles/redis-under-the-hood.html
http://hi.baidu.com/roger_long/blog/item/611b1d017f57f89de950cd87.html
http://redis.io/presentation/Redis_Cluster.pdf
http://www.slideshare.net/karmi/redis-the-ak47-of-postrelational-databases
http://pauladamsmith.com/blog/2011/03/redis_get_set.html

 

 

 


 

Posted by '김용환'
,