nosql now 2013 후기

nosql 2013.10.30 16:04

 2013년 8월에 열린 nosql now 2013 (http://nosql2013.dataversity.net/)의 후기이다. 미국 샌프란시스코 밑에 있는 산호세에서 열렸다. 다녀온 후기를 소개함.. nbp, 쿠팡분들 만났는데, 그분들이 느낀 얘기를 기다렸는데, 얘기가 없어서^^;;


<코스>

1. Session 소개 (대부분 vendor, consulting이나 가끔 진짜 좋은 발표 자료가 있음)

2. Tutorial (mongo db, neo4j, hadoop...)


<느낀점>

1. nosql 을 기반삼아  컨설팅으로 먹고 사는 벤더들이 많이 나왔음. (mongo, foundation db.....)
  오픈소스 진영을 못봐서 참 많이 아쉬웠음.

2. 머리 희끗하 양복입은 주요 업체 매니저님들이 많이 있었음. 개발자와의 비율은 10~20% 미만인듯 

3. geek스런 느낌은 거의 없었음 (infoq나 oscon이 훨씬 개발자스러웠던 기억이 남)

4. 미국 실리콘 밸리에서 일하는동네 커뮤니티 분위기 (서로 친구하세~)

5. 역시 컨퍼런스을 주도하는 세력이 얼마나 중요한지 깨달음..

6. 전혀 nosql에 대해서 아무것도 모르는 개발자들은 session안듣고 tutorial 학습하는 분위기 

7. 참석인원은


<미국사람들과 대화하면서>

1. 개발자들 중에는 인도사람들이 정말 많았음

2. IT가 평등한 사회를 연다고 생각

3. nosql에 대해서 열려있는 마인드. (우리 나라 IT회사는 db에 계속 집착하는 경우가 있음.)

4. nosql에 대해서 하나도 모르는 사람들도 생각보다 많아서 놀랬음.




<괜찮은 발표 소개>


1. netflix에서 cassnadra /astyanax 사용 발표 내용 (Managing Scale and Complexity)

netflix에서 cassnadra/java api인 astyanax를 잘 쓰고 있고, cassandra를 AWS에서 잘 구현하고 있고, AppDynamics를 이용한 서버 아키텍처/Scale/Availability를 설명함.



https://www.youtube.com/watch?v=hYpLGlfCc8Q






2. map의 m7

- hadoop, hbase 의 api만 제외하고 c++로 모두 개발한 상용 솔루션. 



- hadoop, hbase의 critical issue 해결함. 보통 IT 회사에서 내부적으로 오픈소스를 커스터마이징해놓는데. 그  전형적인 DA 용 솔루션

- 아래 자료와 흡사하게 발표

http://www.slideshare.net/mcsrivas/mapr-m7

- 오픈소스로 전환할 생각없냐고 물어보니. 발표자(CTO)가 '너희들이 다 볼 수 있겠냐? 오픈해도 못볼텐데. 우리가 다 관리할꼐' 라며.. 정중히 거절






3. Marvel Comics가 Graphs DB를 이용한 개발 공유 (Solving Fictional Problems with NoSQL)

Peter Olson @Dethtron5000 Marvel Entertainment (발표자 정보)


가장 인상깊었던 내용이었다.


간단히 말하면, Marvel Comics의 자료는 일반 DB로 구현할 수 있지만, 복잡성을 띄고 있었다고 한다. 

(참고로 Marvel Comics는 Avengers, 아이언맨, 헐크, 토르... 등 다양한 캐릭터들을 가지고 있고 퍼블리싱하는 미국의 엔터테인먼트 회사이다.)


예를 들어, 어떤 캐릭터 'A'는 만화책상으로 순차적인 번호로 퍼블리싱되지 않았다. 즉, 작가 마음대로 퍼블리싱했다. 또한 캐릭터 'A'는 다른 시대에서는 'C'라는 이름으로 불렸고, Avengers에서는 이렇게 불리기도 했다...

(사실 이런 사례들을 PPT에서 보니. 틀자체가 전혀 없는 형태의 구성이었다.)

즉, 다양한 현실세계의 복잡성을 Graph DB로 구현했다고 해서, 매료되었다. 발표자료는 아래 공유해놨다. 



http://www.slideshare.net/Dataversity/keynote-presentation-solving-fictional-problems-with-nosql




Posted by 김용환 '김용환'


1. cassandra keyspace 생성 방법 변경

cassandra 2.0 의 cqlsh에서..

cassandra 1.x 과 같은 방식으로 keyspace를 만들면 다음과 같은 에러가 발생된다.


http://www.datastax.com/docs/1.1/references/cql/CREATE_KEYSPACE

http://wiki.apache.org/cassandra/CassandraCli


cqlsh> CREATE KEYSPACE test2

   ...   WITH strategy_class = NetworkTopologyStrategy

   ...   AND strategy_options:DC1 = 3 AND durable_writes=false;

Bad Request: line 3:22 mismatched input ':' expecting '='


cqlsh> CREATE KEYSPACE test2;

Bad Request: line 2:0 mismatched input ';' expecting K_WITH


cassandra 2.0에서 새롭게 keyspace 생성방법이 바뀌었다.


CREATE KEYSPACE testKeySpace  WITH replication = { 'class': 'SimpleStrategy',  'replication_factor' : 3 };


2. conditional schema도 추가되었다. 


cqlsh> CREATE KEYSPACE IF NOT EXISTS testKeySpace  WITH replication = { 'class': 'SimpleStrategy',  'replication_factor' : 3 };


cqlsh> DROP KEYSPACE IF EXISTS testKeySpace;


cqlsh) drop table if exists cf;




DML에도 추가 가능했다. 


cqlsh:testkeyspace1> insert into tableName (empId, age) values (1,10);

cqlsh:testkeyspace1>  insert into tableName (empId, age) values (2,11) if not exists;


 [applied]

-----------

      True



cqlsh:testkeyspace1> update tableName set age=33 where empId=2;

cqlsh:testkeyspace1> update tableName set age=44 where empId=2 if age=33;


 [applied]

-----------

      True


cqlsh:testkeyspace1> select * from tableName where empId=2;


 empid | age

-------+-----

     244


(1 rows)



drop table에서는 if를 쓸 수 없다.



cqlsh:testkeyspace1> drop table tableName if empId=2;

Bad Request: line 1:21 no viable alternative at input 'if'

cqlsh:testkeyspace1> drop table tableName;




***** (고민거리) *********************

## 1

But, 버그인지는 잘 모르겠으나,  local에 실행한 cassandra에서 keyspace with replication_factor=3 생성시에 if not exist 때문에 영향을 미칠 수 있다. replication_factor를 잘 정의한 다음에 conditional schema를 써야 한다. 



cqlsh:testkeyspace> insert into tableName (empId, age) values (1,10);

cqlsh:testkeyspace> insert into tableName (empId, age) values (2,11) if not exists;

Unable to complete request: one or more nodes were unavailable.






## 2

if 와 where 절이 동시에 사용되는 경우에 항상 완벽히 동작되지 않는다. cql에서는 if와 where절을 비교한다. 이럴 때는 약간 애매한 문법이다..


cqlsh:testkeyspace1> update tableName set age=33 where empId=2 if empId=2;

Bad Request: PRIMARY KEY part empid found in SET part


그리고, where절 대신 if문은 존재할 수 없다. 


cqlsh:testkeyspace1> update tableName set age=44 if age=44;

Bad Request: line 1:28 mismatched input 'if' expecting K_WHERE





3. alter table.. drop


cassandra 1.0/1.1 에서는 column family table의 일부 column을 drop할 수 없었으나, 2.0에서는 가능하다. 


cqlsh:testkeyspace> create table tableName( empId int PRIMARY KEY, age int, address text);

cqlsh:testkeyspace> alter table tableName drop address;

cqlsh:testkeyspace> 



4. trigger 사용

그동안 성능때문에 DB의 trigger를 사용하지 않는 한국의 관습(?)이 있다. 좋아보여도 대용량에서 Trigger의 성능은 테스트해봐야할듯..


http://www.datastax.com/dev/blog/cql-in-cassandra-2-0

https://git-wip-us.apache.org/repos/asf?p=cassandra.git;a=blob_plain;f=examples/triggers/src/org/apache/cassandra/triggers/InvertedIndex.java;hb=HEAD


Trigger를 사용해보려면 ITrigger를 상속받은 자바 클래스( org.apache.cassandra.triggers.InvertedIndex)를 하나 만들어 jar로 만든후 conf/trigger 밑에 복사해 두어야 한다. 


/apache-cassandra-2.0.1/conf/triggers$ ls -al

total 8

drwxr-xr-x@  3 knight  wheel  102  9 20 19:26 ./

drwxr-xr-x@ 13 knight  wheel  442  9 20 19:26 ../

-rw-r--r--@  1 knight  wheel   61  9 20 19:26 README.txt


README.txt 안에 "Place triggers to be loaded in this directory, as jar files." 라는 설명이 들어가 있다.


trigger를 아래와 create/drop가능하다. 

create tigger myTrigger on tableName using 'org.apache.cassandra.triggers.InvertedIndex'

drop trigger myTrigger on tableName



5. secondary index 사용 

1.x때는 primary key에 column family를 추가하여 secondary index를 사용했다. 


 create table tableName( empId int, age int, address text, primary key(empId, age));


2.0부터는 create index를 사용할 수 있다. 


cqlsh:testkeyspace1>  create table tableName( empId int PRIMARY KEY, age int, address text);

cqlsh:testkeyspace1> create index on tableName(age);



6. select .. as 사용 가능 

cqlsh:testkeyspace1>  insert into tableName (empId, age) values (1,10);

cqlsh:testkeyspace1> select * from tableName;


 empid | address | age

-------+---------+-----

     1 |    null10


(1 rows)


cqlsh:testkeyspace1> select empId as emp_id, age as age_data  from tableName;


 emp_id | age_data

--------+----------

      1 |       10


(1 rows)





7. cql문에서 limit과 ttl 사용 가능


cqlsh:testkeyspace1> select * from tableName limit 1;


 empid | address | age

-------+---------+-----

     1 |    null10


(1 rows)


cqlsh:testkeyspace1> update tableName using ttl 1 set age=20 where empid=1;

cqlsh:testkeyspace1> select * from tableName;


(0 rows)




Posted by 김용환 '김용환'


Cassandra 2.0  데이터를 보는데.. 참 좋았다. (이 cassandra의 철학은 시스템이 먼저가 아닌 사람을 집중하는 것 같다. )


2.0의 키포인트는 SQL과 transaction의 강력한 지원이다. 2.1에서 cassandra가 생각하는 그림이 나올 예정이라고 한다. 현재 2.0은 전천히 진행중이다. 


SQL과 같은 CQL을 강력히 지원하는 2.0이 나올줄은 몰랐다.  결국 Google 의 Spanner처럼 비슷한 길을 길어가는 형태(SQL, transaction지원) 가 될 것 같은 느낌이 든다. 


cassandra 2.0에서 lightweight transcation(http://www.datastax.com/dev/blog/lightweight-transactions-in-cassandra-2-0) 을 사용하기로 했다. FoundationDB (https://foundationdb.com/blog/those-are-not-transactions-cassandra-2-0) 는 먼소리냐 며 태클을 걸지만... 결국은 써봐야 아는 내용일 것 같다. 



------


cassandra 2.0 이 최근에 출시되었다.

관련 기능 정보에 대한 링크를 정리한다. 


<2.0>


1. What's new cassandar 2.0

http://www.datastax.com/documentation/cassandra/2.0/webhelp/index.html


2. What’s under the hood in Cassandra 2.0

http://www.datastax.com/dev/blog/whats-under-the-hood-in-cassandra-2-0


2. Facebook’s Cassandra paper, annotated and compared to Apache Cassandra 2.0

http://www.datastax.com/documentation/articles/cassandra/cassandrathenandnow.html


3. Cassandra 2.0 Available

http://www.i-programmer.info/news/84-database/6356-cassandra-20-available.html



3. Trigger

http://www.planetcassandra.org/blog/post/whats-new-in-cassandra-20-prototype-triggers-support


4. LMAX disruptor를 이용한 performance 향상

http://lmax-exchange.github.io/disruptor/



<2.0에 적용된 흥미로운 내용>

1. super column에 대한 내용 : Removal of super column support

Tombstoning Cassandra’s super columns

http://www.wentnet.com/blog/?p=38


refactor super column implmentation to use composite column names instead

https://issues.apache.org/jira/browse/CASSANDRA-3237



2. cql, cassandra db driver (1.2부터  지원하고 있었지만 강력해졌다.)

http://wiki.apache.org/cassandra/ClientOptions

https://github.com/datastax/java-driver



3. Java 7 required (open jdk 7 으로도 잘 동작하고 있음)


Posted by 김용환 '김용환'


출처 

http://surachartopun.com/2013/01/cassandra-learn-3-cannot-parse-as-hex.html


cassandra 2.0이 새로 나와서, cassandra cli tutorial 를 보고 사용 중에 "org.apache.cassandra.db.marshal.MarshalException: cannot parse '...' as hex bytes" exception이 발생한다. 

assume을 사용하면 더이상 문제가 발생하지 않는다. 헐!


assume users keys as utf8;

assume users comparator as utf8;

assume users validator as utf8;

Posted by 김용환 '김용환'
Hbase metrics 정보가 좋아서 퍼옴..



Posted by 김용환 '김용환'

Huawei(중국 최고 통신/네트웍 장비 회사)의 자회사인 Huawei Tech 에서 이번에 Hbase에 sencdary index를 구현한 오픈소스를 내어놓았다. 그동안 scan/filter의 낮은 성능 이슈의 한계를 indexing으로 서서히 사용할 수 있을듯 싶다. 


2012년 Hadoop Technical Conference at 베이징 에서 발표한 오버뷰(클릭하면 자료를 볼 수 있음) 를 바탕으로 드디어 오픈 소스로 발표했다. 


https://github.com/Huawei-Hadoop/hindex


아마도 이 결과물들이 Hbase쪽으로 포함될 수 있을 것이다. huawei 개발자가 그동안 hadoop과 hbase에 contribution을 그동안 많이 해서 그런지. hbase committer들이 다들 좋아하는 것 같다. 


관련 내용은 아래와 같다. 


It is 100% Java, compatible with Apache HBase 0.94.8, and is open sourced under Apache Software License v2.


Following features are supported currently.

-          multiple indexes on table,

-          multi column index,

-          index based on part of a column value,

-          equals and range condition scans using index, and

-          bulk loading data to indexed table (Indexing done with bulk load)




간단히 얘기하면. 다음과 같다. 

coprocessor를 가지고 index table을 따로 만든 구조이다. get/put할때마다 index table을 사용하는 형태를 가지고 있다. 




put할 때 마다. copocessor를 이용해서 index table을 계속 유지하도록 했다. 



scan시에도 동일하게 index table을 이용하는 형태로 되어 있다. 




2012년 ppt 기준으로 봤을때.. 성능은 다음과 같았다. 


scan 성능이다. 가로축은 row이고, 세로축은 sencods를 의미한다.  




put 성능은 10% 정도 좋아지는 수준이다. 


Posted by 김용환 '김용환'

[hbase] Hbase Chore

nosql 2013.08.05 18:33

Hbase의 Chore는 일종의 Job 또는 Thread 이며 짜치는(?) 일을 Hbase에서 담당하고 있다. 생각해보면 굳이 thread 클래스를 상속받을 필요가 있겠냐마는...  사실 문제가 있다.


1. 배경

이문제는 jdk 1.6 17, jdk 7에서 패치되었지만, 그 이하의 버전에서는 deadlock 문제가 된다. 그래서 0.92.0에 Chore가 추가되었다. 


 HBASE-4367 , JDK 버그 6915621, HBASE-4101과 연관이 있다. 


Resource Bundle 클래스에서 lock이 아래와 걸린 것을 확인할 수 있다. 내부적으로 Thread.currentThread()를 monitor lock으로 사용하면서 문제가 생긴 것이라 알려져 있다. 


"IPC Server handler 37 on 60020":

        at sun.misc.Unsafe.park(Native Method)

        - parking to wait for  <0x00002aaab584cee0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)

        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747)

        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778)

        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2061)

        at org.apache.hadoop.hbase.regionserver.MemStoreFlusher.reclaimMemStoreMemory(MemStoreFlusher.java:444)

        - locked <0x00002aaab5519648> (a org.apache.hadoop.hbase.regionserver.MemStoreFlusher)

        at org.apache.hadoop.hbase.regionserver.HRegionServer.multi(HRegionServer.java:2586)



"regionserver60020.cacheFlusher":

        at java.util.ResourceBundle.endLoading(ResourceBundle.java:1506)

        - waiting to lock <0x00002aaab5519648> (a org.apache.hadoop.hbase.regionserver.MemStoreFlusher)

        at java.util.ResourceBundle.findBundle(ResourceBundle.java:1379)

        at java.util.ResourceBundle.findBundle(ResourceBundle.java:1292)

        at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1234)

        at java.util.ResourceBundle.getBundle(ResourceBundle.java:832)

        at sun.util.resources.LocaleData$1.run(LocaleData.java:127)

        at java.security.AccessController.doPrivileged(Native Method)

        at sun.util.resources.LocaleData.getBundle(LocaleData.java:125)

        at sun.util.resources.LocaleData.getTimeZoneNames(LocaleData.java:97)

        at sun.util.TimeZoneNameUtility.getBundle(TimeZoneNameUtility.java:115)

        at sun.util.TimeZoneNameUtility.retrieveDisplayNames(TimeZoneNameUtility.java:80)

        at java.util.TimeZone.getDisplayNames(TimeZone.java:399)

        at java.util.TimeZone.getDisplayName(TimeZone.java:350)

        at java.util.Date.toString(Date.java:1025)

        at java.lang.String.valueOf(String.java:2826)

        at java.lang.StringBuilder.append(StringBuilder.java:115)

        at org.apache.hadoop.hbase.regionserver.PriorityCompactionQueue$CompactionRequest.toString(PriorityCompactionQueue.java:114)

        at java.lang.String.valueOf(String.java:2826)

        at java.lang.StringBuilder.append(StringBuilder.java:115)

        at org.apache.hadoop.hbase.regionserver.PriorityCompactionQueue.addToRegionsInQueue(PriorityCompactionQueue.java:145)

        - locked <0x00002aaab55aa2a8> (a java.util.HashMap)



2. Chore




http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/Chore.html



@InterfaceAudience.Private
public abstract class Chore
extends HasThread

Chore is a task performed on a period in hbase. The chore is run in its own thread. This base abstract class provides while loop and sleeping facility. If an unhandled exception, the threads exit is logged. Implementers just need to add checking if there is work to be done and if so, do it. Its the base of most of the chore threads in hbase.

Don't subclass Chore if the task relies on being woken up for something to do, such as an entry being added to a queue, etc.


설명에 있는 것처럼 다양한 짜치는(?) 작업을 진행한다. 다음은 상속받은 클래스이다.


AssignmentManager.TimeoutMonitorAssignmentManager.TimerUpdaterBalancerChoreCatalogJanitorCleanerChoreClusterStatusChore,ClusterStatusPublisherHealthCheckChoreHRegionServer.MovedRegionsCleaner





Chore의 super class인 HasThread는 다음과 같다. Thread Wrapper의 형태를 띄고 있다. 



/**

 * Abstract class which contains a Thread and delegates the common Thread

 * methods to that instance.

 * 

 * The purpose of this class is to workaround Sun JVM bug #6915621, in which

 * something internal to the JDK uses Thread.currentThread() as a monitor

 * lock. This can produce deadlocks like HBASE-4367, HBASE-4101, etc.

 */

@InterfaceAudience.Private

public abstract class HasThread implements Runnable {

  private final Thread thread;

  

  public HasThread() {

    this.thread = new Thread(this);

  }


  public HasThread(String name) {

    this.thread = new Thread(this, name);

  }

  

  public Thread getThread() {

    return thread;

  }

  

  public abstract void run();

  

  //// Begin delegation to Thread

  

  public final String getName() {

    return thread.getName();

  }


  public void interrupt() {

    thread.interrupt();

  }


  public final boolean isAlive() {

    return thread.isAlive();

  }


  public boolean isInterrupted() {

    return thread.isInterrupted();

  }


  public final void setDaemon(boolean on) {

    thread.setDaemon(on);

  }


  public final void setName(String name) {

    thread.setName(name);

  }


  public final void setPriority(int newPriority) {

    thread.setPriority(newPriority);

  }


  public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {

    thread.setUncaughtExceptionHandler(eh);

  }


  public void start() {

    thread.start();

  }

  

  public final void join() throws InterruptedException {

    thread.join();

  }


  public final void join(long millis, int nanos) throws InterruptedException {

    thread.join(millis, nanos);

  }


  public final void join(long millis) throws InterruptedException {

    thread.join(millis);

  }

  //// End delegation to Thread

}



Chore는 다음과 같다.


public abstract class Chore extends HasThread {

  private final Log LOG = LogFactory.getLog(this.getClass());

  private final Sleeper sleeper;

  protected final Stoppable stopper;


  /**

   * @param p Period at which we should run.  Will be adjusted appropriately

   * should we find work and it takes time to complete.

   * @param stopper When {@link Stoppable#isStopped()} is true, this thread will

   * cleanup and exit cleanly.

   */

  public Chore(String name, final int p, final Stoppable stopper) {

    super(name);

    if (stopper == null){

      throw new NullPointerException("stopper cannot be null");

    }

    this.sleeper = new Sleeper(p, stopper);

    this.stopper = stopper;

  }


  /**

   * This constructor is for test only. It allows to create an object and to call chore() on

   *  it. There is no sleeper nor stoppable.

   */

  protected Chore(){

    sleeper = null;

    stopper = null;

  }


  /**

   * @see java.lang.Thread#run()

   */

  @Override

  public void run() {

    try {

      boolean initialChoreComplete = false;

      while (!this.stopper.isStopped()) {

        long startTime = System.currentTimeMillis();

        try {

          if (!initialChoreComplete) {

            initialChoreComplete = initialChore();

          } else {

            chore();

          }

        } catch (Exception e) {

          LOG.error("Caught exception", e);

          if (this.stopper.isStopped()) {

            continue;

          }

        }

        this.sleeper.sleep(startTime);

      }

    } catch (Throwable t) {

      LOG.fatal(getName() + "error", t);

    } finally {

      LOG.info(getName() + " exiting");

      cleanup();

    }

  }


  /**

   * If the thread is currently sleeping, trigger the core to happen immediately.

   * If it's in the middle of its operation, will begin another operation

   * immediately after finishing this one.

   */

  public void triggerNow() {

    this.sleeper.skipSleepCycle();

  }


  /*

   * Exposed for TESTING!

   * calls directly the chore method, from the current thread.

   */

  public void choreForTesting() {

    chore();

  }


  /**

   * Override to run a task before we start looping.

   * @return true if initial chore was successful

   */

  protected boolean initialChore() {

    // Default does nothing.

    return true;

  }


  /**

   * Look for chores.  If any found, do them else just return.

   */

  protected abstract void chore();


  /**

   * Sleep for period.

   */

  protected void sleep() {

    this.sleeper.sleep();

  }


  /**

   * Called when the chore has completed, allowing subclasses to cleanup any

   * extra overhead

   */

  protected void cleanup() {

  }

}



예를 들어 간단히 BalancerChore를 보면 hbase.balancer.period값을 읽어 그 주기 마다 HMaster의 balance() 메소드를 호출하도록 되어 있다. 



Chore는 HasThread를 상속하고, Stoppable interface를 받아 Sleeper를 구현했다. 어떤 조건에 따라 Thread를 통제하도록 코딩되어 있다. 


public abstract class Chore extends HasThread {

  private final Log LOG = LogFactory.getLog(this.getClass());

  private final Sleeper sleeper;

  protected final Stoppable stopper;


  public Chore(String name, final int p, final Stoppable stopper) {

    super(name);

    if (stopper == null){

      throw new NullPointerException("stopper cannot be null");

    }

    this.sleeper = new Sleeper(p, stopper);

    this.stopper = stopper;

  }


  protected Chore(){

    sleeper = null;

    stopper = null;

  }


  @Override

  public void run() {

    try {

      boolean initialChoreComplete = false;

      while (!this.stopper.isStopped()) {

        long startTime = System.currentTimeMillis();

        try {

          if (!initialChoreComplete) {

            initialChoreComplete = initialChore();

          } else {

            chore();

          }

        } catch (Exception e) {

          LOG.error("Caught exception", e);

          if (this.stopper.isStopped()) {

            continue;

          }

        }

        this.sleeper.sleep(startTime);

      }

    } catch (Throwable t) {

      LOG.fatal(getName() + "error", t);

    } finally {

      LOG.info(getName() + " exiting");

      cleanup();

    }

  }


  public void triggerNow() {

    this.sleeper.skipSleepCycle();

  }


  public void choreForTesting() {

    chore();

  }


  protected boolean initialChore() {

    // Default does nothing.

    return true;

  }


  protected abstract void chore();


  protected void sleep() {

    this.sleeper.sleep();

  }


  protected void cleanup() {

  }

}



그리고. CleanChore를 상속받은 LogCleaner는 다음과 같다. 



/**

 * This Chore, every time it runs, will attempt to delete the HLogs in the old logs folder. The HLog

 * is only deleted if none of the cleaner delegates says otherwise.

 * @see BaseLogCleanerDelegate

 */

@InterfaceAudience.Private

public class LogCleaner extends CleanerChore<BaseLogCleanerDelegate> {

  static final Log LOG = LogFactory.getLog(LogCleaner.class.getName());


  /**

   * @param p the period of time to sleep between each run

   * @param s the stopper

   * @param conf configuration to use

   * @param fs handle to the FS

   * @param oldLogDir the path to the archived logs

   */

  public LogCleaner(final int p, final Stoppable s, Configuration conf, FileSystem fs,

      Path oldLogDir) {

    super("LogsCleaner", p, s, conf, fs, oldLogDir, HBASE_MASTER_LOGCLEANER_PLUGINS);

  }


  @Override

  protected boolean validate(Path file) {

    return HLogUtil.validateHLogFilename(file.getName());

  }

}



좀더 재미있는 Chore는 HealthCheckChore가 될 것이다. 특정 스크립트의 timeout를 조절도 가능하다. 


 public class HealthCheckChore extends Chore {

  private static Log LOG = LogFactory.getLog(HealthCheckChore.class);

  private HealthChecker healthChecker;

  private Configuration config;

  private int threshold;

  private int numTimesUnhealthy = 0;

  private long failureWindow;

  private long startWindow;


  public HealthCheckChore(int sleepTime, Stoppable stopper, Configuration conf) {

    super("HealthChecker", sleepTime, stopper);

    LOG.info("Health Check Chore runs every " + StringUtils.formatTime(sleepTime));

    this.config = conf;

    String healthCheckScript = this.config.get(HConstants.HEALTH_SCRIPT_LOC);

    long scriptTimeout = this.config.getLong(HConstants.HEALTH_SCRIPT_TIMEOUT,

      HConstants.DEFAULT_HEALTH_SCRIPT_TIMEOUT);

    healthChecker = new HealthChecker();

    healthChecker.init(healthCheckScript, scriptTimeout);

    this.threshold = config.getInt(HConstants.HEALTH_FAILURE_THRESHOLD,

      HConstants.DEFAULT_HEALTH_FAILURE_THRESHOLD);

    this.failureWindow = (long)this.threshold * (long)sleepTime;

  }


  @Override

  protected void chore() {

    HealthReport report = healthChecker.checkHealth();

    boolean isHealthy = (report.getStatus() == HealthCheckerExitStatus.SUCCESS);

    if (!isHealthy) {

      boolean needToStop = decideToStop();

      if (needToStop) {

        this.stopper.stop("The  node reported unhealthy " + threshold

            + " number of times consecutively.");

      }

      // Always log health report.

      LOG.info("Health status at " + StringUtils.formatTime(System.currentTimeMillis()) + " : "

          + report.getHealthReport());

    }

  }


  private boolean decideToStop() {

    boolean stop = false;

    if (numTimesUnhealthy == 0) {

      // First time we are seeing a failure. No need to stop, just

      // record the time.

      numTimesUnhealthy++;

      startWindow = System.currentTimeMillis();

    } else {

      if ((System.currentTimeMillis() - startWindow) < failureWindow) {

        numTimesUnhealthy++;

        if (numTimesUnhealthy == threshold) {

          stop = true;

        } else {

          stop = false;

        }

      } else {

        // Outside of failure window, so we reset to 1.

        numTimesUnhealthy = 1;

        startWindow = System.currentTimeMillis();

        stop = false;

      }

    }

    return stop;

  }


}




Posted by 김용환 '김용환'

http://www.hbasecon.com/schedule/

Posted by 김용환 '김용환'

HBase의 Region 서버는 GC 알고리즘을 CMS을 사용함으로써 성능을 최적화하는 예가 많았다.

최근, sematext에서 g1을 활용함으로서 성능을 좋게 하는 부분을 발견했다는 블로그 (http://blog.sematext.com/2013/06/24/g1-cms-java-garbage-collector/글이 있어서 공유한다.  


jdk 1.7기반위에 g1 알고리즘(-XX:+UseG1GC)만을 적용했더니. 꽤나 좋아진 것들을 볼 수 있었다.  collection은 많이 하지만 긴 gc time이 많이 줄어들었다. 


그래프를 볼때, 10시 전이 cms 적용, 10시 이후가 g1 적용건이다. 








sematext 에서는 g1 알고리즘이 young gen에서의 많은 gc 작업이 old gen에서의 작업을 덜하게 해줌(full gc을 줄여줌)으로서 좋은 gc time이 나온것이 아닌가 바라보고 있다. 




'nosql' 카테고리의 다른 글

[hbase] Hbase Chore  (0) 2013.08.05
[hbase] hbase 2013 발표 자료 공개  (0) 2013.07.11
[hbase] regsion서버에 G1 gc 적용으로 좋아진 예  (0) 2013.07.09
[hbase] hbase shell의 prompt  (0) 2013.07.05
[hbase] Phoenix 성능  (0) 2013.06.24
[hbase] ROOT catalog table 삭제  (0) 2013.06.20
Posted by 김용환 '김용환'


hbase의 cmd 는 shell script과 ruby를 기반으로 되어 있다.


bin/hbase는 shell script이고, hirb.rb라는 ruby 파일을 호출하도록 되어 있다.


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"





1. prompt


hirb.rb는 내부적으로 ruby의 irb (Interactive Ruby Shell) 을 이용하도록 되어 있다. 


hbase(main):001:0>


3개의 word가 colon separator(:) 으로 나누어진 상태로 스크립트를 사용할 수 있다. 

첫번째 word는 main object이름를 출력하고, 두번째 word는 line number를 의미하고, 마지막 word는 semantic indentation이다. 


hbase(main):002:0> list 'test'

TABLE                                                                                                                                          

test                                                                                                                                           

1 row(s) in 0.9690 seconds




irb 정보(http://ruby-doc.org/docs/ProgrammingRuby/html/irb.htmlhttp://linux.die.net/man/1/irb)를 통해 확인해보니. 다음과 같다. 


FlagDescription
%NCurrent command.
%mto_s of the main object (self).
%Minspect of the main object (self).
%lDelimiter type. In strings that are continued across a line break, %l will display the type of delimiter used to begin the string, so you'll know how to end it. The delimiter will be one of "'/], or `.
%niIndent level. The optional number n is used as a width specification to printf, as printf("%nd").
%nnCurrent line number (n used as with the indent level).
%%A literal percent sign.


For instance, the default prompt mode is defined as follows:

IRB.conf[:PROMPT_MODE][:DEFAULT] = {
      :PROMPT_I => "%N(%m):%03n:%i> ",
      :PROMPT_S => "%N(%m):%03n:%i%l ",
      :PROMPT_C => "%N(%m):%03n:%i* ",
      :RETURN => "%s\n"
}


%i 는 설명이 없지만.. identation이다.

예제)
hbase(main):012:0> def bar
hbase(main):013:1>   def aa
hbase(main):014:2>   print bb
hbase(main):015:2>   end
hbase(main):016:1> end


2. debug

hbase> debug <RETURN>

또는 
$ ./bin/hbase shell -d


3. customized

.irbrc 파일을 생성해서 customized hbase irb shell을 구성할 수 있다. 
                        $ more .irbrc
                        require 'irb/ext/save-history'
                        IRB.conf[:SAVE_HISTORY] = 100
                        IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"


출처: http://hbase.apache.org/shell.html



Posted by 김용환 '김용환'