주키퍼 설치 및 설정

주키퍼 설치 및 설정

주키퍼를 설치 해보자. 다운로드 여기서 다운 받으면 되겠다

압축을 풀고 원하는 디렉토리에 넣어두자. 필자는 /usr/local/에 넣어 두었다.
${home}/conf/zoo.cfg 파일이 주키퍼 설정 파일이다.

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184

설정을 저장하자.
서버를 실행시켜보자!

./bin/zkServer.sh start

JMX enabled by default
Using config: /usr/local/zookeeper1/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

주키퍼 클라이언트를 이용해서 접속해보자!

./bin/zkCli.sh -server localhost:2184

접속이 완료되었다.
간단하게 노드를 만들어보자.

[zk: localhost:2184(CONNECTED) 0] create /zoo_test my_data
Created /zoo_test

만들어진 노드를 확인해보자

[zk: localhost:2184(CONNECTED) 1] ls /
[zoo_test, zookeeper]

잘 만들어져 있다.
정보도 한번 보자.

[zk: localhost:2184(CONNECTED) 2] get /zoo_test
my_data
cZxid = 0x500000007
ctime = Wed Mar 02 08:37:55 UTC 2016
mZxid = 0x500000007
mtime = Wed Mar 02 08:37:55 UTC 2016
pZxid = 0x500000007
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0

다음은 replication 설정을 해보자
세개의 주키퍼가 필요하므로 세개를 복사하자.
필자는 이렇게 했다.
/usr/local/zookeeper1
/usr/local/zookeeper2
/usr/local/zookeeper3
그리고 설정을 바꿔줘야한다.
다시 zoo.cfg 파일을 열어서 아래와 같이 바꾸자.

/usr/local/zookeeper1

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper2

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper2
clientPort=2185
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper3

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper3
clientPort=2186
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

아래의 세줄이 추가 되었고 디렉토리가 변경되었다.
3개의 주키퍼 모두 바꾸자! 디렉토리는 각기 다르게! 물리적으로 서버가 같다면 포트를 나눠줘야한다.
2888 포트는 각각의 통신하기 위한 포트 3888은 마스터를 선출하기 위한 노드라 한다.
server.1,server.2,server.3 의 숫자는 /var/zookeeper1/myid의 값과 동일해야된다.

cat /var/zookeeper1/myid
1
cat /var/zookeeper2/myid
2
cat /var/zookeeper3/myid
3

세개의 노드를 실행해야된다.
귀찮다.
스크립트로 대충 만들었다

#!/bin/bash

param=$1

ZOO1_HOME="/usr/local/zookeeper1/"
ZOO2_HOME="/usr/local/zookeeper2/"
ZOO3_HOME="/usr/local/zookeeper3/"

case $param in
  start)
    $ZOO1_HOME/bin/zkServer.sh start
    $ZOO2_HOME/bin/zkServer.sh start
    $ZOO3_HOME/bin/zkServer.sh start

    ;;
  stop)
    $ZOO1_HOME/bin/zkServer.sh stop
    $ZOO2_HOME/bin/zkServer.sh stop
    $ZOO3_HOME/bin/zkServer.sh stop
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
   echo  "Usage: $0 {start|stop|restart}"
esac

이제 실행해보자!
잘된다!
다시 접속해보자!

./bin/zkCli.sh -server localhost:2184

그리도 노드를 한개더 생성해보자

[zk: localhost:2184(CONNECTED) 0] create /test test
Created /test
[zk: localhost:2184(CONNECTED) 0] ls /

test가 있는 걸 확인 후 빠져나오자 quit

./bin/zkCli.sh -server localhost:2185

이번엔 2185로 접속해보자

[zk: localhost:2185(CONNECTED) 0] ㅣls /

test가 있는걸 확인 할 수 있다.

2186 포트는 마찬가지로 추가 되어있을 것이다.

별도로 주키퍼 관리할 수 있는 관리자 화면을 누군가가 만들었다.
클로저로 만들었으니 클로저를 설치하자!
주키퍼웹UI

JAVA8에 대해 알아보자(2)

java8

이전에 FunctionalInterface와 람다표현식을 배웠다. 아직 못봤거나 까먹었다면 여기에가서 다시 보자!

Stream

Stream 에는 많은 기능이 있다. 다 설명할 수는 없지만 중요한 몇가지를 공부해보겠다.
자바의 컬렉션들은 Stream을 사용 할 수 있다. 혹은 스트림을 만들 수 있다.
흔히 쓰는 List<T>를 예로 들어 공부해보겠다.
그전에 알아두어야 할 용어가 있다.
Intermediate Operation MethodTerminal Operation Method이다.
Intermediate Operation Method는 중간단계로써 스트림을 리턴하기 때문에 계속 Method Chaining 통해 지시 할 수 있다.
그리고 Terminal Operation Method는 스트림을 끝내는 메소드다. Stream은 Lazy 하기 때문에 이 메소드가 호출되면 그때서야 Intermediate Method를 실행한다.

Optional<T> reduce(BinaryOperator<T> accumulator)
void forEach(Consumer<? super T> action)
Optional<T> max(Comparator<? super T> comparator)
long count()
Optional<T> findFirst()

등이 Terminal Operation Method에 속한다.
한번 코드를 보자!

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(numbers.stream().reduce((i, j) -> i + j).get());
numbers.stream().forEach(x -> System.out.print(x + " "));
System.out.println();
System.out.println(numbers.stream().max((i, j) -> i.compareTo(j)).get());
System.out.println(numbers.stream().min((i, j) -> i.compareTo(j)).get());
System.out.println(numbers.stream().count());
System.out.println(numbers.stream().findFirst().get());

두 번째의 reduce는 합치는 작업을 한다. i + j의 합이 다시 i 가 되고 j 는 다음번숫자로 넘어가는걸 반복한다.
forEach는 우리가 흔히 썼던 for each 문과 같다.
max는 말그대로 최대값을 찾는다. min도 마찬가지다.
count는 스트림안에 개수를 리턴한다.
findFirst는 첫 번째 있는 값을 가져온다.

Stream<T> filter(Predicate<? super T> predicate)
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
Stream<T> sorted()
Stream<T> limit(long maxSize)

등이 Intermediate Operation Method에 속한다. 이 외에도 많이 있다.
마찬가지로 코드로 보자!

numbers.stream().filter(i -> i > 5).forEach(x -> System.out.print(x + " "));
System.out.println();
numbers.stream().map(i -> i * 2).forEach(x-> System.out.print(x + " "));
System.out.println();
numbers.stream().sorted((i, j) -> j.compareTo(i)).forEach(x -> System.out.println(x));
numbers.stream().limit(4).forEach(x -> System.out.println(x));

filter는 말그대로 걸러주는 역할을 한다. 파라미터가 Predicate이다 Predicate은 boolean 값을 리턴한다.
map은 어떤타입을 다른타입 혹은 같은타입으로 변환해준다. 위 코드는 2배를 해주는 코드다.
flatMap은 map이랑 같지만 Stream타입을 리턴한다.
sorted는 정렬을 해주는 함수다. 위의 코드는 내림차순으로 정렬한 코드다.
limit는 개수는 제한하는 코드다 mysql의 limit와 같다.
그럼 한번 응용을 해보자.
1~9까지중 3보다 큰값을 골라 2배를 해주고 내림차순으로 정렬뒤 3개만출력하는 코드를 구현해보자. 간단하게 구현 할 수 있다.

numbers.stream()
        .filter(i -> i > 3)
        .map(i -> i * 2)
        .sorted((i,j) -> j.compareTo(i))
        .limit(3)
        .forEach(x -> System.out.println(x));

간단하게 Stream에 대해서 알아봤다.
어느정도 감만 잡았다면 성공한거다.
다음 시간엔 method reference 대해서도 알아보겠다.

JAVA8에 대해 알아보자(1)

java8

자바8의 새롭게 바뀐 부분이 많지만 그 중 내가 자주 쓰는걸 정리 해보겠다.

@FunctionalInterface

첫 번째로 @FunctionalInterface 인터페이스다.
람다를 쓰긴 위한 애노테이션이다. 만약 저 애노테이션이 붙은거라면 람다 표현식을 사용 할 수 있다.
하지만 명시적으로 지정 하지 않더라도 abstract 메소드가 한개라면 람바 표현식을 사용 할 수 있다.
만약 저 애노테이션을 사용한다면 abstract 메소드가 2개 이상 있을경우 컴파일 타임에 에러가 난다.
자바 기본 패키지에 있는 Function이라는 인터페이스다.

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);

    //...
}

한번 커스텀한 interface를 만들어보자.
두개의 같은 타입 파라미터를 넘겨서 두개를 더하는 인터페이스다.

@FunctionalInterface
interface AddFunction<T> {

    T apply(T t, T t1);
}

사용해 보자

AddFunction<Integer> add = (i, j) -> i + j;
System.out.println(add.apply(10, 20));

AddFunction<String> add1 = (i, j) -> i + j;
System.out.println(add1.apply("hello", " world"));

결과는 다음과 같을 것이다.

30
hello world

lambda

두 번째론 람다표현식이다. 자바 개발자 한테는 조금 생소한 표현식 이다. 하지만 다른 언어들은 일찌감치 람다 표현식을 사용하고 있다.
스칼라, 파이썬 하스켈, c#등 여러가지 언어에서 사용 하고 있다.
한번 살펴보자.
우리가 쓰레드를 사용 할때 이용하는 인터페이스중 Runnable가 있다. 이 것도 java8에선 FunctionalInterface로 구현되었다.

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

우리가 java8 이전에는 이렇게 사용하곤 했다. 우리가 흔히 말하는 익명 클래스다. 예를 든 코드다 실질적으로 이렇게 사용하진 않는다.

Runnable runnable = new Runnable() {
     @Override
     public void run() {
         System.out.println("run 호출");
     }
};
runnable.run();

그런데 람바를 쓰면 아주 간단하게 바뀐다. 한번보자.

Runnable runnable = () -> System.out.println("run 호출");
runnable.run();

6줄을 단 한줄로 바꿔버렸다. 대단하다.
그럼 어떻게 바뀌는지 한번 보자.
() 이거는 파라미터다 Runnableabstract 메소드 run은 받는 파라미터가 한개도 없다. 그래서 괄호만 해주는거다.
-> 애로우?라 부른다? 람다? 인가? 흠 그리고 다음 나오는게 메소드 바디이다. 간단하다.
그럼 다음 예제도 살펴보자
이번엔 아까 위에서 봤던 Function 인터페이스다. 이 인터페이스를 아마 자주 사용할 듯 하다.
일단 람다를 쓰지말고 한번 해보자.

Function<Integer,String> function = new Function<Integer, String>() {
    @Override
    public String apply(Integer integer) {
        return String.valueOf(integer);
    }
};
String str = function.apply(1010);
System.out.println(str);

일단 Function 인터페이스는 제네릭타입이다. 첫 번째는 파라미터타입 두 번째는 리턴 타입이다.
한마디로 어떤 타입의 파라미터로 넘기면 다른 타입을 반환하는걸 의미한다. 같은 타입을 지정해도 상관없다. 이런걸 identity라 부른다.
위의 코드는 int를 String으로 변환하는 코드다.
이제 람다로 바꿔보자!

Function<Integer,String> function = x -> String.valueOf(x);
String str = function.apply(1010);
System.out.println(str);

이것도 아주 깔끔하고 짧게 바뀌었다.
다시 한번 살펴보자. apply 메소드는 파라미터가 한개다.그래서 x라는 변수 한개를 선언했다.(파라미터가 한개일땐 ()로 감싸주지 않아도 된다.)
그리고 그 x로 String.valuOf를 이용하여 변환 하였다.
그런데 String.valueOf를 호출하기전에 그 파라미터가 어떤건지 한번 Print로 출력하고 싶다.
그럼 메소드 바디를 감싸주면 된다. 컬리브레이스로 감싸자 해보자.

Function<Integer,String> function = x -> {
    System.out.println(x);
    return String.valueOf(x);
};

이외에도 자주 쓰는 인터페이스는
Consumer<T> 어떤 타입의 파라미터로 받는다 리턴은 없다.
Predicate<T> 어떤 타입의 파라미터로 받는다 리턴은 Boolean 이다.
Supplier<T> 어떤 타입으로 리턴한다. 파라미터는 없다.

이 외에도 java.util.function 패키지에 가보면 function 인터페이스가 있다. 한번씩 보자!
다음 시간에 Stream을 공부해보겠다.