(Garbage Collection) Old Area의 Concurrent Mark-sweep 알고리즘

Initial Mark Phase : 싱글 쓰레드에서만 사용한다. 애플리케이션이 중지되고 애플리케이션에서 직접 Reference(Root set에서 한 단계의 Reference관계)되는 Live Object 만 구별한다. Suspend 상태지만 빠르다. Concurrent Mark Phase 단계 : 싱글 쓰레드에서만 사용한다. 애플리케이션은 수행되고, GC Thread외 Working Thread는 애플리케이션 수행이 가능하다. Initial Mark Phase에서 선별된 Live Object가 Reference하고 있는 object를 추적해 Live여부를 구별한다. Remark Phase 단계: 멀티 쓰레드가 사용되며 애플리케이션이 중지된다. 이미 Marking된 오브젝트를 다시 추적, Live 여부 확정, 모든  Resource를 투입한다. Concurrent Sweep Phase 단계 : 싱글쓰레드만 사용한다. 애플리케이션은 수행되고 최종 Live로 판명된 오브젝트를 제외한 Dead Object를 지운다. 단, sweep 작업만하고 Compaction작업은 수행 안한다.항상 Compaction은 Heap의 Suspend를 전제로 하는데 반복된 Sweep은 단편화를 유발한다. 때문에 Free List를 사용하여 단편화를 줄이는 노력을 한다.

(Pytorch) DataLoder 클래스

DataLoader클래스란? 데이터를 배치로 만드는 작업을 돕는 유틸 클래스로, 배치 데이터를 만드는 여러한 복잡한 작업을 추상화 한다. 해당 클래스는 파이토치의 utils 모듈에 위치한다. 또한 tochvision과 torchtext를 제공한다. 이 두 클래스는 이미지 분석과 자연어 처리를 다룰 때 사용한다.

(Docker) 도커 컨테이너의 네트워킹 스택 관리하기

이미지
도커 컨테이너마다 자체적으로 네트워크 스택을 갖추고 있다. 이는 리눅스 커널의 네트워크 네임스페이스를 통해 제공되는 곳으로, 컨테이너 마다 net 네임스페이스에 대한 인스턴스가 새로 생성되기 때문에 다른 컨테이너나 외부에는 드러나지 않고 해당 컨테이너 내부에서만 사용된다. 1. docker0 브릿지 docker0 브릿지는 도커 네트워킹에서 가장 기본적인 기능을 제공한다. 도커서비스가 구동할 때마다 호스트 머신에 리눅스 브릿지가 생성된다. 이렇게 생성된 브릿지는 컨테이너의 인터페이스를 통해 통신하며, 외부에 대한 프록시 역할도 한다.  한 호스트에서 구동하는 여러 컨테이너는 리눅스 브릿지를 통해 서로 통신한다. docker0는 네가지 모드를 제공하며, 다음과 같이 --net 플래그를 통해 설정한다. --net=default: 컨테이너 끼리 연결하기 위한 브릿지로 디폴트 브릿지를 사용한다. --net=nonde: 컨테이너를 완전히 격리된 형태로 구동하며 네트워크에 연결하지 않는다. --net=container:$container2: $container2라는 이름의 컨테이너에서 사용하는 네트워크 네임스페이스를 공유하도록 컨테이너를 생성한다. 1-1. 도커 브릿지 설정 관련 문제의 해결 방법 컨테이너 포트를 호스트의 포트와 매핑하는 방법을 살펴보고, 컨테이너를 외부와 연결할 때 발생할 수 있는 문제를 보자 두 컨테이너 모두 상대방에게 핑(ping)을 보낼 수 있을 뿐만 아니라 외부 네트워크에도 연결 할 수 있다. 외부와 연결하기 위해서는 컨테이너의 포트를 호스트의 포트와 매핑해야 한다. 앞서 설명한 바와 같이 컨테이너마다 네트워크 네임스페이스를 갖고 있다. 컨테이너가 생성될 때, 그 컨테이너에 대한 네트워크 네임스페이스도 새로 생성된다. 컨테이너와 리눅스 브릿지는 가상 이더넷(Virtual Ethernet)=veth 링크를 통해 연결한다. 컨테이너의 eth0 포트...

(Redis)레디스 운영 시 고려사항

1. 메모리 크기 레디스는 메모리에 데이터를 저장하기 때문에 레디스가 사용할 메모리의 크기를 지정하는것은 성능과 가장 밀접한 관련이 있다. 실제로 저장되는 데이터의 크기는 redisObject와 키가 저장된 크기를 뺀 나머지가 된다. 저장되는 데이터가 작은 크기의 문자열이라면 redisObject를 저장하기 위한 오버헤드가 더 크게 된다. 이럴 떄는 문자열을 숫자로 바꾸어 저장하거나, 다른 데이터형을 사용하면 더 많은 데이터를 저장할 수 있다. 만약 레디스에 저장될 데이터의 크기를 산정하지 못하여 redis.conf와 maxmemory 설정에 값을 지정할 수 없게 되었다고 하자. 그러면 레디스에 데이터가 계속 추가되어 물리 메모리를 모두 사용하게 된다. 이때 운영체제에서는 애플리케이션이 시스템에서 사용 가능한 물리 메모리 보다 더 많은 메모리를 사용하려고 할 때 스왑이라는 가상 메모리 공간을 하드디스크에 생성하여 사용하는데, 이 영역을 스왑공간이라 부른다. 이떄 스왑 공간이 충분하지 않으면 운영체제는 메모리에서 동작 중인 프로세스를 제거하여 사용가능한 메모리의 영역을 확보하게 된다. 이와 같이 동작 중인 프로세스를 죽이는 리눅스의 프로그램을  OOM킬러라고한다. 그러므로 OOM킬러를 피하려면 충분한 스왑공간을 확보해야한다. 그런데 데이터가 저장되기 시작하면 레디스의 응답시간은 수십 배에서 수백 배까지 늘어나게 된다. 만약 응답시간이 중요한 서비스라면 반드시 redis.conf의 maxmemory 설정에 설치된 물리 메모리 크기 이내의 값을 지정하여야 한다. 일반적으로 운영체제는 설치된 메모리 크기의 두 배를 스왑공간으로 할당한다. 여기서 말하는 두 배는 메모리가 충분하지 못했던 과거의 기준이다. 메모리의 가격이 저렴해지고 엔트리급 서버 시스템이 16GB이상의 메모리를 갖는 지금은 기준이 조금 달라졌다. 레드햇 엔터프라이즈의 가상 메모리 설정 가이드 문서에 따르면 시스템에 설치된 물리 메모리의 크기에 따라서 다른 값을 ...

(Redis) 레디스의 확장과 분산기법

레디스에 스케일 아웃을 처리하기 위한 방법으로 두 가지 기법을 제공한다. 읽기분산을 위한 복제(Replication)와 쓰기 분산을 위한 샤딩(Sharding)이 이에 해당된다. 1. 복제 복제는 동일한 데이터를 다중의 노드에 중복하여 저장하는 것을 말한다. 레디스는 복제를 위해 마스터와 슬레이브의 복제의 개념을 사용한다. 마스터는 복제를 위한 데이터의 원본 역할을 한다. 슬레이브는 마스터 노드에 데이터 복제 요청을 하고 데이터를 수신하여 데이터를 동기화 한다. 통상적으로 레디스 인스턴스 하나가 처리할 수 있는 TPS는 1만~2만이다. 또한 대부분의 레디스 명령은 읽기와 쓰기에 따른 성능편차가 없다. 복제는 슬레이브 노드가 마스터 노드의 데이터를 실시간으로 복제하여 데이터의 동기화를 유지한다. 슬레이브 노드가 시작할 때 마스터 노드에게 복제를 요청하고 최초 복제가 완료된 이후는 변경 사항만 업데이트 한다. 레디스의 복제는 마스터노드가 슬레이브노드의 정보를 가지지 않고, 슬레이브 노드가 마스터 노드의 위치만 알고있으면 복제를 할 수 있다. 1-1. 단일 복제 마스터노드와 슬레이브 노드 하나로 구성된다. 마스터 노드에 변경이 발생하면 실시간으로 슬레이브 노드에 데이터 변경사항이 기록된다. 하지만 슬레이브 노드에 변경이 발생하면 마스터 노드는 해당 변경 사항을 감지하지 못한다. 슬레이브 노드에서 데이터 변경이 일어나는 순간 데이터의 정합성이 무너지게 되므로 슬레이브 노드에서는 데이터의 변경을 수행하지 않아야 한다. 1-2. 다중 복제 단일 복제만으로는 필요한 읽기 성능을 만족하지 못할때 다중 복제를 고려할 수 있다. 단일 복제 구조의 클러스터에 슬레이브 노드를 추가하기 위해서는 마스터 노드의 위치정보를 슬레이브 노드에 설정하고 인스턴스를 실행하면 노드 추가가 완료된다. 이와 같이 단일 복제 상태에서 여러 대의 슬레이브 노드를 추가한 것을 다중 복제라고 한다. 마스터 노드의 재시작이 필요하지 않다. ...

(스프링) Ioc컨테이너와 DI

이미지
<IOC 컨테이너를 통해 애플리케이션이 만들어지는 방식> 결국 스프링 애플리케이션이란, POJO클래스와 설정 메타정보를 이용해 IOC 컨테이너가 만들어주는 오브젝트의 조합이다. RootBeanDefinition을 보면 bean클래스가 private volatile Object beanClass; 로 되어있는 것을 볼 수 있다. 이는 volatile을 선언하게 되면 cpu cache에 해당 값을 저장하는 과정 없이 오직  MainMemory에서 값을 읽고, 쓰는 과정을 거친다. 즉, 멀티쓰레드에서 한개의 쓰레드가 read&write를 하더라도 다른 쓰레드에서 읽기를 하는 경우 값이 변하더라도 항상 일관된 값을 유지하게 해준다.

(Effective Java) 익명 클래스보다는 람다를 사용하라_람다와 스트림

이미지
람다를 왜 JDK 1.1에서는 함수객체를 만드는 주요 수단은 익명 클래스였다. 그러나 익명클래스 방식은 코드가 너무 길어 자바는 함수형 프로그래밍에 적합하지 않았다. 결국 이러한 문제로 이를 람다로 교체됨 (더욱 간결하게 표현할 수 있음) 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다. 람다는 한 줄일때 가장 좋고 길어야 세 줄안에 끝내는게 가장 좋다. 세 줄을 넘어가면 가독성이 심하게 나빠진다. 람다의 시대가 열리며 익명클래스 -> 람다로 대체 되었지만, 람다는 함수형 인터페이스에서만 쓰인다. 예컨대 추상클래스의 인스턴스를 만들 때 람다를 쓸 수 없으니, 익명 클래스를 써여한다. 마지막으로 람다는 자신을 참조할 수 없다. this키워드는 바깥 인스턴스를 가르킨다. 람다를 직렬화하는 일은 극히 삼가야한다. 정리: 함수객체를 구현하기 위해 익명클래스를 도입, 그러나 코드가 길어지는 단점이 존재하여 이를 람다로 대체하기 시작함 그러나 람다를 사용하지 못하는 경우가 있는데 1. 자기 자신을 참조하는 this를 사용하는 경우 2. 코드길이가 너무 길어지는 경우 오히려 문서화를 할 수 없음 3. 직렬화를 하는 경우는 삼가야 한다.

(Docker) Elastic, logstash, kibana(Docker-compose)

version: '2.2' services:   elasticsearch:     image: docker.elastic.co/elasticsearch/elasticsearch:6.2.1     container_name: elasticsearch     hostname: elasticsearch     environment:       - cluster.name=docker-cluster       - bootstrap.memory_lock=true       - "ES_JAVA_OPTS=-Xms512m -Xmx512m"     ulimits:       memlock:         soft: -1         hard: -1     volumes:       - esdata1:/usr/share/elasticsearch/data     ports:       - 9200:9200     logstash:     image: docker.elastic.co/logstash/logstash:6.2.1     container_name: logstash     hostname: logstash     environment:       - "LS_JAVA_OPTS=-Xms512m -Xmx512m"     ports:       - 9600:9600     volumes: ...

(Kubernetes) StatefulSet(스테이트 풀 셋)

리플리카컨트롤러, 리플리케이션셋, 디플로이먼트는 모두 상태가 없는(stateless) 포드들을 관리하는 용도 였습니다. 스테이트풀셋(StatefulSets)은 단어의 의미 그대로 상태를 가지고 있는 포드들을 관리하는 컨트롤러 입니다. 스테이트풀셋을 사용하면 볼륨을 사용해서 특정 데이터를 기록해두고 그걸 포드가 재시작했을때도 유지할 수 있습니다. 여러개의 포드를 띄울때 포드 사이에 순서를 지정해서 지정된 순서대로 포드가  실행되게 할수도 있습니다. 이런식으로 어떠한 상태를 가지고 있어야 할때 사용하는게 스테이트풀 셋입니다.

(Kubernetes) Deployment vs Pod

둘의 차이는 Pod는 단순히 Pod만 생성하는 것이지만 Deployment는 Pod를 생성할 때, 실패하는 경우를 감시하고 만약 특정한 숫자 이상의 포드를 생성하라고 명령한 경우는 그 숫자가 될 때까지 지속적으로 pod를 생성하게한다.  If you don’t want a Deployment to monitor your pod (e.g. your pod is writing non-persistent data which won’t survive a restart, or your pod is intended to be very short-lived), you can create a pod directly with the create command.

(AWS) ElasticBeansTalk 로 도커 컨테이너 배포하기

1. Single Container인 경우 Dockerfile 을 생성하여 이미지를 사용자 지정하고 Docker 컨테이너를 Elastic Beanstalk에 배포합니다. Dockerrun.aws.json  파일을 생성하여 기존 Docker 이미지에서 Elastic Beanstalk으로 Docker 컨테이너를 배포합니다. 애플리케이션 파일, 모든 애플리케이션 파일 종속성,  Dockerfile  및  Dockerrun.aws.json  파일이 포함된  .zip 파일을 만듭니다.  Dockerfile  또는  Dockerrun.aws.json  파일만 사용하여 애플리케이션을 배포하는 경우 파일을 .zip 파일로 압축할 필요가 없습니다. 2. MultiContainer인 경우 docker-compose.yml 을 Dockerrun.aws.json 으로 변경한다. 이를 쉽게해주는 pip 라이브러리가 존재한다. (https://container-transform.readthedocs.io/en/latest/) ElasticbeansTalk 생성시 멀티 컨테이너로 옵션을 변경하여 생성한다. 그후 생성한 Dockerrun.aws.json파일을 업로드 한다. 업로드가 되더라도, 로그를 보게되면 에러로그가 있을 수 있다. 이는 외부에서 도커 컨테이너로 접속시 아이피 주소를 인식하지 못하는 경우이다. 이를 위해 다음과 같이 변경한다. localhost:9092 -> 생성한 (url):(port번호) (외부 접속시) 참고 사이트 : https://rmoff.net/2018/08/02/kafka-listeners-explained

(Docker) Docker compose 에서 ports와 expose의 차이

둘다 포트를 명시하지만 차이점이 존재한다. 만약 호스트(즉, 컨테이너 밖인 로컬)에서 해당 컨테이너로 접속하기 위해서는 ports에 해당값을 명시한다. Expose는 컨테이너 간의 포트를 바라볼때 사용한다.

(kafka) 장애 복구 정리

이미지
1. WAS -> Kafka (연결불가능) 이 경우 Producer(소셜엔진) 에서 카프카로 데이터 전송시 exception이 발생 이 exception을 소셜엔진엔서 callback을 이용해 실패로그로 저장하던지 MongoDB에 저장하여 실패 데이터를 기록 이와 같은 케이스는 다음과 같은 방법으로 실패를 처리할 수 있다 1) retries 옵션에 적당한 값을 설정해 실패 시 재시도 (엄청난 지연 발생가능) 2) 전송 실패시 발생하는 Exception을 catch에 큐에저장 후 다시 재전송 실패가 지속되면 카프카 문제로 판단해 실패로그를 저장 혹은 MongoDB 에 해당 데이터 저장 참고 : http://readme.skplanet.com/?p=13042 Scenario 1 - Fire-and-forget with a failed node and partition leader fail-over (acks=0) 이 케이스는 프로듀서에서 acknowledgements를 받지 않는다. 즉, 전송만 계속하는 것으로 만약 현재 카프카 호스트의 Leader 가 다운된다면 가정) 약 10만개 메시지 전송 중, 3만개 메시지 전송 중, 카프카 leader가 down되었을 때 새로운 leader를 선출하게된다. 이 텀동안 데이터 유실이 발생 약 6700여개 메시지 전송 실패 Scenario 2 - Acks=1 with a failed node and partition leader fail-over ack0=1인 경우, Leader노드가 fail된 경우. 이 케이스 또한 데이터 유실이 발생한다. 그러나 acks=0 인 경우보다 데이터 유실 발생이 더 적다. 테스트) 10만 메시지를 한개의 Producer에서 전송했을 때, 3만번쨰에서 Leader가 죽고, 새로운 Leader 가 선출되었을때, 약 5개의 데이터 손실 발생, 약 9만개 메시지는 Producer 에 응답함 ...

(Kafka) 카프카 스트림즈 아키텍처

이미지
카프카 스트림즈에 들어오는 데이터는 카프카 토픽 메시지이다. 스트림과 카프카 토픽의 관계는 다음과 같다. 각 스트림 파티션은 카프카의 토픽 파티션에 저장된 정렬된 메시지이다. 스트림 데이터 레코드는 카프카 해당 토픽의 메시지(키+값)이다. 데이터 레코드의 키를 통해 다음 스트림(=카프카 토픽) 으로 전달된다. 카프카 스트림즈는 입력 스트림의 파티션 개수만큼 태스크를 생성한다. 각 태스크에는 입력 스트림(즉 카프카 토픽) 파티션들이 할당되고, 이것은 한번 정해지면 입력 토픽의 파티션에 변화가 생기지 않는 한 변하지 않는다. 각 입력스트림으로 부터 할당받은 태스크 파티션은  변화하지 않는다. 머신이 중지되더라도, 해당 태스크가 재시작해야한다.  카프카 스트림즈는 사용자가 스레드의 개수를 지정할 수 있게 해주며, 1개의 스레드는 1개이상의 태스크를 처리할 수 있습니다. 다음 그림은 1개의 스레드에서 2개의 스트림 태스크가 수행되는 모습을 보여준다.

(Kafka) 카프카 스트림즈란?

이미지
카프카 스트림즈는 카프카에 저장된 데이터를 처리하고 분석하기 위해 개발된 클라이언트 라이브러리이다. 카프카 스트림즈는 이벤트 시간 과 처리 시간 을 분리해서 다루고 다양한 시간 간격 옵션을 지원하기에 실시간 분석을 간단하지만 효율적으로 진행할 수 있습니다. 카프카 스트림즈는 스파크 스트림이나 스톰과 같이 스트림 처리를 하는 프로세서들이 서로 연결되어 형상, 즉, 토폴로지를 만들어서 처리하는 API 이다.  스트림 : 끈임없이 전달되는 데이터 세트를 의미한다. 스트림에 기록하는 단위는 키-값 형태이다.  스트림 처리 애플리케이션 : 카프카 스트림 클라이언트를 사용하는 애플리케이션으로, 하나 이상의 프로세서 토폴로지에서 처리되는 로직을 의미한다. 프로세서 토폴로지는 스트림 프로세서가 서로 연결된 그래프를 의미한다. 스트림 프로세서 : 프로세서 토폴로지를 이루는 하나의 노드를 말하며, 노드들은 프로세서 형상에 의해 연결된 하나의 입력 스트림으로부터 데이터를 받아서 변환한 다음 다시 연결된 프로세서에 보내는 역할을 한다.

(엘라스틱 서치) FORBIDDEN/12/index read-only / allow delete 이슈

이미지
이유는 디스크 용량이 5%이하인 경우 자동으로 false처리하게 된다. 그러므로 두가지 방법이 있는데 첫 번째, elasticsearch.yml파일 안에 cluster.routing.allocation.disk.threshold_enabled: false 처리한다. 해당 인덱스 정보를 확인한 결과 GET activitylog-index/_settings read_only_allow_delete : true인 것을 볼 수 있다. 이를 해결하려면, PUT activitylog-index/_settings {   "index": {     "blocks" : {       "read_only_allow_delete": "false"     }   } }

(kafka) configued broker.id 1 doesn`t match store broker.id 0 이슈 문제 해결

한 호스트에서 여러 브로커를 생성하여 테스트 할 시 위와같은 에러가 발생할 수 있는데 이는 server-0.properties server-1.properties server-2.properties  각 파일에서 카프카가 저장시킬 로그 디렉토리를 분리해야한다. log.dirs = /tmp/kafka-logs-1 log.dirs = /tmp/kafka-logs-2 log.dirs = /tmp/kafka-logs-3

(zookeeper) systemd 등록 및 설명

리눅스 서버를 운영하거나 애플리케이션 서비스를 운영하는 경우에는 여러 종류의 프로세스들을 잘 관리하는 것도 매우 중요하다. 예를들어, 예기치 않게 서버의 오작동으로 인해 리부팅된 경우 어떤 프로세스는 반드시 자동으로 시작돼야 하는 경우도 있고, 반대로 어떤 프로세스는 반드시 관리자가 수동으로 시작해줘야 하는 경우가 있습니다. 이렇게 다양한 상황에 따라 효율적으로 프로세스들을 관리하기 위한 방법으로 여러 프로세스들을 systemd에 등록해 운영할 수 있다. ========================================================== 주키퍼에서는 zookeeper-server.service라는 파일명으로 만든다. <zookeeper-server.service> [Unit] Description=zookeeper-server After=network.target [Service] Type=forking User=root Group=root SyslogIdentifier=zookeeper-server WorkingDirectory=/usr/local/zookeeper Restart=always RestartSec=0s ExecStart=/usr/local/zookeeper/bin/zkServer.sh start ExecStop=/usr/local/zookeeper/bin/zkServer.sh stop ========================================================== 1. [Unit] 일반적인 옵션을 나타낸다. 가장 많이 사용하는 옵션은 실행 순서를조정하는 After, Before이다. - Description : 해당 유닛에 대한 상세한 설명을 나타내며 이 내용은 systemctl status 명령어에 표시된다. - After : 유닛이 시작되는 순서를 조정하며 After에 저장된 유닛이 실행된 이후 시작된다. - Before : 유닛이 시작되는 ...

(안드로이드) Handler post 메소드에 대한 설명

Handler 객체가 Post 메소드 안에 Runnable객체를 넣는 의미가 직접적으로 이해 되지 않아 문서를 본 결과. The  post  versions allow you to enqueue Runnable objects to be called by the message queue when they are received 상대방 측에서 메시지 큐로 부터 수신 했을 떄, 해당 Runnable 즉, 쓰레드 안에서 정의된 로직을 호출한다는 것이다.

(스칼라) build.sbt 설명

1. name : 프로젝트 이름 2. version : 프로젝트 버전 3. scalaVersion : 스칼라 버전 4. libraryDependencies : 의존하는 라이브러리 들을 설정한다. 또한 해당 라이브러리가 빌드 시점 중 어느 시점에 의존할지 설정한다. (예를들어 컴파일할 떄, 패키징 할 때) 5. assemblyOption in assembly : set-assembly  플러그인의 옵션 libraryDependencies에는 sbt가 관리하는 프로젝트가 의존하는 라이브러리를 설정하는데, Seq형식으로 설정한다. 여러개가 존재하는 경우 쉼표를 통해 구분하며, 하나의 의존라이브러리는 "<groupId> % <artifactId> % <version>" % "<configuration>" 형식으로 지정한다. <configuration>은 해당 라이브러리가 어느 의존 단계에 포함되어야 할지를 의미한다. provided 인 경우는 컴파일 단계에는 클래스패스에 포함되고, 패키지 단계에서는 포함되지 않는 것이다.