레이블이 deep인 게시물을 표시합니다. 모든 게시물 표시
레이블이 deep인 게시물을 표시합니다. 모든 게시물 표시

[컴] host name 과 domain name 의 차이

host name vs domain name / 호스트 / 도메인 정의 / underbar / underscore / host name 만들기 전에 주의할 점

host name 과 domain name 의 차이

결론을 이야기 하면, domain name 이 좀 더 넓은 범위라거 보면 될 것 같다.

domain name > host name

host name 은 말그대로 host 에 붙이는 name 이라고 할 수 있는데, host 라는 것은 특정 ip address 를 소유한 객체로 보면 될 것 같다.( “RFC 1035 - Domain names - implementation and specification, section-2.3.1 Preferred name syntax” 에서도 host name 을 ip address 와 mapping 되는 객체로 보고 이야기 한다.)

그래서 host name 은 이 특정 ip address 와 mapping 된 이름(name) 이라 할 수 있겠다.

dns 의 table 을 생각하면 쉽다. A record 와 AAAA record 에 쓰이는 것이 host name 이라고 생각하면 된다.

그 외에 CNAME, MX record 들에 쓰이는 domain 들은 host name 이 아니라고 보면 될 것 같다. 이 들은 더 넓은 범주인 domain name 이긴 하다

host name 을 만들때 주의할 점

RFC 1035, 2.3.1 Preferred name syntax” 를 보면, domian name 을 지을 때 다른 조건도 만족할만한 이름을 짓는게 낫다고 이야기 하면서 예시로 main domain 과 host name 이름을 지을때 어떤 조건을 만족하는게 좋은 지 이야기 해주고 있다.

mail domain같은 경우는 domain name 의 조건도 만족해야 하지만 "RFC 822 - STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES" 의 조건도 만족해야 한다.

host name 을 정할 때는 옛날 hosts.txt 에서 사용했던 규칙을 따르라고 한다. 이유는 옛날에 host 의 이름에 대해 사용했던 규칙으로 옛날 프로그램들이 만들어져 있어서 이 규칙에 맞지 않는 host name 은 host name 이 틀렸다고, 규칙에 맞지 않다고 error 를 던질 수 있기 때문이다.

그 규칙이 아래와 같다.

<domain> ::= <subdomain> | " "

<subdomain> ::= <label> | <subdomain> "." <label>

<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]

<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>

<let-dig-hyp> ::= <let-dig> | "-"

<let-dig> ::= <letter> | <digit>

<letter> ::= any one of the 52 alphabetic characters A through Z in
upper case and a through z in lower case

<digit> ::= any one of the ten digits 0 through 9

domain name에 대,소문자 사용은 가능하지만, 같은 철자로 된 domain name 이면, 대문자로 된 domain name 이나 소문자로 된 domain name 이나 같은 것으로 취급한다.

label 들은 ARPANET host name rules 을 따라야만 한다. - letter 로 시작해야만 하고 - letter 나 digit 으로 끝나야만 한다. - 그 사이의 문자는 letter, digit, hyphen 만 가능하다. - 길이는 63 자 이하여야 한다.

RFC1123 를 보면, 이전의 label 의 제약 사항중에 letter로 시작해야만 했던것은 digit으로 시작해도 된다고 바뀌었다.

From RFC-1039
     <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
To RFC-1123
      <name>  ::= <let-digit>[*[<let-or-digit-or-hyphen>]<let-or-digit>]

underscore(_) 문제

몇몇 library 들에서 host name 에 _ underscore 가 들어간 경우 문제가 된다. 특히 오래된 library 일수록 그런 경향이 있는 듯 보인다. 그러니 위의 오래된 hostname 규칙을 따르는 것이 낫다.

See Also

  1. HostNamingRules < CF < TWiki : host naming rule 과 관련한 RFC 문서 내용을 모아놓았다.

Refrences

  1. dns - Can (domain name) subdomains have an underscore "_" in it? - Stack Overflow

[컴] RxJS 는 어떤 이득이 있는가

react / reactorx / reactor extension / 원리 / RxJS 에 대한 이해 / frp 의 이득 / benefit / 무엇이 더 나은가 / 무엇때문에 왜 frp 를 쓰는가.

RxJS 는 어떤 이득이 있는가

개인적으로 이 programming model 이 기존의 방법론과 어떤 점이 다른지에 대한 개념을 잡기가 어려웠다. Observable sequence 로 굳이 만들지 않아도 충분히 코드를 짤 수 있다. 그런데 굳이 왜 이것을 사용하는가? 에 대한 의문을 해소하고 싶어서 글을 쓴다.

MS 가 만든 programming model

이 prgramming model 은 ms 에서 처음에 만들어서 (Erik Meijer and his team) open source로 공개했다고 한다. 아래는 관련글이다.

언제 사용할까?

현재까지 판단하기로 이것은 data 를 asynchronous 하게 공급하는 것들을 감싸서 event 를 날리는 어떤 객체로 만들어 쓸 수 있다.

즉 data stream (예를 들면, file read, network request 등)을 만들어 주는 library 라고 보면 될 것 같다. synchrnouse 하게 작업할 때 blocking 이 생길만한 요소가 있다면, 그것을 data stream 으로 만들면 되는 것이다.

data stream

이것을 data stream 이라고 표현하는 이유는, 만약 우리가 event emitter로 구성하면 그것은 callback function 하나를 등록하는 것으로 여길 수 있다. 그런데 stream 이라면 이것은 마치 list 에 대해 loop 을 돌면서 data 를 처리하는 개념으로 이것을 이해하고, 구성할 수 있다.

개념이 달라지기에 code 의 모습도 조금 달라진다. 하지만 결국 특정 event 가 오면 그에 대한 처리를 한다는 점에서는 event-subscribe pattern 과 맥이 닿아 있다. 하지만 모습이 바뀌고, 개념이 바뀌면서 code를 좀 다른 모양으로 할 수 있다. (event listner 를 등록하는 code와 list 를 iterate 하는 code는 사실 data 가 있을때 동작한다는 점은 같지만 다른 모습으로 구현되어 있다. 그리고 그 code를 읽는 우리의 이해도 다르다.)

간략한 코드로 설명

간략하게 code를 보면 아래처럼 myObservable을 만들게 된다. 이렇게 Obserable로 감싸면 그냥 단순하게 data-list 가 된다고 이해하자.(다만 그 data 를 주는 시점은 알수없는)

const myObservable = new rxjs.Observable(subscriber => {
  data = requestData()
  subscriber.next(data);
});

그리고 우리는 이 data-list 에서 data 가 있다고 event 를 줄때 해야 할 일을 subscribe으로 정해놓을 수 있다.

myObservable.subscribe( data => {
    // data 를 가지고 할 일
    console.log(data)
})

개념

  • Bridging to Callbacks · rxjs : callback 을 Observable sequence 형태로 변경하고, Observable sequence 를 callback 형태로 변경하는 예제를 확인할 수 있다.
  • Bridging to Promises · rxjs : Promise 을 Observable sequence 형태로 변경하고, Observable sequence 를 Promise 형태로 변경하는 예제를 확인할 수 있다.

이 Rxjs 를 이해하기에는 ref.1 의 글이 가장 좋았다.

이 rxjs 를 iterable pattern 을 구현하는 것에 대입해보자. iterable pattern 은 간단하게 생각하면 array 처럼 traversing 할 수 있도록 만들어주는 것이다. 실제로 data 가 있는데, 이것의 traverse 방법을 정의해주는 것으로 보면 될 것 같다.

이 때 우리는 next() 함수를 만들어서 그 다음의 element(value) 를 가져오게 된다. observer.next() 를 이 next() 와 같은 느낌으로 보면 이해하면 된다. 이 observer.next() 를 호출하는 시점에 특정한 value 를 “subscribe 시점에 등록해 놓은 callback 함수”에 그 value 를 전달해 주는 것이다.

const myarr = []
for(let i=0; i<myarr.length; i++){
  console.log(myarry[i])
}
class MyIterator{

  private data: {value: number, index: number}[]
  constructor(data){
    this.data = data
  }

  public next(): any{
    while(this.cursor < this.data.length){
      const curdata = this.data[this.cursor]
      this.cursor++
      if(curdata.index % 2 === 0){
        return curdata
      }
    }
  }

  public hasNext(): any{
    const cursor0 = this.cursor
    while(cursor0 < this.data.length){
      const curdata = this.data[cursor0]
      cursor0++
      if(curdata && curdata.index % 2 === 0){
        return true
      }
    }
    return false
  }

}

const miter = new MyIterator([{index:0, value: 1}, {index:1, value: 10}, {index:2, value: 100}, {index:3, value: 1000}]);

while(miter.hasNext()){
  console.log(miter.next())
}

이제 우리가 자주 쓰는 ajax 로 server에서 data 를 requst하는 부분을 봐보자. 대체로 아래와 같은 모습을 하고 있다.

var request = new XMLHttpRequest();
request.open('GET', url);
request.onload = () => {

    if (request.status === 200) {
        // do something
        console.log('success')
    } else {
        console.log(new Error(request.statusText))
    }
};

request.send();

아래처럼 observable 로 만들 수 있다. (ref. 1 참고)

const request = Observable.create((observer: Observer<any>) => {

    var request = new XMLHttpRequest();
    request.open('GET', url);
    request.onload = () => {

        if (request.status === 200) {
            observer.next(request.responseText);
            observer.complete();
        } else {

            observer.error(new Error(request.statusText));
            observer.complete();

        }

    };

    request.send();

});

request.subscribe(function onSuccess(text: string){
    console.log(text)
})

data 를 얻어오는 대리자(observerable)가 존재한다.

위의 코드에서 observer.next() 를 호출하면 우리가 subscribe 에 등록한 callback 함수를 호출하게 된다.(see also. 1 참고) 이 observer.next() 를 호출하는 주체는 Observable 이다.

Functional Reactive Programming(FRP) 에서는 observable.subscribe() 이 iterable 의 next() 의 역할을 한다고 보면 될 듯 하다. iterable 에서는 직접적으로 next()를 호출했다면, FRP 에서는 subscribe 를 한번 거쳐서 next() 를 호출하는 차이가 있다.

어쨌든 결과적으로 subscribe을 호출하면, iterable.next() 를 호출하는 것처럼, data 가 넘어오게 된다. 그러면 그것에 대한 처리를 해주면 된다.

조금 다른 점은 iterable 은 synchronous 하게 next() 로 값을 얻어온 후, 그 다음 우리가 필요한 작업(operation) 을 바로 수행하게 된다. 즉, next() 가 synchronous 하게 동작하는 것을 전제로 programming 을 작성한다.

그런데 subscribe 을 호출하면, 이것은 우리가 직접적으로 next() 를 호출하는 것이 아니기에, 실제로 값을 전달해주는 next() 가 언제 호출될 지 모른다. 바로 전달될 수도 있지만, 한참있다가 전달될 수도 있다. 그래서 우리는 asynchronous 하게 처리하기 위해 직접 subscribe 을 호출한 후 return 값을 받아서 값을 처리하지 않고, callback function 을 전달한다.

FRP 가 data traversing 의 변경이 조금 더 수월하다.

우리는 이 next() 가 호출되기 위해서는 observable.subscribe() 을 호출해야 한다. 즉 직접적으로 next() 를 호출하지 않는다. 그래서 우리는 iterable pattern 에서처럼 직접적으로 next() 를 호출하지 않고, next() 를 호출해 주기 위해 그저 subscribe할 뿐이다.

iterable pattern 에서는 우리가 직접 next() 가 어떻게 동작하는지에 대한 code를 작성했다. FRP 에서는 이 부분을 우리가 observable 에 작성한다고 보면 된다.

이 observable 에 이것을 작성해 놓으면, obserable 에서 제공하는 다양한 함수들(operation) 을 이용해서 observer.next() 를 호출하기 전에 조작이 가능하다. 예를 들면, 특정 범위에 대해서만 observer.next()를 호출하거나, 일정시간후(delay)에 observer.next()를 호출하는 등이 가능해 진다.

즉 next() 를 호출하기 전에, 우리가 만든 observable 이 전달하는 data 의 모습을 더 쉽게 변경할 수 있다. iterable 에서는 next() 를 직접호출하기 때문에, next() 를 직접 수정해서 어떤 data 를 넘겨줄 것인가를 정하게 되지만(또는 ’상속’등을 통해서 next()를 override하거나), FRP 에서는, Observable 이 제공하는 operation 등을 통해서, 어떤 iterable 을 하는 조건을(예를 들면, filtering 이나, delay 등) 쉽게 적용할 수 있도록 해주는 것이다.(see also 2 참고)

iterable pattern 이나 FRP 나 data traverse 를 어떻게 할 것인가 대해서는 똑같이 user 가 직접 작성한다. 하지만 FRP 는 이부분 중간에 layer를 하나둬서, user가 작성한 data traverse 를, 또는 data 자체의 모양을, 좀 더 쉽게 변경할 수 있도록 해놓은 것이라고 보면 될 것 같다.

code를 보면 이해하기 더 쉬울수 있다. observable 에 우리가 subscribe을 호출하는데, chaining을 통해서 이 observable 를 다른 모습으로 변경시키고, 그것을 우리가 subscribe 하기 때문이다. (see also 2 를 보면 이해가 더 쉬울 듯 하다.)

아래 코드를 보면, myObservable2 은 순수한 rxjs.Observable 이 아니다. rxjs.Observable 뒤에 .pipe() 에 의해 변형된 Observable 이다. 우리는 이 변형된 Obeservable 에 subscribe 을 하게 된다.

const myObservable2 = new rxjs.Observable(proxyObserver => {
    console.log('Observalbe');
    proxyObserver.next(42);
    proxyObserver.next(100);
    proxyObserver.complete();
  }
).pipe(
  rxjs.operators.observeOn(rxjs.asyncScheduler)
);


myObservable2.subscribe({
    next(x){
        console.log(x)
    },
    ...
});

See Also

  1. 쿠…sal: [컴] Rx.js 에서 Observable.subscribe 의 동작
  2. 쿠…sal: [컴] Rx.js 에서 새로운 스케쥴러를 사용하는 경우
  3. The introduction to Reactive Programming you've been missing · GitHub : 좋은 글, 이해가 쉽다.

Reference

  1. RxJs — An Introduction in TypeScript — Part 1 | by Yarlen Mailler | The Startup | Medium

P

[컴] Rx.js 에서 새로운 스케쥴러를 사용하는 경우

rxjs / reactx

Rx.js 에서 새로운 스케쥴러를 사용하는 경우

Observable 에 새로운 scheduler 를 set 하는 경우를 보자. 코드는 다음과 같다.

const myObservable2 = new rxjs.Observable(proxyObserver => {
    console.log('Observalbe');
    proxyObserver.next(42);
    proxyObserver.next(100);
    proxyObserver.complete();
  }
).pipe(
  rxjs.operators.observeOn(rxjs.asyncScheduler)
);

var finalObserver = {
    next(x) {
      console.log('got value ' + x)
    },
    error(err) {
      console.error('something wrong occurred: ' + err);
    },
    complete() {
       console.log('done');
    }
  };
console.log('just before subscribe');
myObservable2.subscribe(finalObserver);
console.log('just after subscribe');

간략한 코드 흐름, code flow

Observable()
  operators.observeOn(rxjs.asyncScheduler)
    const operateRetFn = operate(callback1)
  Observable.pipe(operateRetFn)
    pipeFromArray(operations)(this)
      operateRetFn(this)
        const newObservable = Observable.lift(callback2)

자세한 code flow

function Observable(subscribe) {
    if (subscribe) {
        this._subscribe = subscribe;
    }
}

function observeOn(scheduler, delay) {
    if (delay === void 0) { delay = 0; }
    return operate(function (source, subscriber) {  // callback1
        source.subscribe(
            new OperatorSubscriber(subscriber, function (value) { 
                    return subscriber.add(
                        scheduler.schedule(function () { 
                            return subscriber.next(value); 
                        }, delay)
                    ); 
                }, function () { 
                    return subscriber.add(
                        scheduler.schedule(function () { 
                            return subscriber.complete(); 
                        }, delay)
                    ); 
                }, function (err) { 
                    return subscriber.add(
                        scheduler.schedule(function () { 
                            return subscriber.error(err); 
                        }, delay)
                    ); 
                }
            )
        );
    });
}


function operate(init) {
    return function (source) {  // `operateRetFn`
        if (hasLift(source)) {
            return source.lift(function (liftedSource) {    // `callback2`
                try {
                    return init(liftedSource, this);    // `callback1` is invoked
                }
                ...
            });
        }
        throw new TypeError('Unable to lift unknown Observable type');
    };
}

Observable.prototype.pipe = function () {
    var operations = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        operations[_i] = arguments[_i];
    }
    return operations.length ? pipeFromArray(operations)(this) : this;
};

function pipeFromArray(fns) {
    ...
    if (fns.length === 1) {
        return fns[0];  // `operateRetFn` function
    }
    return function piped(input) {
        return fns.reduce(function (prev, fn) { return fn(prev); }, input);
    };
}


Observable.prototype.lift = function (operator) {
    var observable$$1 = new Observable();
    observable$$1.source = this;
    observable$$1.operator = operator;  // `callback2`
    return observable$$1;
};


Observable.prototype.subscribe = function (observerOrNext, error, complete) {
    var subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);
    if (config.useDeprecatedSynchronousErrorHandling) {
        ...
    }
    else {
        var _a = this, operator = _a.operator, source = _a.source;
        subscriber.add(operator
            ? operator.call(subscriber, source)  // 최종적으로 callback1 이 호출된다.`
            : ...
    }
    return subscriber;
};

See Also

  1. 쿠…sal: [컴] Rx.js 에서 Observable.subscribe 의 동작

References

  1. RxJS - Scheduler

[컴] Rx.js 에서 Observable.subscribe 의 동작

rxjs

Rx.js 에서 Observable.subscribe 의 동작

전체 흐름

  1. Observable.subscribe 을 호출
  2. –> Observable 생성시 등록한 callback(subscriber) 호출
  3. –> callback 안에서 subscriber.next(val)
  4. –> subscribe 시 등록한 subscriber function 을 호출
console.clear();
const myObservable = new rxjs.Observable(subscriber => {
  console.log('Observalbe');
  subscriber.next(42);
  subscriber.next(100);
  setTimeout(() => {
    subscriber.next(300); // happens asynchronously
  }, 1000);
});

myObservable.subscribe(x => {
  console.log(x);
});

myObservable.subscribe(x => {
  console.log('x2 : ' + x);
});

event 마다 해당하는 handler 를 전부 호출 하는 것이 아니다.

대체로 event 를 dispatch 하는 경우에는 event 마다 handler 의 list 를 가지고 있고, 그 event 가 호출될 때마다 해당하는 handler 를 전부 호출하는 구조이다.

하지만 여기는 다르다. 직접 실행해 보면 알겠지만, myObservable.subscribe 를 호출하는 시점에 Observable 로 등록한 function 이 동작을 시작한다. 그래서 그 안에서 subscriber.next() 를 호출하면 비로서 우리가 subscribe 을 호출하면서 등록한 function 이 실행된다.

그래서 위처럼 2번을 subscribe 해보면, 순차적으로 첫번째 subscribe 에 대한 호출이 끝나고 나서, x2에 대한 처리가 되는 것을 확인할 수 있다.

아래 글을 참고하면 좋을 듯 하다.

- ref. 1 에서 -

This is drastically different to event handler APIs like addEventListener / removeEventListener. With observable.subscribe, the given Observer is not registered as a listener in the Observable. The Observable does not even maintain a list of attached Observers.

A subscribe call is simply a way to start an “Observable execution” and deliver values or events to an Observer of that execution.

자세한 code

subscriber.next(10)
  Subscriber._next
    callback function of myObservable

subscriber.next(10)
Subscriber.prototype.next = function (value) {
    if (this.isStopped) {
        ...
    }
    else {
        this._next(value);
    }
};
Subscriber.prototype._next = function (value) {
    this.destination.next(value);
};
function wrapForErrorHandling(handler, instance) {
    return function () {
        ...
        try {
            handler.apply(void 0, __spreadArray([], __read(args)));
        }
        catch (err) {
            ...
        }
    };
}
// myObservable.subscribe(
x => {
    console.log(x);
}

myObservable.subscribe()
    Observable._trySubscribe(subscriber)
      Observable._subscribe(sink)
        Observable's callback function
       

myObservable.subscribe(x => console.log(x))
Observable.prototype.subscribe = function (observerOrNext, error, complete) {
    var subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);
    if (config.useDeprecatedSynchronousErrorHandling) {
        ...
    }
    else {
        ...
        this._trySubscribe(subscriber));
    }
    return subscriber;
};
Observable.prototype._trySubscribe = function (sink) {
    try {
        return this._subscribe(sink);
    }
    ...
};
// const myObservable = new rxjs.Observable(
subscriber => {
  console.log('Observalbe');
  subscriber.next(42);
  ...

sample source

위에서 사용한 code이다.

See Also

  1. 쿠…sal: [컴] Rx.js 에서 새로운 스케쥴러를 사용하는 경우
  2. https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#request-and-response : request, response 의 경우 어떻게 stream 으로 만드는 지에 대한 좋은 예시

References

  1. RxJS - Observable

[컴] Hadoop 의 Map Reduce job

 

맵리듀스 / 단계 / 설명 / 하둡

Hadoop 의 Map reduce job

map task

하둡의 각 map task은 다음 4개로 나뉜다.

  • record reader
  • mapper
  • combiner
  • partioner

map task의 출력으로 나오는 keys and values 는 reducer들로 전송된다. 이 keys and value 는 intermediate 값이다.

reducer task

reducer task는 다음 단계로 구분된다.

  • shuffle
  • sort
  • reduce
  • output format

map task들이 실행되는 노드에 data 가 있다. 이 방식으로는 데이터는 일반적으로 네트워크를 통해 이동할 필요가 없으며 로컬 컴퓨터에서 계산할 수 있다.

단계들(phases)

record reader

  • record reader는 input format에 의해 생성된 input split을 record로 translate한다.
  • record reader의 목적은 데이터를 record로 parse하는 것이지만, record 자체를 parse하는 것은 아니다.
  • key/value pair의 형태로 데이터를 mapper에 전달한다.
  • 보통, 이 내용에서 키는 위치 정보이고 값은 레코드를 구성하는 데이터의 덩어리(chunk of data)이다.
  • 맞춤형 레코드 리더는 이 책의 범위 밖이다.
  • 일반적으로 데이터에 적합한 record reader가 있다고 가정한다.

map

  • mapper에서는 0개 이상의 새 key/value pair을 생산하기위해서 사용자가 제공한 코드가 각 key/value pair에서 실행된다.
  • 이 key/value pair 는 중간값(intermediate value) 이다.
  • key 와 value 를 무엇으로 하는지 정하는 것은 임의적이지 않고, MapReduce job 을 완료하는데 중요하다.
  • key 는 data 가 group 되는 기준이고, value 는 reducer에서 하는 분석과 관련있는 중요한 정보이다.
  • 이 책의 디자인 패턴에는 무엇이, 왜 특정 키/값이 선택되었는지 설명하기 위해 많은 디테일이 제공될 것이다.
  • MapReduce 설계 패턴 사이의 주요한 차별화 요소 중 하나는 이 pair의 의미이다.

combiner

  • 선택적인 localized reducer인 combiner 는 map phase에서 데이터를 그룹화할 수 있다.
  • mapper에서 중간 키를 가져와서 사용자가 제공한 메소드를 적용하여 mapper의 작은 범위(scope)에서 값을 집계(aggregate)한다.
  • 예를 들어, 집계 카운트(count of aggregation)는 각 part의 카운트 합계이므로 중간 카운트를 생성한 다음, 중간 카운트를 합해서 최종 결과를 만들 수 있다.
  • 많은 상황에서 이것이 네트워크를 통해 움직이는 데이터의 크기를 감소시킨다.
  • 네트워크를 통해 세 번 전송(헬로월드, 1)하는 것보다 전송(헬로월드, 3)하는 데 더 적은 바이트를 보내게 된다.
  • combiner는 그것들을 광범위하게 사용하는 패턴으로 더 깊이 다뤄질 것입니다.
  • 많은 새로운 하둡 개발자들이 combiner를 무시하지만, 그들은 종종 나쁜점 없이 최고의 성능 향상을 제공합니다.
  • 우리는 어떤 패턴이 combiner를 사용함으로써 이득이고 어떤 패턴이 combiner를 사용할 수 없는지를 책에서 알려줄것
  • combiner는 실행을 보장하지 않으므로 전체 알고리즘의 일부가 될 수 없다.

partitioner

  • partitioner는 mapper(또는 combiner가 사용중이라면, combiner)로부터 중간 key/value pair을 가져와서 그것들을 reducer 당 하나의 shard로 나눈다.
  • 기본적으로 partitioner는 hash code를 위해 object에서 정보를 얻는다. 이 hash code는 일반적으로 md5sum 이다.
  • 그런 다음 partitionaer는 key.hashCode() % (reducer 수) 를 수행한다.
  • 이렇게 하면 키 공간이 reducer에 고르게 분산되고, 다른 mapper에서 동일한 값을 가진 키가 동일한 reducer에 배치된다.(me: 간단하게 이야기하면, % 연산으로 나온값을 reducer key 로 사용하는 것.)
  • partitioner의 기본 동작은 사용자가 정의할 수 있으며, 정렬과 같은 몇몇 고급 패턴에 존재할 것이다.
  • 그러나 partitioner 를 변경할 필요는 거의 없다.
  • partitioned data는 각 map task에 대해서 로컬 파일 시스템에 기록된다.
  • partitioned data는 해당 reducer가 가져갈 때까지 기다리게 된다.

shuffle and sort

  • reduce task는 순서 shuffle and sort 단계부터 시작합니다.
  • 이 단계에서는 모든 partitioner들에 의해 작성된 output files을 가져와서 reducer가 실행 중인 로컬 컴퓨터에 다운로드한다.
  • 이러한 개별 data 조각은 키별로 정렬돼서 하나의 더 큰 데이터 목록으로 만들어진다.
  • 이 sort의 목적은 동일한 키를 그룹화하여 reduce 작업에서 해당 값을 쉽게 iterated 되도록 하는 것이다.
  • 이 단계는 사용자가 변경할 수 없으며 프레임워크가 모든 것을 자동으로 처리한다.
  • 개발자가 제어할 수 있는 유일한 것은 custom Comparator 개체를 이용해서 어떻게 키를 정렬할지 하고 그룹화할지 정하는 것

reduce

  • reducer 는 그룹화된 데이터를 입력으로 받아, 키 그룹당 한 번씩 reduce 기능을 실행한다.
  • 함수는 해당 키와 관련된 모든 값에 대한 키와 iterator를 전달받는다.
  • 우리의 많은 패턴에서 볼 수 있듯이, 이 함수에서 광범위한 처리가 발생할 수 있다.
  • 데이터는 여러 가지 방법으로 aggragated, filtered, combined 될 수 있다.
  • reduce 함수가 완료되면 0개 이상의 key/value pair를 최종 단계인 output format으로 전송한다.
  • reduce함수는, map function과 마찬가지로, 솔루션의 핵심 논리 부분이기 때문에 작업마다 변경될 것이다.

output format

  • output format은 reduce 함수에서 최종 key/value pair를 translate해서, 그것을 record writer를 이용해서 file 에 쓴다.
  • 기본적으로 키와 값은 tab으로 구분하고 record는 newline character로 구분한다.
  • 이것은 일반적으로 더 풍부한 output format을 제공하기 위해 커스터마이징될 수 있다.
  • 데이터는 format에 관계없이 결국 HDFS에 기록된다.
  • I/O만 처리하기 때문에, output format을 커스터마이징하는 것은 이 책의 범위를 벗어난다.

Reference

  1. MapReduce Design Patterns Building Effective Algorithms and Analytics for Hadoop and Other Systems Kindle Edition by Donald Miner - 2013

[컴][os] Windows SandBox

 win10 / 샌드박스 / isolation / vm / 가상머신 / 금융어플 사용 / 금융 프로그램 사용 /

Windows SandBox

2019 년 MS 가 발표했다.

쉽게 이야기하면, vm 에 windows 를 새롭게 설치해서 사용하는 것처럼 새롭게 설치한 초기화된 windows 를 사용할 수 있게 해준다.(하지만 vm 대신에 container 를 사용한다.)

sandbox 특징

  • windows 10 Pro/Enterprise 에서 실행된다.
  • Hyper-V 위에서 실행된다.
  • 시작할 때마다 새롭게 만들어지고, 닫으면 현재 상태가 날라간다.
  • WSB format 을 사용한다. 이 file 은 config file 을 이용해서 설정할 수 있다.
    • network, vGPU, script 등 이 가능하다.
  • Windows Containers 기술에 기반한 배포.
  • Windows Container 기술과 Hyper-V 기술을 사용한다.
    • 몇년전 MS 가 windows server 용으로 Windows Container 를 발표했다. 이 기능으로 Docker 를 windows 에서 돌릴 수 있게 해줬다.

base image

  • windows 가 sandbox 자체를 customization 을 허락하지 않기 때문에 우리가 원하는 base image 를 만들 수는 없다.
  • sandbox path :%programdata%\Microsoft\Windows\Containers

sandbox 의 3개 구성요소

  1. CmService.dll(svchost.exe): Container Manager Service
    • .wil file 을 unpack 한다.
    • template VHDx file 을 만든다. 모든 Hyper-V based VM 은 machine 이 사용하는 virtual disk 를 표현하는 VHDx file 을 사용한다.
    • unpack 한 .wil file 을 이용해서 base layer를 만들고 이것을 mount 한다.
  2. vmcompute.exe: Hyper-V Host Compute Service
    • 설정파일을 읽고, container 를 만든다.
    • VM worker process 를 생성한다.
    • vSMB path 들을 만든다.
  3. vmwp.exe: Virtual Machine Worker Process
    • VM file들(VHDX/VMGS) 를 load 한다.
    • vSMB server 를 만든다.

sandbox configuration

샌드박스 설정방법은 다음 링크들을 참고하자.

  1. Windows Sandbox configuration - Windows security | Microsoft Docs
  2. How to configure Windows Sandbox on Windows 10 | Windows Central

file 전송

간단하다. windows <--> windows sandbox 사이에 copy-and-paste 가 된다.

See Also

Reference

  1. Playing in the (Windows) Sandbox - Check Point Research, 2021-03-11

[컴] RDD, Resilient Distributed Datasets

rdd / spark rdd / apache spark / 아파치 스파크 rdd 란? / rdd 의 의미

RDD, Resilient Distributed Datasets

ref. 1 의 내용을 정리했다.

RDD

Spark의 핵심 아이디어는 RDD (Resilient Distributed Datasets) 이다. Spark는 RDD 개념을 사용하여 더 빠르고 효율적인 MapReduce 작업을 수행한다.

  • RDD (Resilient Distributed Dataset)는 Spark의 기본 ‘자료구조’(data structure)다.
  • 변하지 않는 분산 된 객체 모음 이다.(immutable distributed collection of objects)
  • RDD의 각 데이터 세트는 ’클러스터의 다른 노드에서 계산 될 수있는 논리 파티션’으로 나뉜다.
  • RDD는 사용자 정의 클래스를 포함하여 모든 유형의 Python, Java 또는 Scala 객체를 담을 수 있다.


RDD 생성방법

RDD를 생성하는 방법은 다음 2가지가 있다.

  1. 드라이버 프로그램의 기존 컬렉션을 병렬화
  2. 외부 스토리지 시스템의 dataset 를 참조(referencing)
    • 외부 스토리지 시스템
      • 공유 파일 시스템
      • HDFS
      • HBase
      • Hadoop Input Format 을 제공하는 모든 데이터 소스

기존의 framework 에서 MapReduce

MapReduce는 클러스터에서 병렬 분산 알고리즘을 사용하여 대규모 데이터 세트를 처리하고 생성하는 데 널리 채택된다. 이를 통해 사용자는 작업 분산(work distribution) 과 fault tolerance에 대해 걱정할 필요없이 high-level 연산자 set (set of high-level operators)을 사용하여 병렬 계산(write parallel computations)을 write 할 수 있다.

  • 대부분의 현재 프레임 워크에서 계산들 사이에서 (Ex-두 MapReduce 작업 사이) 데이터를 재사용하는 유일한 방법은 외부의 stable storage system (ex: HDFS)에 데이터를 write 하는 것이다.
  • 반복(iterative) 및 대화형(interactive) 애플리케이션 모두 병렬 작업을 할 때 더 빠른 데이터 공유가 필요하다.
  • 복제(replication), 직렬화(serialization), 디스크 IO(disk IO)로 인해 MapReduce에서 데이터 공유는 속도가 느리다.
  • 스토리지 시스템과 관련하여 대부분의 Hadoop 애플리케이션은 HDFS read-write operation에서 시간의 90 % 이상이 소요된다.

MapReduce 에서 반복적인 작업(iterative operations)

다음 그림은 현재 framework 들이 동작하는 방식을 보여준다. 다음 3개의 동작으로 인해 상당한 overhead 가 발생하고, 그로인해 시스템 속도가 느려진다.

  • data replication
  • disk I/O
  • serialization
from: https://www.tutorialspoint.com/apache_spark/apache_spark_rdd.htm

MapReduce 에서 대화형 작업(interactive operations)

사용자는 ’같은 data 의 하위집합(subset)’에서 여러 query 들을 실행하게 된다. 그런데 이 query 를 실행할 때마다 data 를 HDFS 에서 읽어온다. 즉 disk I/O 가 발생한다. 그래서 이것이 시간을 잡아먹는다.

from: https://www.tutorialspoint.com/apache_spark/apache_spark_rdd.htm

Apache Spark RDD

Apache Spark 는 그래서 in-memory processing computation(메모리내 처리 계산) 을 지원한다. Spark 는 작업전반에 걸쳐 ‘현재 메모리 상태’(state of memory) 를 object 로 저장한다 그리고 이 object 는를 작업들(jobs) 사이에서 공유가 가능하다(sharable). 메모리에 있는 data 를 공유하는 것은 ‘네트워크' 와 'disk’ 보다 10~100배는 빠르다.

Spark RDD에서 반복적인 작업(iterative operations)

  • 중간결과를 stable storage 에 계산하는 대신 ‘분산 메모리(distributed memory)’ 에 저장한다.
  • 메모리가 부족하면 disk 에 적는다.
from: https://www.tutorialspoint.com/apache_spark/apache_spark_rdd.htm

Spark RDD에서 대화형 작업(interactive operations)

  • 만약에 여러개의 다른 query 들이 '같은 data set' 에서 실행되면, 이 특정 data 는 메모리에 저장된다. 그래서 실행속도가 빨라지게 된다.
  • 기본적으로 RDD는 실행할 때마다 새롭게 만들어지지만, 유저가 RDD 를 memory 에 유지시킬 것이다.(persist) 이 때에는 다음 query 시점에서 더 빠른 access 를 가능하게 하기위해, Spark 가 cluster 주위의 요소들을 유지할 수 있다.
  • 유지하려는 RDD(persisting RDDs) 를 disk 에 저장하거나, 여러 노드들에 복사하는 방법도 가능하다.
from: https://www.tutorialspoint.com/apache_spark/apache_spark_rdd.htm

See Also

  1. 쿠…sal: [컴] Apache Spark
  2. Using Apache Spark and MySQL for Data Analysis, 2015-10-07
    • 압축된 big data 를 spark 를 이용해서 바로 query 를 적용하는 내용
  3. RDD Programming Guide - Spark 3.1.2 Documentation
  4. 쿠...sal: [컴] RDD programming

Reference

  1. Apache Spark - RDD - Tutorialspoint

[컴] First class citizen

 1급 시민 / 1급 객체 / 1급 함수


First class citizen

First class citizen 의 특징은 다음과 같다. ref. 1 에 보면 ’Robin Popplestone’이 제안한 정의다.

  1. 모든 items 들은 function의 실질적인 parameters 이 될 수 있다.
  2. 모든 items 들은 function 의 결과로 return 될 수 있다.
  3. 모든 items 들은 할당문(assignment statement) 의 subject 가 될 수 있다. (변수등에 저장할 수 있다.)
  4. 모든 items 들은 같은지 여부(equality) 를 테스트할 수 있다.

대체로 모든 언어에서 간단한 스칼라 data type 들은 거의 대부분 first-class 이다.(예를 들면, integer, float 등등)

만약 ‘이 언어가 first-class function 을 갖고 있다’ 고 이야기한다면, 그것은 그 언어의 function 이 first-class citizen 의 특징을 가졌다는 이야기이다.

간단한 예

간단히 예를 들면, java 옛버전 에서는 함수를 parameter 로 넘기지 못한다.(JDK8 이후 가능하다.) 그래서 java 에서는 function 이 first-class citizen 이 아니다.

Higher-order function 의 특징

  • 함수를 인자(함수 parameter) 를 갖거나
  • 함수를 return 해준다.

그래서 higher-order function 을 만드려면, function 이 first-class citizen 이 돼야 한다.

See Also

  1. Currying 과 partial function

References

  1. First-class citizen - Wikipedia

[컴] Unit test best practices in C#

 유닛테스트 베스트 프랙티스 / 하는 법 / 방법 / 좋은 유닛테스트 / unittest

Unit test best practices in C#

ref.1 의 내용을 간략히 정리했다.

좋은 unit test 의 특징

  1. 빠르다.
  2. 독립적이다. 다른 것에 의존성이 없다.
  3. 반복적으로 수행할 수 있어야 한다.
  4. pass , fail 을 자동으로 감지할 수 있어야 한다.
  5. 테스트코드 작성 시간이 길지 않아야 한다. : 테스트하려는 code 를 작성하는 것보다 테스트 작성에 더 많은 시간이 걸리는 것은 새로운 테스트 디자인을 고민해 봐야 한다.

Code converage

’코드 커버리지’가 높은것이 꼭 좋은 코드를 이야기하지 않는다. 예를 들어 edge cases 등을 잘 다루지 않았다면, coverage 가 높아도 의미가 없다. 무조건 높은 coverage 를 추구하는 것은 역효과이다.

Mock 과 Stub 의 차이

Mock 은 그 자체를 테스트 하게 되는 fake object 이다. 예를 들면 아래 코드에서 처럼 mock 의 값이 변경되었는지를 assert 를 이용해서 확인한다.

var mock
var mockOrder = new FakeOrder();
var purchase = new Purchase(mockOrder);

purchase.ValidateOrders();

Assert.True(mockOrder.Validated);

반면에 Stub 은 그저 test 를 도울뿐 그자체가 test 되지 않는다.

var stubOrder = new FakeOrder();
var purchase = new Purchase(stubOrder);

purchase.ValidateOrders();

Assert.True(purchase.CanBeShipped);

Best practices

  1. test 이름을 잘 짓자
  2. 테스트를 잘 배열하자.
  3. 최소한의 통과하는 테스트를 작성하자.
  4. magic 문자열을 피하자.
  5. 테스트내에 logic 을 피하자.
  6. helper method 들을 사용하자.
  7. 여러개의 assert 를 사용하는 것을 피하자.
  8. private method 의 검증은 public method 들을 unit test 하는 것으로 검증하자.
  9. static references 들을 Stub 으로 사용하자.

1. test 이름을 잘 짓자

이름이 테스트의 의도를 명확하게 표현하기 때문이다.

이름은 다음 3가지를 포함하자

  1. 테스트되는 method 이름
  2. 테스트되는 시나리오
  3. 시나리오가 살행될 때 기대되는 행동
// - Add : method name
// - SingleNumger: 테스트 시나리오
// - ReturnsSameNumber : expected behavior

public void Add_SingleNumber_ReturnsSameNumber(){
    ...
}

2. 테스트를 잘 배열하자.

일반적으로 unit test 가 Arrange, Act, Assert 로 진행된다. 이것을 명확히 읽을 수 있게 해주자. 테스트를 가능한 잘 읽을 수 있도록 해주자. Arrange, Assert 로 부터 무엇을 테스트하려는 것인지가 명확히 확인할 수 있도록 해줘야 한다.

3. 최소한의 통과하는 테스트를 작성하자.

테스트 코드작성시에는 동작(behavior)에 초점을 두자.

테스트하려는 동작을 증명하기 위해 최대한 간소하게 작성하자. model 의 properties 중 “테스트와 관련없는 property를 set 하는 것”이나 필요치 않은 “non-zero 값을 사용하는 것”들은 테스트하려는 것들에 대한 집중을 흐트러뜨릴 뿐이다.

non-zero 값을 사용하는 것 이것은 일반적으로 어떤 값을 넣어도 되는 테스트일때 굳이 이상한 값을 넣어서 왜 이런 값을 넣었는지 궁금하게 만들필요가 없다는 뜻 인듯 하다.

4. 특정의미가 있는 문자열을(magic string)을 쓰지말자.

unit test 에서 변수명을 짓는 것도 중요하다.

이 테스트로 무엇을 달성하려고 하는지 보다 ’무엇을 증명하려는지’를 명확하게 보여줘야 한다. 되도록 test code 를 읽는 사람이 이 값이 무슨 뜻인지 알기 위해 원본 source code 를 보지않아도 이해할 수 있도록 해줘야 한다.

만약 특정 문자열을 사용해야 하는 경우라면, 아래처럼 변수명을 정해주고 사용하자.

void Add_MaximumSumResult_ThrowsOverflowException()
{
    var stringCalculator = new StringCalculator();
    const string MAXIMUM_RESULT = "1001";

    Action actual = () => stringCalculator.Add(MAXIMUM_RESULT);

    Assert.Throws<OverflowException>(actual);
}

5. 테스트 안에서 logic 을 피하자.

수동으로 string 을 묶거나, 논리적인 조건들(if, while, for, switch) 을 피하자.

이것으로 테스트 코드에서 버그의 발생을 줄일 수 있다. 그것의 구현의 세부사항보다는 결과에 집중하자.

테스트가 실패했다는 것이 실제로 code 가 뭔가 이상하다는 것을 알려줘야 한다.(me: 테스트가 코드의 logic 을 잘 테스트해야 한다.는 뜻인듯.)

만약에 input 에 대한 결과값들을 여러번 테스트하고 싶다면, 이것을 for 문으로 만들어서 테스트하지 말고, 여러개의 테스트로 분리해서 테스트하자.

6. setup, teardown 보다는 helper method 를 선호하자.

  • helper method 가 가독성을 높여준다. setup/teardown 은 test code 내에 보이지 않지만 helper method 는 보인다.
  • 너무 많은 것은 setup 하거니, 너무 적게 setup 하지 않게 된다.
  • test 사이에 state 를 공유할 확률이 적다. state 를 공유하는 것은 그 test 사이에 원치않는 dependencies 를 만들게 된다.

7. 여러개의 assert 는 피하자.

1개의 assert 가 실패하면 그 뒤의 assert 도 같이 실패해 버린다.(me: 이것은 자동으로 계속 돌아야 하는 경우 안좋다. 전부테스트하고 틀린것들을 찾아내야 하는데, 하나가 실패해서 다른 것들을 전혀 테스트 안하게 된다.)

8. private method 들은 public method 들을 테스트하는 것으로 검증하자.

  • private method 는 public method 의 자세한 구현이기 때문에 public method 를 test 하면 private 도 같이 테스트된다.
  • me : private method 는 refacotring 등을 하면서 구조적으로 자주 변경될 수 있다.

9. static 참고들을 Stub 하자.

production code 가 static references 들(에를 들면 DateTime.Now 같은 함수들)을 이용하면, 테스트하기 힘들다. 이럴 때는 이 부분을 외부에서 parameter 로 넘겨서 받도로 한다. 그래서 stub 을 만들어서 넘기면 된다.

public int GetDiscountedPrice(int price)
{
    if (DateTime.Now.DayOfWeek == DayOfWeek.Tuesday)
    {
        return price / 2;
    }
    else
    {
        return price;
    }
}
public interface IDateTimeProvider
{
    DayOfWeek DayOfWeek();
}

public int GetDiscountedPrice(int price, IDateTimeProvider dateTimeProvider)
{
    if (dateTimeProvider.DayOfWeek() == DayOfWeek.Tuesday)
    {
        return price / 2;
    }
    else
    {
        return price;
    }
}

Reference

  1. Best practices for writing unit tests - .NET | Microsoft Docs
  2. 단위 테스트 작성에 대한 모범 사례 - .NET | Microsoft Docs, ref.1 의 한글버전

[컴][os] io_uring

 

io_uring

io_uring 은 linux 에 새로운 ‘비동기 I/O API’ 이다. Facebook 에 근무하는 Jens Axboe 가 만들었다고 한다. performance overhead 가 작은, 성능이 좋은 i/o 라고 한다.[ref. 1]

이전에 linux 의 ’비동기 I/O API’들

  • select
  • poll
  • epoll
  • aio

이름에 ring 이 들어간것 처럼 io_uring는 ’kernel space와 user space 통신’을 위해서 ring buffer 들을 main interface 로 을 사용한다고 한다. 이 io_uring 도 system call 들을 사용하지만 이것을 최소한으로 유지하고 있다. 그리고 사용자가 직접 polling mode 를 사용해서 system calls 의 사용량을 최대한으로 줄일 수 있다.[ref. 1]

Reference

  1. What is io_uring? — Lord of the io_uring documentation

[컴] Vuejs를 ReactJS 관점에서 비교

 vuejs vs reactjs / reactjs

Vuejs를 ReactJS 관점에서 비교

props

react 의 props 은 vuejs 에서도 props 이다.

state

react 의 state 에 해당하는 것이 vuejs 에서는 data 이다.

하지만 한가지 주의할 점은 data: function(){} 의 호출은 create 시점에만 호출된다는 점이다. 그래서 그 이후에 호출을 하게 하려면 vue component lifecycle 에 맞춰서 호출을 해야 한다.(update 시점등에서)

처음에는 vuejs 가 property 가 변하면(set) 알아서 render 를 호출한다고 이야기했기 때문에 data: function({}) 도 그 안의 property 가 변경되면 다시 호출될 것이라 생각했다. 하지만 data: function({}) 는 위에서 이야기 했듯이 component 가 생성되는 시점에 한번만 호출된다. 아래 예시를 확인하면, 좀 더 이해가 쉬울 것이다.

setState

react 에서는 state 를 변경하기 위해 setState() 를 호출해야 한다. 이 것을 호출하면, 그에 따라 render 가 다시 호출된다. vuejs 에서는 이 부분을 getter setter 를 갖는 property 를 사용해 해결한다. 간단히 이야기하면, 그냥 정의된 값이 변경되면, 알아서 render 를 호출한다.

그래서 주의해야할 점은 자신이 render 를 호출했는지를 확인하기가 좀 까다롭다. 그래서 값을 변경했을때, 화면을 render 해주는지 안해주는지를 확인하려면, 이 값이 propsdata 에 정의되어 있는 값을 변경하는지에 대한 판단이 필요하다.

non reactive property

위에서 처럼 정의하는 대부분의 property 를 알아서 reactive 하게 만들기 때문에 반대로 non-reactive property 를 만들기가 어렵다. 일단 위에서 제시한 방법을 사용하면 될 듯 하다. 

render()

vuejs 에서는 render 함수를 따로 쓸 수도 있지만, 아래 예시처럼 <template> tag 를 사용할 수도 있다. 그래서 간단히 이야기하면, <template> 이 곧 render 라고 생각하면 된다. 그래서 만약 react에서 props 이 변경되거나 setState 가 변경됐을 때 render 가 호출된다면, vuejs 에서는 template 을 다시 호출한다고 보면 된다.

개인적으로 이 template 이 좋지 않은건, browser debugger 에서 file 이 다른 부분과 분리되어서 다른 file 로 보여진다. 그래서 불편하다.

input, checkbox

기본적으로 react 에서는 state 또는 prop 을 변경시켜야 해당하는 element 의 상태가 변한다. 하지만 vuejs 은 이것을 그냥 둔다. 그래서 input 이나 checkbox 의 모습이 변했다고 해서 그것이 rendering 이 호출됐다고 볼 수 없다.

props.children

reactjs 에서는 props.children 를 사용할 수 있는데 그것을 vuejs 에서는 slot 이라는 이름으로 표현한다.



예시

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <my-template :msg="mymsg" />
    <button @click="onClick">change the text</button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import MyTemplate from "./MyTemplate.vue";

export default Vue.extend({
  name: "Home",
  components: {
    MyTemplate,
  },
  data: function(){
    return {
      mymsg: "this is my message",
    }
  },
  methods: {
    onClick() {
      this.mymsg = "this is my message 2"
    },
  },
});
</script>
<template>
  <div class="">
    <h1>{{ msg }}</h1>
    <h1>{{ mystateMsg }}</h1>
    
  </div>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
  name: "MyTemplate",
  props: {
    msg: String,
  },
  data: function () {
    return {
      mystateMsg: this.msg
    };
  },
});
</script>

[컴][네트워크] 2020월 12월 14일 구글의 서비스의 접속 에러 원인

 장애 / 중단 / 구글 중단 / outage

2020월 12월 14일 구글의 서비스의 접속 에러 원인

2020월 12월 14일 47분 가량 구글 서비스가 접속이 안됐다. 그 원인에 대한 설명이 Google Cloud Status Dashboard 에 올라와서 번역을 해 봤다.


Google User ID Service 가 하는 일

  • 모든 계정에 대해서 unique 한 id 를 가지고 있다. 
  • OAuth token 들과 cookie 들을 위한 접속자격 증명서(authentication credentials) 을 다룬다.
  • 계정관련 data(account data) 를 분산된 db 에 저장한다. 이 분산db 는 update 의 동기화등을 위해서 Paxos protocol 을 사용한다.
  • 보안을 위해서 이 서비스는 outdated data 를 발견하면 requests 를 거부한다.

구글은 서비스들에 할당(allocate) 된 다양한 resource 들의 몫(quota)을 관리하는데 자동화툴을 사용한다.

User ID Service 은 새로운 quota system 으로 migration 이 진행되고 있다.

"quota 제한"을 집행하는 것에 대한 "기존의 유예기간(grace period)"은 이 이슈가 발생하는 것을 지연시켰다. 그리고 그것은 결국 유예기간이 종료됐고, 자동화된 quota system 들이 User ID service에게 허락된 quota 를 감소시키는 것을 시작하게 했고 이 사건을 일으켰다.

기존의 safety checks 은 많은 의도되지 않은 quota 변경들을 막기 위해 존재하지만 "하나의 service 에 대한 0으로 보고된 부하(zero reported load for a single service)"의 시나리오에 대해서는 커버하지 않았다.

  • Quota changes to large number of users: since only a single group was the target of the change
  • Lowering quota below usage, since the reported usage was inaccurately being reported as zero
  • Excessive quota reduction to storage systems, since no alert fired during the grace period
  • Low quota, since the difference between usage and quota exceeded the protection limit.

결과적으로, account database 의 quota 가 줄어들었고 그것이 Paxos leader 가 writing 하는 것을 막았다. 바로 그 후에 read operations 의 많은 수가 outdated 가 되었고 이것이 authentication lookups에 대한 error를 만들었다.

Reference

  1. Google Cloud Infrastructure Components Incident #20013 | Google Cloud Status Dashboard

[컴] MIMO (multiple-input and multiple-output)

미모 / 원리 /마이모 /


MIMO (multiple-input and multiple-output)

기지국과 단말기에 “여러 안테나”를 사용하는 것이다.

여러개의 안테나가 왜 필요하냐면, 다음 2가지 이유로 필요하다.

  1. 같은 주파수 대역을 여러번 사용하기 위해서
    • 같은 주파수 대역의 정보를 여러 안테나를 이용해서 병렬로 보내서 대역폭을 늘리는 효과를 가져가는 것
  2. 여러 주파수 대역을 사용하기 위해서
    • 여러 주파수 대역을 이용해서 같은 정보를 보내서 간섭등으로 인해 지연되거나 유실되는 부분을 버리거, 빠르게 도착하는 녀석을 사용하는것

Reference

  1. MIMO - 위키백과, 우리 모두의 백과사전
  2. MIMO - Wikipedia

[컴][웹] dns server 동작 방식

 도메인 네임 서버 / domain name server / dns resolver

dns server 동작 방식

DNS serverprocess procedure

from: https://www.youtube.com/watch?v=vrxwXXytEuI
from : http://technet.microsoft.com/en-us/library/cc728065(v=ws.10).aspx

대략적으로 얘기를 하자면, lower lever DNS Server 가 모든 자료를 가지고 있지 않기 때문에 client(web browser 라고 생각하면 된다.) 에서 자신이 가지고 있지 않은 domain 에 대한 request 가 올 수도 있다.

보통 client 에서 요청하는 URL 의 ip address 정보는 local pc 의 dns(c:\>ipconfig /displaydns 통해서 확인할 수 있다.) 에서 알 수 있거나, ISP 의 DNS 서버가 caching 해 놓은 정보를 통해 빠르게 응답을 받을 수 있다. 하지만, client 에 설정되어 있는 가장 최초의 DNS server 에 정보가 없을 때는 어떻게 할까?

이 때에는 root dns server 에 요청을 하게 된다. DNS(Domain Name Service) 는 가장 최상단에 13개 정도의 Root DNS server 를 갖는다. 이 root dns server 에 요청하면, 요청한 domain 에 대한 알맞은 server 의 정보를 준다. (위의 그림의 Preferred DNS server) 가 또 다른 DNS Server 에게 묻게 된다. 이런 식으로 아는 녀석이 나올때까지 계속 다른 server 에게 물어서 답(ip address)을 얻고 이것을 다시 client 에게 보내 주고, 자신의 이 값을 caching 해 놓게 된다.

그럼 client 는 어떻게 최초의 lower lever DNS server 를 알 수 있을까? static 으로 컴퓨터에 IP address 를 set 해줄 때 dns server 의 ip 도 같이 set 해주게 되어있다. 그렇기 때문에 client 컴퓨터가 자동으로 ip-address 할당 받을 때 set 된다고 생각하면 된다.

참고로, DNS server 에 url 에 대한 ip-address 에 대한 요청은 OS 가 하게 된다.

ipconfig /displaydns

/displaydns      DNS 확인 프로그램 캐시 내용을 표시한다.

이해를 돕는 자료

여기 알기쉬운 자료가 있다. 한번 봐 보자.

  1. How Internet Works · Vladstudio
  2. How DNS Works Visually - YouTube, 2020-12-27 : 영상으로 설명해 준다.

See Also

  1. DNS 가 어떤 절차를 거치는 가에 대한 설명 : http://compnetworking.about.com/od/dns_domainnamesystem/f/dns_servers.htm
  2. DNS 에 관한 개략적인 설명: http://webdesign.about.com/od/domains/g/bldefdns.htm
  3. name server 를 찾는 명령어
    • nslookup
    • whois www.daum.net

[컴][nodejs] function parameter vs class parameter

 

function parameter or class parameter

function 을 넘기고, 넘겨받은 function 을 execute 하는 javascript 코드가 아래에 있다. 이 코드를 만약 oop 의 모습으로 구현하는 것이 나을까 아니면 그냥 아래 처럼 function 으로 두는 것이 나을까.

function 을 parameter 로 넘기는 code

function myCallback(param1){
    return 1;   
}

function do(callback){
    callback(1000);
}

// run
do(myCallback)

oop 모양으로 구현

class 를 이용해서 new 를 하게 되는 순간 하게 되는 일들이 있다. (참고: [컴][웹][자바스크립트] proto 와 prototype --> constructor) 그래서 javascript 에서는 직접적으로 function 을 넘겨서 실행하는 것이 더 효율적이긴 하다.

class Callback{
    ...
    run(param1){
        return 1;
    }   
}

function do(callbackClass){
    const obj = new callbackClass()
    obj.run(1000)
}

do(Callback)

instantiate 를 먼저하고 parameter 로 넘기는 것

class Callback{
    ...
    run(param1){
        return 1;
    }   
}

function do(callbackObj){
    callbackObj.run(1000)
}

do(new Callback())
function Callback(){
    ...
    this.run() = function(param1){
        return 1;
    }
}

function do(callbackClass){

    callbackObj.run(1000)
}

do(new Callback())


결론

이것은 js 에서는 class 가 결국 function 이기 때문에, function 을 이용하는 것이 유리해 보인다. 이유는 function 은 new operator 를 굳이 사용하지 않아도 되기 때문이다. new 를 사용하면 js 에서 수행하는 동작이 있는데, 이것을 하지 않아도 되기 때문에 속도면에서 memory 면에서 아주 조금 유리해 보인다.

Reference

  1. [컴][웹][자바스크립트] proto 와 prototype --> constructor

[컴][웹] V8엔진의 TurboFan



작성중 ...

CrankShaft JIT --> TurboFan JIT
layer 를 추가했다.


ref. 1 에 보면 turbofan 의 절차를 확인할 수 있다.
  1. Function Body Decoder
  2. Graph Construction (SSA)
  3. Optimization
  4. Scheduling
  5. Instuction Selection
  6. Register Allocation
  7. Code Generation
ref. 2 에서 TurboFan 에 대한 글들을 확인할 수 있다.


출처: An overview of the TurboFan compiler


출처: An overview of the TurboFan compiler



See Also

  1. TurboFan JIT Design : TurboFan TechTalk presentation
  2. TurboFan: A new code generation architecture for V8
  3. V8 관련 글들



References

  1. V8 JavaScript Engine: Liftoff: a new baseline compiler for WebAssembly in V8
  2. TurboFan · v8/v8 Wiki · GitHub
  3. An overview of the TurboFan compiler

[컴][알고리즘] BFS breadth-first search

너비 우선 탐색 / bfs /









BFS breadth-first search

vertex s 에서 출발한다.

s 의 adj 는 A, B 이니,
먼저, A 가 level 에 있는지 본다.
A가 level 에 없으니 A에 대한 level (level['A']) 를 set 한다.
그 다음 B 가 level 에 있는지 본다.
B도 level 에 없으니 B에 대한 level (level['B']) 를 set 한다.
그리고 방문했던 A, B는 next 에 저장해 놓는다.
그래서 그 다음에 loop 을 돌 frontier 를 만들게 된다.

frontier 의 각 adj vertex 들을 접근하면서,
각 vertex 가 방문했는지를 level 이 채워져 있는지로 확인한다.
이미 방문한 애들은 그냥 skip 한다.

prarent 는 각 vertex 가 어디서 부터 왔는지를 저장한다. 이것을 거꾸로 하면, path 가 된다.

level = {}
parent = {}

def bfs(s, adj):
    level = {"s": 0}
    parent = {"s": None}
    i = 1
    frontier = [s] # level i-1
    while frontier:
        next = [] # level i
        for u in frontier:
            for v in adj[u]:
                if v not in level:
                    level[v] = i
                    parent[v] = u
                    next.append(v)
        frontier = next
        i += 1     
이 bfs 를 한번 돌리면, 연결된 "하나의 연결된 그래프"의 vertex 들을 전부 visit 하게 된다. 그리고 현재의 연결된 그래프와 연결되지 않은, 나머지 vertex 의 방문을 위해서는 bfs 를 다시 실행해야 한다.

See Also

  1. [컴][알고리즘] Depth-First Search DFS, 깊이우선 탐색

References

  1. 13. Breadth-First Search (BFS) - YouTube


[컴][안드로이드] adb 동작

안드로이드 / android / adb how to work /

adb 동작


from : https://www.slideshare.net/tetsu.koba/adbandroid-debug-bridge-how-it-works

  1. adb client 를 실행하면,
  2. client 는 먼저 실행되고 있는 adb server process가 있는지 확인한다.
  3. 없으면 server process 를 시작한다.
  4. server가 시작되면, server 는 local TCP port 5037 에 bind 해서, adb client 에서 보내는 명령을 받을 준비를 한다.
  5. 모든 adb client 는 adb server 와의 통신을 위해 5037 port 를 사용한다.
  6. 서버는 그러고 난후에, 모든 실행되고 있는 기기(devices) 과 connection 들을 설정한다.(set up)
  7. 서버는 "5555~5585 사이의 홀수로 된 port 들"을 scanning 해서, emulator 가 어디있는지를 찾는다.
    • "5555~5585 사이의 홀수로 된 port 들" 은 첫 16개의 emulator 들이 사용하게 된다.
  8. 서버가 scanning 한 port 중에서 adbd(adb 데몬, target phone 에 있다.)을 찾으면, 그 port 와 connection 을 set up한다.
  9. 각 emulator 는 한쌍의 port 를 사용한다.
    • console connection 을 위해 짝수번 port
    • adb connection 을 위해 홀수번 port
Emulator 1, console: 5554
Emulator 1, adb: 5555
Emulator 2, console: 5556
Emulator 2, adb: 5557
and so on...
  1. emulator 가 port 5555 를 통해 adb 에 연결됐으면, emulator 의 console 은 5554 port 에서 listen (수신대기)하고 있는 것이다.
  2. 서버가 모든 기기들과 connection 을 맺으면,
  3. 그 기기들에 대해서 adb command 를 사용할 수 있다.
  • 서버는 device 에 대한 연결을 관리하고, 여러 adb client 로 부터 오는 command 들을 handle 한다. 그래서 특정 device 를 control 하기 위해 특정 client 를 사용할 필요는 없다.

from : https://www.slideshare.net/tetsu.koba/adbandroid-debug-bridge-how-it-works

Reference

  1. Android Debug Bridge (adb) | Android Developers
  2. ADB(Android Debug Bridge): How it works?

[컴] Head-Of-Line blocking

네트워크 / 이더넷 /

HOL blocking

from: https://en.wikipedia.org/wiki/Head-of-line_blocking#/media/File:HOL_blocking.png

switch 에 여러개의 input queue 가 있고, input queue 들로 들어오는 packet 들은 어떤 output 으로 갈지 정해져 있다. 이런 구조에서 1번 input queue 에서 output 4로 가려는 packet 이 들어왔고, 3번 input queue 에도 output 4 로 가려는 packet 이 들어왔다고 해보자.

그리고 이것들이 동시에 처리되는 시점에 있다고 하자. 그러면, 둘 다 4번 output 으로 보내야 하지만, output 은 한번에 1개밖에 보낼 수 없다. 그래서 1번이나 3번 input queue 중에 선택을 해야 한다.

그래서 만약 3번을 택했다면, 1번 input queue 는 자신의 packet(4번으로 가려는) 을 "3번 input queue 의 packet" 이 처리된 후에 처리해야만 한다.

그렇게 되면 어쩔 수 없이, 이번 clock 에는 아무런 일도 할 수 없다. 그냥 쉬게 된다.

이런식으로 block 이 되는 것이 Head-Of-Line blocking 이다. 당연히 이로 인해 처리능력이 줄어들게 된다. 그래서 이를 해결하기 위한 방법중 하나로 Virtual output queueing 이 쓰인다고 한다.

Reference

  1. Head-of-line blocking - Wikipedia
  2. [RE] Head of Line Blocking Prevention(HOL)이란? | NETMANIAS

[컴][네트워크] 라우팅 프로토콜

routing protocol / router / 라우팅 프로토콜  / 어떻게 패킷이 가는가 / 네트워크 알고리즘


라우팅 프로토콜

routing protocol은 3가지 형식으로 분류할 수 있다.
  1. routing table 을 누가 만드느냐에 따라 분류
  2. 내부 network에서 routing을 담당하느냐에 따른 분류
  3. routing table을 어떻게 만드느냐에 따른 분류

routing table 을 누가 만드느냐에 따라 분류

스태틱 라우팅 프로토콜(static routing protocol)

  • 사람이 직접 손으로 routing table(라우팅 테이블)을 만드는 것이다.
  • 경로에 문제가 발생하면, 다시 사람이 고쳐주지 않는 한 문제를 해결하지 못한다.

다이나믹 라우팅 프로토콜(dynamic routing protocol)

  • 라우터가 알아서 routing table을 만들어 준다.
  • 경로 이상 시 알아서 다른 경로를 설정할 수 있다.
  • 하지만 라우터의 부담이 가중된다.
  • RIP, IGRP, OSPF, EIGRP 등이 있다.

내부 network에서 routing 을 담당하느냐에 따라

  • IGP(Interior Gateway Protocol)
  • EGP(Exterior Gateway Protocol) 로 나눌 수 있다.
같은 관리자의 관리 하에 있는 라우터의 집합을 AS(Autonomous System)라고 하는데,
Autonomous System 내에서 사용되는 router 의 protocol 이 IGP이다. RIP, IGRP, EIGRP, OSPF 이 여기에 속한다.
그리고 AS와 다른 AS 사이에서 사용되는 router의 protocol이 EGP이다. BGP, EGP 이 여기에 속한다.


routing table을 어떻게 관리하는 가에 따라

  • 디스턴스 벡터 알고리즘(Distance Vector Algorithm)을 사용하는 프로토콜,
  • 링크 스테이트 알고리즘(Ling State Algorithm)을 사용하는 프로토콜
DVA 는 routing table 에 목적지까지 가는데 필요한 거리와 방향만을 기록. RIP와 IGRP가 대표적이다
LSA 는 라우터가 목적지까지 가는 경로를 SPF(Shortest-Path-First) 알고리즘이란 것을 통해 routing table에 기록. OSPF가 대표적이다.