토스에서 진행한 SLASH 22를 보고 Kafka에 대한 호기심이 강하게 들었다. (이름은 많이 들어봤는데 그동안 알아볼 생각을 안했다ㅠ)

현재 팀에서 내가 맡아서 관리해야 될 서버들이 점점 늘어나고 있는데 

여기서 이 서버들이 실제 오픈을 하고 운영 레벨로 넘어가게 되면 모니터링을 하기가 굉장히 어려워질 것임을 예상했다.

현재 팀에는 딱히 모니터링 시스템이라고 할 만한 게 없고 (AWS CloudWatch를 이용하는 정도?)

내가 원하는 것은 어플리케이션 단의 모니터링 시스템이 었기 때문에

이 참에 Kafka를 활용해서 한 번 모니터링 시스템을 구축해보면 어떨까 하는 생각이 들었다. 

일단 그 생각의 실현을 위한 첫 스텝으로 Kafka가 뭔지 알아보려 한다. 

 

 

아래는 최범균 님의 'kafka 조금 아는척하기 시리즈' 유튜브 영상을 보며 정리한 내용입니다. 

 

Kafka 

분산 이벤트 스트리밍 플랫폼

 

 

4개의 구성요소

  • 프로듀서 
    • 메시지(이벤트)를 카프카에 넣는다
  • 컨슈머
    • 메시지(이벤트)를 카프카에서 읽는다.
  • 카프카 클러스터
    • 메시지(이벤트)를 저장한다.
      • 하나의 카프카 클러스터는 여러 개의 브로커로 구성되어 있으며 각각 서버라고 보면 된다. 
      • 브로커는 메시지를 나눠서 저장하고, 이중화 처리도 하고, 장애가 나면 대체도 하는 등의 역할을 수행한다. 
  • 주키퍼 클러스터 (주키퍼 앙상블) 
    • 카프카 클러스터를 관리하는 용으로 클러스터 정보가 저장되어 관리가 됩니다.
    • 브로커가 한 개 밖에 없을 때에도 클러스터로 동작하는데 클러스터 내의 브로커에 대한 분산 처리를 주키퍼가 담당한다. 
      • 주키퍼
        • 분산 시스템에서 시스템 간이 정보 공유, 상태 체크, 서버들 간의 동기화를 위한 락 등을 처리해주는 '분산 코디네이션 시스템'. 카프카에서는 서버의 상태를 감지하기 위해 사용되며 새로운 토픽이 생성되었을 때 토픽의 생성과 소비에 대한 상태를 지정합니다. 

 

토픽과 파티션

  • 토픽
    • 카프카에서 메세지를 저장하는 단위가 토픽 
    • 여러 매세지가 있을 때 이 메세지가 어떤 종류의 메세지인지 구분할 필요가 있는데 이때 사용하는 것이 토픽이다
      • 예를 들어 주문용 토픽, 뉴스용 토픽 같이 각각의 메세지를 알맞게 구분하기 위해 토픽을 사용한다.
      • 파일 시스템의 폴더와 유사하다고 보면 된다. 
    • 한 개의 토픽은 한 개 이상의 파티션으로 구성된다. 
      • 파티션은 메세지를 저장하는 물리적인 파일 
        • 프로듀서와 컨슈머는 토픽을 기준으로 메세지를 주고받는다!
  • 파티션 (= 파일이라고 보면 된다)
    • 파티션은 추가만 가능한 파일이다. 
      • 각 메세지 저장 위치를 오프셋(offset)이라고 한다. 
        • 프로듀서가 카프카에 메세지를 저장하면 저장된 메세지는 offset1, offset2 이렇게 오프셋 값을 가지게 된다.
        • 여러 consumer가 한 topic(일종의 queue 개념)으로부터 여러 번에 걸쳐 메시지를 가져올 수 있습니다. 이런 방식이 가능한 이유는 클라이언트가 해당 queue에서 어느 부분까지 데이터를 받아갔는지 위치를 알려주는 'offset'을 관리하기 때문입니다.
      • 프로듀서가 넣은 메세지는 파티션의 맨 뒤에 추가한다.
      • 컨슈머는 오프셋 기준으로 메세지를 순서대로 읽는다.
      • 메세지는 삭제되지 않는다. (설정에 따라 일정 시간이 지난 뒤 삭제)
    • 한 파티션 내에서만 메세지 순서가 보장된다.

여러 파티션과 프로듀서

  • 프로듀서는 라운드로빈 또는 키로 파티션을 선택한다. 혹은 키를 이용해서 파티션을 선택한다.
    • 프로듀서가 카프카에 메세지를 전송할 때 토픽의 이름 뿐만 아니라 키를 지정할 수 있는데 키가 있는 경우에는 그 키의 해시값을 이용해서 저장할 토픽을 선택할 수 있게 된다. 그래서 같은 키를 갖고 있는 메세지는 같은 파티션에 저장이 된다 (같은 키에 대해서는 메세지 순서가 정해진다)

여러 파티션과 컨슈머 

그룹에 속해있는 컨슈머들이 특정한 파티션을 공유할 수 없다.

  • 컨슈머는 컨슈머 그룹이라는 거에 속하게 되어 있는데 컨슈머가 카프카 브로커에 연결할 때 나는 어떤 그룹에 속해있다고 지정하게 되어있음 
    • 한 개의 파티션은 그룹의 한 개 컨슈머에만 연결이 가능하다. (= 컨슈머 그룹 기준으로 파티션의 메세지가 순서대로 처리되는 것을 보장할 수 있게 된다.)

카프카 성능이 왜 좋을까요?

  • 페이지캐쉬 - 카프카는 파티션 파일에 대해서 OS에서 제공하는 페이지 캐쉬를 이용하기 때문에 파일 IO가 메모리에서 처리되기 때문에 IO속도가 빨라진다.
    • 페이지 캐시란? ( https://medium.com/@tas.com/ )
      • 처리한 데이터를 메인 메모리 영역(RAM)에 저장해서 가지고 있다가, 다시 이 데이터에 대한 접근이 발생하면 disk에서 IO 처리를 하지 않고 메인 메모리 영역의 데이터를 반환하여 처리할 수 있도록 하는 컴포넌트다. 즉 OS가 파일을 read하여 메모리에 올려두고 있다가, 빠르게 접근하여 사용하겠다는 것.
      • 다시 kafka와 내용을 같이 보면, producer가 서버인 broker에게 넣는 데이터는 consumer가 사용하기 전 일정 시간동안 page cache 올려두어, consumer가 데이터를 읽어 갈 때 그 읽어가는 속도를 빠르게 한다는 것으로 이해하면 되겠다.
  • 제로카피 - 디스크에서 데이터를 읽어다가 네트워크로 보내는 속도가 빠르다.
    • 파일에서 소켓으로 데이터를 전송하는 전통적인 과정  -> 비효율 (4개의 사본과 2개의 시스템 호출 )
      1. 운영 체제는 디스크에서 커널 공간의 페이지 캐시로 데이터를 읽습니다.
      2. 응용 프로그램은 커널 공간에서 사용자 공간 버퍼로 데이터를 읽습니다.
      3. 응용 프로그램은 데이터를 다시 커널 공간에 소켓 버퍼에 쓴다.
      4. 운영체제는 소켓 버퍼에서 네트워크를 통해 전송되는 NIC 버퍼로 데이터를 복사한다.
        • Disk > Kernel(PageCache) > User-Space(Buffer) > Kernel(Socket Buffer) > Kernel(NIC Buffer)
    • kafka는 OS가 페이지캐시에서 네트워크로 데이터를 직접 보낼 수 있으므로 위와 같은 재복사가 방지됩니다. 따라서 이 최적화된 경로에서는 NIC 버퍼에 대한 최종 복사본만 필요합니다. 데이터가 메모리에 저장되고 읽을 때마다 사용자 공간으로 복사되는 대신 페이지 캐시에 정확히 한 번 복사되고 소비할 때마다 재사용됩니다.
    • pagecache와 sendfile의 조합 덕분에 Kafka 클러스터에서 디스크가 완전히 캐시에서 데이터를 제공하기 때문에 디스크에서 읽기 활동을 볼 수 없음을 의미합니다.

 

  • 빠르다 - 브로커가 컨슈머에 대해서 할 수 있는 역할이 없어서 상대적으로 빠르다. (제재하지 않고 프로듀서와 컨슈머가 직접 함) 
  • 일괄작업 - 묶어서 보내고 묶어서 받는다. (Batch) 프로듀서와 컨슈머는 일정 크기만큼 메시지를 모아서 전송 그리고 조회가 가능하다. 따라서 낱개로 건건히 보내는 것보다 아무래도 더 빨라질 수밖에 없음 
  • 처리량 조절 쉬움 -  그냥 브로커 추가하고 파티션 추가하거나 컨슈머가 느리다고 생각되면 컨슈머 추가하면 됨.
  • 장애 복구 간단 - 장애가 났을 때 대처하기 위해 리플리카를 사용한다.  (리더/팔로워 구조)
    • 리플리카는 파티션의 복제본으로 복제수만큼 파티션의 복제본이 각 브로커에 생김
      • 하나가 리더 나머지가 팔로워가 되어서 팔로워는 리더로부터 데이터를 읽어와서 저장하므로 리더가 속한 브로커가 장애가 발생하면 이때 다른 팔로워 중에서 하나가 리더가 되고, 프로듀서와 컨슈머는 신규 리더를 통해 메세지를 처리할 수 있게 됩니다. 

프로듀서

 

Properties prop = new Properties();
prop.put("bootstrap.servers", "kafka01:9092, kafka01:9092, kafka01:9092");
prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
prop.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

KafkaProducer<Integer, String> producer = new KafkaProducer<>(prop);
producers.send(new ProducerRecord<>("topicname", "key", "value")); // 방법1
producers.send(new ProducerRecord<>("topicname", "value")); // 방법2

producer.close();

KafkaProducer 클래스는 send 메소드를 제공하며 이 send 메소드에 ProducerRecord를 전달하면 됩니다. 

ProducerRecord가 브로커에 전달할 카프카 메세지가 됩니다.

 

프로듀서 내부 동작 흐름

 

(강의에 나온 내용 대사 그대로를 옮겨 적었습니다.)

send() 메소드를 통해 레코드를 전달하면 Serializer를 통해 byte 배열로 변환하고

Partitioner를 이용해 메세지를 어느 토픽의 파티션으로 보낼지 결정합니다.

그리고 변환된 바이트 메시지를 버퍼에 저장하는데 버퍼에 바로 저장하지 않고 배치로 묶어서 저장하게 됩니다.

그리고 sender를 통해 배치를 차례대로 가져와 카프카 브로커로 전송합니다.

  여기서 Sender는 별도 쓰레드로 동작하며 배치가 찼는지 여부에 상관없이 보내며

Sender 쓰레드와는 별개의 쓰레드에서 send 메서드를 통해 메세지를 배치로 모으게 됩니다.

(즉, 메세지를 모으는 쓰레드와 배치를 전송하는 쓰레드는 다릅니다.)

배치하고 sender와 관련된 설정이 처리량에 영향을 주게 됩니다. (batch.size / linger.ms)

batch.size는 배치의 최대 크기를 지정하고 지정한 크기만큼 메세지가 차면 메세지가 바로 전송을 하게 됩니다.

그래서 배치 사이즈가 너무 작으면 한 번에 보낼 수 있는 메세지 크기가 작고, 전송 횟수가 많아 처리량이 떨어지게 되겠죠?!

linger.ms는 센더가 메시지를 보내는 대기 시간입니다.

기본값은 0이며 대기시간을 주게 되면 기다렸다 배치를 전송하기 때문에 한 번에 많은 메세지를 보내게 됩니다. 

 

send() 메소드를 통해 전송한 것은 결과를 확인하지 않습니다. (실패 여부 모름) 따라서 실패에 대한 별도 처리가 필요없는 메시지 전송에 사용합니다. 그런데 실패 여부를 알아야 될 때가 있는데 이 때 두 가지 방법이 사용 가능하다.

 

전송 후 실패 여부를 알고 싶다면

 

  1.   Future 사용 (처리량이 낮아도 정확해야 하는 경우)

get()을 사용하면 블로킹이 되기 때문에 루프를 돌면서 전송하는 경우에는 전송-블로킹-전송-블로킹이라

배치에 메시지가 1개씩만 들어가기 때문에 처리량도 떨어짐

Future<RecordMetadata> f = producer.send(new ProducerRecord<>("topic", "value"));
try {
	RecordMetadata meta = f.get(); // 블로킹
} catch (ExecutionException ex) {}

 

2.   Callback 사용 

콜백 객체는 전송 후 전송 결과를 onCompletion 메서드로 받게 되는데 Exception을 받게 되면 전송이 실패된 것.

처리량이 떨어지지 않는다. 

producer.sned(new ProducerRecord<>("simple", "value"),
	new Callback() {
    	@Override
        public void onCompletion(RecordMetadata metadata, Exception ex) {
        }
    });

 

전송보장과 ack

 

Producer는 전송을 보장하기 위해 ack값을 제공한다. ack가 0이면 처리량은 많아 지겠지만 메세지 전송 여부는 알 수 없습니다. ack가 1이면 파티션의 리더에 값이 저장되면 성공 응답을 알려줍니다. 따라서 리더에 장애가 발생하면 메세지가 유실될 가능성이 있습니다. (팔로워에 저장이 아직 안됐는데 성공 응답을 내려주었고, 이 상태로 리더에 장애가 발생하는 경우가 이에 해당된다) ack가 all 이면 모든 팔로워에 다 저장이 되었을 때 응답을 내려줍니다. 따라서 메시지 유실이 없어야 되는 경우에는 all로 주는 것이 맞다고 볼 수 있다. 

 

+ 전송하다 에러가 나는 경우 재시도가 가능한 경우에는 kafka에서 재시도를 수행한다. 

+ enable.idempotence 속성을 사용하면 메시지 중복 전송 가능성을 낮출 수 있다. 

 

재시도와 순서

재시도의 주의 사항은 중복 전송과 순서가 바뀐다는 것이다.

  • max.in.flight.requestes.per.connection 옵션
    • 블록킹 없이 한 커넥션에서 전송할 수 있는 최대 전송중인 요청 개수

이 옵션값이 1보다 크게 되면 재시도가 언제 이뤄지냐에 따라 메시지 순서가 바뀔 수 있다. 

따라서, 전송 순서가 중요하면 이 값을 1로 지정해야 한다. 

 

 


 

컨슈머

 

토픽 파트션에서 특정 레코드 조회

Properties prop = new Properties();
prop.put("bootstrap.servers", "localhost:9092");
prop.put("group.id", "group1");
prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDesrializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String> (prop);
consumer.subscribe(Collections.singleton("simple")); // 토픽 구독
while (조건) {
	ConsumerRecords<String, String> recoreds = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record: records) {
    	System.out.println(record.value() + ":" + record.topic() + ":" + 
        	record.partition() + ":" + record.offset());
    }
}

consumer.close();

토픽 파티션은 그룹 단위로 할당된다. 

각 컨슈머가 파티션에 연결되는데 파티션보다 컨슈머가 더 많이 생기면 이후로 생기는 컨슈머는 놀게 된다. 특정 파티션에 연결될 수 없기 때문에.. 그래서 컨슈머 개수가 파티션 개수보다 커지면 안되고, 처리량이 떨어져서 컨슈머가 커져야 되면 파티션 개수도 함께 늘려야 합니다.

 

커밋과 오프셋

컨슈머의 poll 메소드는 이전에 커밋한 오프셋이 있으면 그 오프셋 이후의 레코드를 읽어 옵니다. 

만약에 poll 메소드로 레코드를 읽어오려는데 커밋된 레코드가 없는 경우에는 auto.offset.reset 옵션 설정값을 사용합니다.

 

auto.offset.reset

  • earliest : 맨 처음 오프셋 사용
  • latest : 가장 마지막 오프셋 사용
  • none :  익셉션 발생 

컨슈머 설정

조회에 영향을 주는 주요 설정

  • fetch.min.bytes
    • 조회시 브로커가 전송할 최소 데이터 크기
      • 기본값은 1이며 이게 크면 대기 시간이 늘지만 처리량은 올라감
  • fetch.max.wait.ms
    • 데이터가 최소 크기가 될 때까지 기다릴 시간 
      • 기본값은 500(0.5초)이며 브로커가 리턴할 때까지 대기하는 시간으로 poll() 메서드의 대기 시간과 다름
  • max.partition.fetch.bytes
    • 파티션 당 서버(브로커)가 리턴할 수 있는 최대 크기 
      • 기본값은 1MB

자동 커밋 / 수동 커밋

enable.auto.commit 설정을 통해 자동 커밋할지 수동 커밋을 할지 결정한다. 

true이면 일정 주기로 컨슈머가 오프셋을 커밋하고, false면 수동으로 진행되게 된다.

자동 커밋은 poll(), close() 메서드 호출시 자동으로 실행된다.

 

수동커밋 방법 

  1. 동기

ConsumerRecord<String, String> records = consumer.poll(Duration.ofSeconds(1));
for (ConsumerRecord<String, String> record : records) {
	처리
}
try {
	consumer.commitSync();
} catch (Exception ex) {
	// 커밋 실패시 에러 발생
    // 실패하면 알맞은 처리 하면 됨
}

  2. 비동기

ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));
for (ConsumerRecord<String, String> record : records) {
	..처리
}
consumer.commitAsync(); // commitAsync(OffsetCommitCallback callback)

비동기이기 때문에 코드 자체에서 실패 여부를 바로 알 수가 없고, 알고 싶으면 콜백을 받아서 처리해야 한다. 

 

컨슈머가 동일한 메시지를 읽어올 수 있다. 커밋이 실패했다거나 컨슈머가 추가 되는 케이스에서 리밸런싱이 일어나고, 이 과정에서 동일한 메시지를 읽어올 수 있다. 이때문에 멱등성(idempotence - 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질)을 고려해야 한다. 그리고 데이터 특성에 따라 타임스탬프, 일련 번호 등을 활용해야 한다. 

 

 

세션 타임아웃, 하트비트, 최대 poll 간격

컨슈머는 하트비트를 계속 브로커에 전송해서 연결을 유지한다. 브로커는 일정 시간 동안 컨슈머를 통해 하트비트를 전달받지 못하면 그룹에서 빼버린다. 그리고 리밸런싱을 진행한다. 

관련 설정은 

  • session.timeout.ms : 세션 타임 아웃 시간 (기본값 10초)
  • hearbeat.interval.ms : 하트비트 전송 주기 (기본값 3초)
    • session.timeout.ms의 1/3 이하 추천
  • max.poll.interval.ms : 정해진 시간 동안 poll()하지 않으면 컨슈머를 그룹에서 빼고 리밸런스를 진행한다. 

 

세션 종료

보통은 무한 루프를 돌면서 poll() 메서드로 레코드를 불러온느 코드를 작성하게 되는데 이 loop를 어떻게 벗어날 수 있을까! 바로 wakeup() 메서드를 호출한다. finally에서 consumer.close()를 해주자~

 

KafkaConsumer는 쓰레드에 안전하지 않기 때문에 여러 쓰레드에서 동시에 사용하지 않아야 한다. 

 


추가 내용

 

주키퍼 

• 주키퍼 사용용도

주키퍼는 클러스터에서 구성 서버들끼리 공유되는 데이터를 유지하거나 어떤 연산을 조율하기 위해 주로 사용

  • 설정 관리 : 클러스터의 설정 정보를 최신으로 유지하기 위한 조율 시스템으로 사용됩니다.
  • 클러스터 관리 : 클러스터의 서버가 추가되거나 제외될 때 그 정보를 클러스터 안 서버들이 공유하는 데 사용됩니다.
  • 리더 채택: 다중 어플리케이션 중에서 어떤 노드를 리더로 선출할 지를 정하는 로직을 만드는 데 사용됩니다. 주로 복제된 여러 노드 중 연산이 이루어지는 하나의 노드를 택하는 데 사용됩니다.
  • 락, 동기화 서비스 : 클러스터에 쓰기 연산이 빈번할 경우 경쟁상태에 들어갈 가능성이 커집니다. 이는 데이터 불일치를 발생시킵니다. 이 때, 클러스터 전체를 대상을 동기화해( 락을 검 ) 경쟁상태에 들어갈 경우를 사전에 방지합니다.

 

Kafka vs RabbitMQ

둘 다 pub/sub 기반의 메시지 큐 서비스인데 Kafka는 이벤트 브로커이고, RabbitMQ는 메세지 브로커이다. 

이벤트 브로커는 메세지 브로커의 기능을 포함하는 더 큰 범위의 개념이기에 이벤트 브로커가 메세지 브로커 역할을 수행할 수도 있다.

메세지 브로커는 중간 다리 역할을 수행하는 broker로 publisher가 생산한 메세지를 큐에 저장하고, consumer가 데이터를 가져가면 즉시 혹은 짧은 시간 내에 큐에서 데이터를 삭제한다. 보통 서로 다른 시스템 사이에서 데이터를 비동기 형태로 처리하고 싶을 때 사용하며 AWS에서는 비슷하게 SQS가 있다. 

 

이벤트 브로커는 publisher가 생산한 이벤트를 저장하고,  consumer가 해당 이벤트를 사용하더라도 이벤트가 저장된다는 특징으로 이후에 다시 재사용 할 수 있는 장점을 가지고 있다. 

 

(https://www.cloudamqp.com/blog/when-to-use-rabbitmq-or-apache-kafka.html)

RabbitMQ 사용 사례 
  • 일반적으로 단순/전통적인 pub-sub 메시지 브로커를 원하는 경우 확실한 선택은 RabbitMQ입니다. 요구 사항이 channels/queues을 통한 시스템 통신을 처리할 만큼 간단하고, 메세지를 보존하거나 스트리밍을 요구하는게 아닌 경우에 말이다. 
  • 두 개의 주요 사용 사례로 나눌 수 있다.
    • LONG-RUNNING TASKS
      • RabbitMQ를 사용하는데 오래 걸리는 작업이 백그라운드에서 안정적으로 실행되어야 할 때
    • MIDDLEMAN IN A MICROSERVICE ARCHITECTURES
      • 애플리케이션 내부 및 애플리케이션 간의 통신 및 통합을 위한 경우
      • 마이크로서비스 간의 중개자로서 시스템에게 단순히 작업을 실행하라는 것을 알릴 때 예를 들면 주문 처리나 주문 상태 업데이트 같은 경우다. 

Apache Kafka 사용 사례

  • 일반적으로 스트리밍 데이터를 저장, 읽기(다시 읽기), 분석하기 위한 프레임워크를 원한다면 Apache Kafka를 사용합니다. 감사를 받거나 메시지를 영구적으로 저장해야 하는 시스템에 이상적입니다.
  • 두 개의 주요 사용 사례로 나눌 수 있다.
    • DATA ANALYSIS (추적, 수집, 로깅, 보안 등)
      • 데이터를 분석해서 Insights를 얻고, 수많은 데이터에 대한 감사 또는 분석이 필요한 경우.
      • 주요 분석, 검색 및 저장 시스템
    • 실시간 처리
      • 처리량이 많은 분산 시스템 역할을 합니다. 소스 서비스는 데이터 스트림을 실시간으로 가져오는 대상 서비스로 푸시
      • Kafka는 적은 수의 소비자와 실시간으로 많은 생산자를 처리하는 시스템에서 사용할 수 있습니다. 즉, 주식 데이터를 모니터링하는 금융 IT 시스템.

 

  RabbitMQ Apache Kafka
무엇인가? 견고하고 성숙한 범용 메시지 브로커 높은 유입 데이터 스트림 및 재생에 최적화된 Message Bus
주요 용도 애플리케이션 내부 및 애플리케이션 간의 통신 및 통합으로 기 실행 작업 또는 안정적인 백그라운드 작업을 실행해야 하는 경우 스트리밍 데이터의 저장, 읽기(다시 읽기) 및 분석
메세지 지속성 수신 확인 시 삭제 보존 기간 옵션에 따라 메세지 유지
(수신 되어도 삭제하지 않음)
라우팅 소비자 노드에 정보를 반환할 수 있는 유연한 라우팅 지원 유연한 라우팅을 지원하지 않으며 별도의 주제를 통해 수행해야 합니다.
메시지 우선순위 지원 지원하지 않음
 
 

 

 

 

출처

https://www.youtube.com/watch?v=0Ssx7jJJADI (최범균 님의 kafka 조금 아는척하기 시리즈)

https://epicdevs.com/17

https://m.blog.naver.com/kgw1988/221212827363 (카프카에서의 데이터 저장 방식)

https://kafka.apache.org/documentation/#gettingStarted 공식문서

 https://programacion.tistory.com/156 [KA's Regalo:티스토리]

https://www.cloudamqp.com/blog/when-to-use-rabbitmq-or-apache-kafka.html

-내용 출처 : 우아한 Tech 채널 (디디의 Redis)

 

  • Redis
    • Remote Dictonary Server
    • 원격의 Key,Value 구조 서버로 해석할 수 있다. 
  • Cache
    • 나중의 요청에 대한 결과를 미리 저장했다가 빠르게 사용하는 것
    • 어디에 ? 메모리 구조를 먼저 살펴보자.
  • 메모리구조
    • Storage (SSD, HDD) -> Main Memory (DRAM) -> CPU Cache -> CPU Register
      • -> 이 순으로 속도가 빠르고, 비싸다.
    • 맥북을 예로 들면?
      • i7 CPU - 12 MB Cache Memory / 16GB DRAM / 512GB SSD
        • 12MB Cache Memory (SRAM) : 엄청 빠르고, 비싼데 용량이 작음->데이터베이스로 사용하기엔 작음
        • 16GB DRAM : 적당히 빠르고, 비싸고, 크고 휘발성임 -> 휘발성이라는 것은 컴퓨터가 꺼지면 데이터가 전부 날라가게 됨
        • 512GB SSD : 비교적 느리고, 저렴하고, 용량이 엄청큼, 그리고 비휘발성! 
    • 데이터베이스는 컴퓨터가 꺼져도 데이터를 유지해야 하기 때문에 SSD에 기본적으로 저장함
    • 하지만 기술이 발달하고, 하드웨어가 커지다 보니 메인메모리에 저장해서 좀 더 빠르고 쉽게 데이터에 접근하면 어떨까? 하는 접근방식으로 나온 것이 Redis
Database보다 더 빠른 Memory에 더 자주 접근하고 덜 자주 바뀌는 데이터를 저장하자
In-memory Database Redis (Cache)

 

  • Data Structure
    • Collection을 지원함 (Memcached와 다른 점)
    • 자바를 예로 들면 아래와 같은 자료구조를 제공한다.
      • Map.Entry
      • LinkedList
      • HashSet
      • TreeSet
      • HashMap
  • 어디에서 쓰나요?
    • 여러 서버에서 같은 데이터를 공유할 때
  • 주의해야 할 점
    • Single Thread 서버 이므로 시간 복잡도를 고려해야 한다.
      • Redis는 기본적으로 Single Threaded를 활용함, 이를 통해 여러 개의 Thread가 경합하는 Race Condition을 피하려고 했음 (이 외에도 여러 방법을 통해 Race Condition을 방지하려 함)
      • 네트워크로 부터 요청을 받아서 처리를 할 때 Command가 오랜 시간이 걸리는 경우 나머지 요청들이 더 이상 받아지지 않고 서버가 다운되는 문제가 발생될 수 있음
      • O(N)의 명령어 같은 경우는 지양해야 한다. (싱글쓰레드기 때문에 처리가 그만큼 빨라야 한다)
        • 예를 들면 모든 Key들을 가져오는 명령어, Flush(), GetAll() 같은 것
    • In-memory 특성상 메모리 파편화, 가상 메모리 등의 이해가 필요
  • 메모리 관리
    • 메모리 파편화
    • 가상메모리 Swap
    • Replication - Fork
      • 메모리 데이터 저장소이기 때문에 데이터 유실될 문제를 안고 있음
      • 복사 기능을 제공해주기 때문에 slave redis server 혹은 디스크에 데이터를 복사 저장함
      • 복사를 할 때 프로세스를 그대로 복사해서 사용하는 과정을 거치는데 만약 메모리가 꽉 차 있다면 복사가 잘 안되어 서버가 죽는 경우가 생길 수 있기 때문에 메모리를 여유있게 사용해야 함

드디어 도커를 실제로 사용해보는 날이다. 

이노무 자식, 너를 낱낱히 파헤쳐보겠다.

 

출처는 아래와 같고, 이 포스팅은 아래 출처에서 나온 내용을 정리하기 위함이다. 

https://subicura.com/2017/01/19/docker-guide-for-beginners-2.html

 

다운로드는 Docker for Mac .dmg파일을 다운로드 받아 설치하면 된다.

도커는 리눅스 컨테이너이므로 네이티브 처럼 설치되었지만 실제로는 가상머신에 설치된 것.

 

도커를 설치하고 아래의 명령어를 보면 설치가 잘 완료된 것을 볼 수 있다. 

$ docker version

Client와 Server정보가 정상적으로 출력되면 된다. 

 

여기서 버전 정보가 Client와 Server로 나뉘어져 있는 이유는 도커는 하나의 실행파일이지만 실제로 클라이언트와 서버 역할을 할 수 있기 때문이다. 도커 커맨드를 입력하면 클라이언트에서 도커 서버로 명령을 전송하고 결과를 받아 터미널에 출력한다. 기본값이 도커 서버의 소켓을 바라보고 있기 때문에 터미널에서 명령어를 입력했을 때 바로 명령을 내리는 것 같은 느낌을 받는다. 이게 가상 서버에 설치된 도커가 동작하는 이유!

 

 

아래는 docker 공식 Documentaion에서 발췌한 내용이다.

https://docs.docker.com/get-started/overview/

https://docs.docker.com/get-started/overview/

Docker 클라이언트 는 Docker 컨테이너를 빌드, 실행 및 배포하는 무거운 작업을 수행 하는 Docker 데몬 과 통신합니다. Docker 클라이언트와 데몬 은 동일한 시스템에서 실행되거나 Docker 클라이언트를 원격 Docker 데몬에 연결할 수 있습니다. Docker 클라이언트와 데몬은 UNIX 소켓 또는 네트워크 인터페이스를 통해 REST API를 사용하여 통신합니다. 

 

도커 데몬 

Docker 데몬( dockerd)은 Docker API 요청을 수신하고 이미지, 컨테이너, 네트워크 및 볼륨과 같은 Docker 객체를 관리합니다. 데몬은 Docker 서비스를 관리하기 위해 다른 데몬과 통신할 수도 있습니다.

도커 클라이언트 

Docker 클라이언트( docker)는 많은 Docker 사용자가 Docker와 상호 작용하는 기본 방법입니다. 와 같은 명령을 사용할 때 docker run클라이언트는 이러한 명령을 로 보냅니다 dockerd. 이 docker명령은 Docker API를 사용합니다. Docker 클라이언트는 둘 이상의 데몬과 통신할 수 있습니다.

도커 레지스트리 

Docker 레지스트리 는 Docker 이미지를 저장합니다. Docker Hub는 누구나 사용할 수 있는 공개 레지스트리이며 Docker는 기본적으로 Docker Hub에서 이미지를 찾도록 구성되어 있습니다. 자신의 개인 레지스트리를 실행할 수도 있습니다. docker pull또는 docker run명령 을 사용하면 구성된 레지스트리에서 필요한 이미지를 가져옵니다. docker push명령 을 사용하면 이미지가 구성된 레지스트리로 푸시됩니다.

이미지

이미지 도커 컨테이너를 만들기위한 읽기 전용 템플릿입니다. 종종 이미지는 몇 가지 추가 사용자 정의와 함께 다른 이미지를 기반으로 합니다. 예를 들어, 이미지를 기반으로 하는 이미지를 빌드할 수 ubuntu 있지만 Apache 웹 서버와 애플리케이션은 물론 애플리케이션을 실행하는 데 필요한 구성 세부 정보도 설치합니다.

자신만의 이미지를 만들거나 다른 사람이 만들고 레지스트리에 게시한 이미지만 사용할 수 있습니다. 고유한 이미지를 빌드하려면 이미지를 만들고 실행하는 데 필요한 단계를 정의하는 간단한 구문 으로 Dockerfile 을 만듭니다. Dockerfile의 각 명령은 이미지에 계층을 생성합니다. Dockerfile을 변경하고 이미지를 다시 빌드하면 변경된 레이어만 다시 빌드됩니다. 이것은 다른 가상화 기술과 비교할 때 이미지를 가볍고 작고 빠르게 만드는 부분입니다.

컨테이너

컨테이너는 이미지의 실행 가능한 인스턴스입니다. Docker API 또는 CLI를 사용하여 컨테이너를 생성, 시작, 중지, 이동 또는 삭제할 수 있습니다. 컨테이너를 하나 이상의 네트워크에 연결하거나, 스토리지를 연결하거나, 현재 상태를 기반으로 새 이미지를 생성할 수도 있습니다.

기본적으로 컨테이너는 다른 컨테이너 및 해당 호스트 시스템과 비교적 잘 격리되어 있습니다. 컨테이너의 네트워크, 저장소 또는 기타 기본 하위 시스템이 다른 컨테이너나 호스트 시스템과 얼마나 격리되었는지 제어할 수 있습니다.

컨테이너는 이미지와 컨테이너를 만들거나 시작할 때 제공하는 구성 옵션으로 정의됩니다. 컨테이너가 제거되면 영구 저장소에 저장되지 않은 상태 변경 사항이 사라집니다.

 

 

도커를 실행하는 명령어는 다음과 같습니다.

docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

https://subicura.com/2017/01/19/docker-guide-for-beginners-2.html

Ubuntu 컨테이너 생성 명령어

컨테이너는 ubuntu 16.04로 예제와 동일하게 실행했고, local에 존재하지 않아서 이미지를 pull하였다. 

$ docker run ubuntu:16.04

컨테이너는 생성되자마자 종료되었다.

컨테이너는 프로세스이기 때문에 실행중인 프로세스가 없으면 컨테이너는 종료된다. 

 

/bin/bash 명령어를 사용하여 컨테이너를 실행

$ docker run --rm -it ubuntu:16.04 /bin/bash

바로 이전에 이미지를 다운 받았기 때문에 이미지를 다운로드 하는 화면 없이 바로 실행되었다. 

exit 명령어를 통해 bash 쉘을 종료하면 컨테이너도 같이 종료됩니다. 

 

redis 컨테이너 생성

메모리 기반의 다양한 기능을 가진 스토리지 redis,

redis 컨테이너를 실행해보자!

 

-d : 백그라운드 모드 

-p : 컨테이너의 포트를 호스트의 포트로 연결

 

docker run -d -p 1234:6379 redis
$ telnet localhost 1234 // telnet이 없어서 brew로 설치해주었다.
Trying ::1...
Connected to localhost.
Escape character is '^]'.

//여기서부터 명령어를 입력해주면 된다.
set mykey hello
+OK
get my key
$5
hello
quit

백그라운드 모드에서 동작하고 있던 컨테이너. -p 로 동작시킨 컨테이너이기 때문에 호스트의 1234 포트를 컨테이너의 6379 포트로 연결하였다. 따라서 localhost의 1234 포트로 접속하게 되면 redis를 바로 사용할 수 있게 된다.

 

MySQL 컨테이너 생성

 

-e : 환경변수 설정

--name : 컨테이너에 읽기 어려운 ID 대신 쉬운 이름을 부여한다. 

$ docker run -d -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true --name mysql mysql:5.7

$ mysql -h127.0.0.1 -uroot // mysql 도 brew로 설치해주었다.

mysql> show databases;
mysql> quit

MYSQL_ALLOW_EMPTY_PASSWORD 환경변수를 설정하여 패스워드 없이 root 계정을 만들었다. 

 

그 외

$ mysql -h127.0.0.1 -uroot
create database wp CHARACTER SET utf8;
grant all privileges on wp.* to wp@'%' identified by 'wp';
flush privileges;
quit

# run wordpress container docker run -d -p 8080:80 --link mysql:mysql \
  -e WORDPRESS_DB_HOST=mysql \
  -e WORDPRESS_DB_NAME=wp \
  -e WORDPRESS_DB_USER=wp \
  -e WORDPRESS_DB_PASSWORD=wp \
  wordpress

워드프레스용 데이터베이스를 생성하고 워드프레스 컨테이너를 실행합니다. 호스트의 8080포트를 컨테이너의 80포트로 연결하고 MySQL 컨테이너와 연결한 후 각종 데이터베이스 설정 정보를 환경변수로 입력합니다.

중요한건 MySQL 컨테이너와 연결한다는 것 같다. 

 

<tensorflow>

$ docker run -d -p 8888:8888 -p 6006:6006 teamlab/pydata-tensorflow:0.1

 

이렇게 여러개의 컨테이너를 실행해보았고, 컴퓨터가 컨테이너 기반의 도커를 이용해 짱짱하게 실행하는 것을 볼 수 있었다. 


도커 기본 명령어

 

 

컨테이너 목록 확인하기 

docker ps [OPTIONS]

OPTIONS : -a , --all

 

컨테이너 중지 및 삭제 

docker stop [OPTIONS] CONTAINER [CONTAINER...] //중지
docker rm [OPTIONS] ${CONTAINER_ID} //삭제

이미지 목록 확인하기

docker images [OPTIONS] [REPOSITORY[:TAG]]

이미지 다운로드하기

docker pull [OPTIONS] NAME[:TAG|@DIGEST]
docker pull ubuntu:14.04

이미지 삭제하기

docker rmi [OPTIONS] IMAGE [IMAGE...]

 

 


 

 

컨테이너 둘러보기

컨테이너 로그 보기 

컨테이너가 정상 동작하는지 확인 

docker logs [OPTIONS] CONTAINER

options : -f, --tail

 

아무 옵션이 없는 경우 전체 로그 출력, --tail 옵션은 마지막 10줄만, -f 옵션은 실시간 로그 생성 확인을 위함

 

컨테이너 명령어 실행하기 

실행중인 컨테이너에 들어가서 파일을 실행하고 싶을 때가 있음 -> 그럴 때 exec 명령어로 실행함

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
docker exec -it mysql /bin/bash //실행중인 MySQL 컨테이너에 접속

 

컨테이너 업데이트

먼저 새 버전의 이미지를 다운받고, 기존 컨테이너를 중지 혹은 삭제한 다음 새 이미지를 기반으로 새 컨테이너를 실행 

그런데 컨테이너를 삭제할 때 컨테이너에서 생성된 모든 파일이 사라지게 됨으로 중요한 데이터의 경우에는 외부 스토리지에 저장해야 하는데 AWS S3 혹은 Data Volumes를 컨테이너에 추가해서 사용. 

 

데이터 볼륨은 호스트의 디렉토리를 마운트해서 사용하는 방법이 있다. 

MySQL은 /var/lib/mysql디렉토리에 모든 DB정보가 담기므로 호스트의 특정 디렉토리를 연결해주도록 한다.

 

# before
$ docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --name mysql \
  mysql:5.7

# after
$ docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --name mysql \
  -v /my/own/datadir:/var/lib/mysql \ # <- volume mount
  mysql:5.7

https://subicura.com/2017/01/19/docker-guide-for-beginners-2.html

/my/own/daradir 디렉토리를 컨테이너의 /var/lib/mysql 디렉토리로 마운트한다. 

이전 버전의 MySQL 이미지를 삭제하고 최신 버전의 MySQL 이미지를 다운받고 컨테이너를 실행할 때 동일한 디렉토리를 마운트한다면 데이터를 그대로 사용할 수 있게 되는 것이다.

 

 


 

Docker Compose

커맨드라인에서 명령어로 작업하지 않고, YAML방식의 설정파일을 이용해서 복잡한 명령어를 쉽게 수행할 수 있게 한다.

$ curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ docker-compose version

 

아래는 docker-compose.yml 파일의 내용이다.

version: '2'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
       - wp_data:/var/www/html
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
    wp_data:
$ mkdir wp
$ cd wp
$ wp vi docker-compose.yml
$ wp docker-compose up

 

실행하게 되면 손쉽게 워드프레스가 만들어진 것을 확인할 수 있다. 

 

 

이 포스팅의 대부분의 글은 아래의 사이트를 참고하였습니다.

https://subicura.com/2017/01/19/docker-guide-for-beginners-2.html

도커,, 정말 지겹게도 많이 들어본 단어인데 아직도 정확히 뭔지 모른다.

궁금증이 극에 달할 때 마다 구글링을 해서 찾아봤었고, 아 이런거구나 싶었다가도 금방 다시 원상태로 복귀.

정확하게 무엇인지 이해를 못했으니.. 

오늘 또 궁금증이 극에 달하여 구글링을 시작했고, 이왕 이렇게 된거 포스팅을 정리하며 간단하게 정리해보고자 한다.

부디 이번에는 단기기억에서 장기기억으로 넘어갈 수 있도록 해보겠다.

장황하게 쓰지 않고 짧고 간단하게.

가능하면 도커 이해를 위한 미니프로젝트도 해보고 싶다.

왜냐면 나란 사람은 실제 코딩을 해봐야 와닿는 사람이기 때문에.. (부딪혀보고 보는 편)

 

 

 

일단, 아래 글을 정독하며 이해해보기로 한다.

https://subicura.com/2017/01/19/docker-guide-for-beginners-1.html

 

 

글쓴이는 실제 아래와 같은 상황에서 어려움을 겪어다고 한다.

  • Redhat Enterprise Linux 4에 Oracle 10g을 설치해야 하는데 설치가 잘 되지 않았다.
  • 회사에서 사용하는 리눅스와 오라클 버전은 딱 정해져있다. 
  • 버전을 업데이트 하는 건 정말 어렵고 Risky함
  • 서버 세팅은 정말 어렵
  • 하나의 서버에 여러개의 프로그램을 설치하는 것은 어렵다.
    • 라이브러리의 버전이 다르거나 동일한 포트를 사용하는 문제가 있기 때문에 
  • 서버 환경은 계속 바뀌고 있음 AWS -> Azure 혹은 CentOS -> Ubuntu 
  • 마이크로서비스 아키텍쳐로 프로그램이 많아져 서버 관리가 어렵다. (서버가 수백, 수천대)

 

이런 상황에 도커가 등장! 

서버 관리 방식이 완전히 바뀌게 된다.

 

 

 

도커는 그래서 무엇인가 ?

  • 컨테이너 기반의 오픈소스 가상화 플랫폼 
    • ^^ ㅋㅋㅋㅋㅋ 이게 뭔말인가 
    • 실생활의 컨테이너 
      • 네모난 화물 수송용 박스로 옷, 신발 등의 다양한 화물을 넣어서 배로 쉽게 옮기는 것
    • 서버에서의 컨테이너
      • 다양한 프로그램, 실행환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로그램의 배포 및 관리를 단순하게 해준다. 
      • PC, AWS, Azure, Google cloud등 어디에서든 실행가능 
  • 컨테이너 
    • 격리된 공간에서 프로세스가 동작하는 기술로 가상화 기술의 하나 (프로세스 격리 방법 or 격리된 공간)
      • 기존의 가상화 기술과 다른 점은?
        • 전체 OS를 가상화 한 것이 아님 (리눅스에서 윈도우를 돌림)
          • 호스트 OS 위에 게스트 OS 전체를 가상화하는 방식  (구방식) -> 무겁&느림
        • 게스트 OS 정도만 필요라 하는 거기 때문에 성능이 기존 가상화보다 성능이 향상됨
    • 하나의 서버에 여러개의 컨테이너를 실행하면 서로 영향을 미치지 않고 독립적으로 실행 (가벼운 VM느낌)
    • 컨테이너를 띄워서 할 수 있는 것은 ?
      • 실행중인 컨테이너에 접속해서 apt-get or yum으로 패키지 설치 가능
      • 여러개의 프로세스를 백그라운드로 실행할 수 있음
      • CPU나 메모리 사용량 제한 가능 
      • 호스트와 특정 포트와 연결하거나 호스트의 특정 디렉토리를 내부 디렉토리인 것처럼 사용 가능 
    • 새로운 컨테이너를 하나 만드는 데는 1-2초로 가상 머신과 비교할 수가 없음 

  • 이미지
    • 컨테이너 실행에 필요한 파일과 설정값등을 포함하고 있는 것 (Immutable - 불변)
    • 컨테이너 = 이미지를 실행한 상태 
      • 추가되고 변하는 값은 컨테이너에 저장
    • 같은 이미지에서 여러개의 컨테이너를 생성할 수 있음 
      • 컨테이너의 상태가 변하거나 삭제되도 이미지는 변하지 않고 그대로 남아 있음 
    • 이미지는 컨테이너를 실행하기 위해 필요한 모~~든 정보를 가지고 있기 때문에 의존성 파일을 컴파일하고 이것저것 설치하지 않아도 된다. 
      • 그냥 이미지를 다운받고 컨테이너를 생성하면 된다. 
    • 이미지 저장 방식 
      • 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 도커 이미지는 용량이 굉장히 크다. 
        • 기존 이미지에 파일 하나를 추가 함으로써 전체를 다시 다운받는다면 매우 비효율적  
      • 그래서 레이어라는 개념을 사용
        • 유니온 파일 시스템을 이용하여 어러개의 레이어를 하나의 파일시스템으로 사용함
        • 읽기 전용 레이어로 구성되고 파일이 추가 되거나 수정되면 새로운 레이어가 생성됨 
            • ubuntu 이미지가 A + B + C의 집합이라면, ubuntu 이미지를 베이스로 만든 nginx 이미지는 A + B + C + nginx가 됩니다.
  • Dockerfile
    • 도커는 이미지를 만들기 위해 Dockerfile 이라는 파일에 DSL 언어를 사용하여 이미지 생성 과정을 적음 
    • 서버에 어떤 프로그램을 설치하려고 이것저것 의존성 패키지를 설치하고 설정 파일을 만들었던 것을 이제는 Dockerfile로 관리할 수 있다. 
 vertx/vertx3 debian version
FROM subicura/vertx3:3.3.1
MAINTAINER chungsub.kim@purpleworks.co.kr

ADD build/distributions/app-3.3.1.tar /
ADD config.template.json /app-3.3.1/bin/config.json
ADD docker/script/start.sh /usr/local/bin/
RUN ln -s /usr/local/bin/start.sh /start.sh

EXPOSE 8080
EXPOSE 7000

CMD ["start.sh"]

 

'TIL (Today I Learned)' 카테고리의 다른 글

Redis  (0) 2021.12.08
Docker mac에 설치해서 컨테이너 실행해보기 / Docker 문법  (0) 2021.08.04
BigQuery - Cloud SQL , CSV 파일  (0) 2019.10.18
Google Kubernetes Engine(GKE)  (1) 2019.10.15
NGINX  (0) 2019.10.15

Google Quick Lab 에 있는 내용을 조금 정리해보았어요~ :-)

오늘 들어야 할 랩이 4개나 남았는데 왜이리 졸린지 ㅠㅠ

 

 

  •  BigQuery
    • 구글 클라우드 플랫폼에서 실행되는 페타바이트 규모의 데이터 웨어하우스
  • Exporting queries as CSV files
    • BigQuery Consoel에서의 데이터 결과를 CSV파일로 추출
  • Upload CSV files to Cloud Storage
    • Navigation menu > Storage > Browser 선택해서 Create Bucket 선택 
    • 버켓 이름 지어주고 버켓생성하기~
    • 버켓 생성 후 Upload files 클릭해서 아까 추출한 CSV 파일을 올린다.
  • Cloud SQL 생성해서 CSV 파일 넣어주기
    • Navigation menu > SQL
    • 인스턴스 생성 클릭
    • MySQL 을 데이터베이스 엔진으로 선택
    • Console에서 데이터베이스와 테이블 생성
      • gcloud sql connect qwiklabs-demo --user=root
      • CREATE DATABASE bike;
      • CREATE TABLE london1 (필드명 1 VARCHAR(255), 필드명 INT ...)
      • USE bike;
      • CREATE TABLE london1;
      • 여기까지 하면 데이터를 부을 준비가 완료된 것임,
    • Cloud SQL 인스턴스 페이지에서 IMPORT 클릭
    • 아까 생성한 CSV 파일을 넣어주고 만들어둔 데이터베이스와 테이블을 선택한다. 
    •  Import 해주면 완성!

'TIL (Today I Learned)' 카테고리의 다른 글

Redis  (0) 2021.12.08
Docker mac에 설치해서 컨테이너 실행해보기 / Docker 문법  (0) 2021.08.04
Docker 도커가 대체 뭐야 ㅠㅠ  (0) 2021.08.03
Google Kubernetes Engine(GKE)  (1) 2019.10.15
NGINX  (0) 2019.10.15
  • Google Kubernetes Engine(GKE)은 Google 인프라를 사용하여 컨테이너형 애플리케이션을 배포, 관리 및 확장할 수 있는 관리 환경을 제공한다. Kubernetes Engine 환경은 컨테이너 클러스터를 형성하기 위해 그룹화된 여러 개의 기계(특히 Google Compute Engine 인스턴스)로 구성된다. 
  • Kubernetes 명령과 리소스를 사용하여 애플리케이션을 배포 및 관리하고, 관리 작업을 수행하고 정책을 설정하고, 배포된 워크로드의 상태를 모니터링 할 수 있다.
  • Kubernetes Engine cluster를 사용하면 Google 클라우드에서 제공하는 아래 기능을 활용할 수 있다. 
    • Load-balancing
    • Node Pools (클러스터 내의 노드 하위 세트를 지정하는 역할)
    • Automatic scaling
    • Automatic upgrades
    • Node auto-repair
    • Logging and Monitoring
  • GKE를 사용하여 컨테이너 생성, 애플리케이션 배포를 해봅시다!

 

'TIL (Today I Learned)' 카테고리의 다른 글

Redis  (0) 2021.12.08
Docker mac에 설치해서 컨테이너 실행해보기 / Docker 문법  (0) 2021.08.04
Docker 도커가 대체 뭐야 ㅠㅠ  (0) 2021.08.03
BigQuery - Cloud SQL , CSV 파일  (0) 2019.10.18
NGINX  (0) 2019.10.15

TIL인 만큼 짧은 메모 형식으로만 기록하겠다.

 

Google Quick Lab에 참여하는 도중 NGINX란 단어가 나와 조금 찾아보았다. 

  • 엔진 X라고 읽음
  • Web Server , FTP, EMAIL 기능을 가진다. 
  • 클라이언트 요청에 응답하기 위해서 비동기 이벤트 기반의 구조를 가지고 작동하는데, 아파치 웹서버의 경우는 스레드/프로세스 기반의 구조를 가진다. 
  • Web Server ( = HTTP SERVER)
    • 서버쪽에서 데이터를 전달하는 소프트웨어
    • HTTP 요청을 처리할 수 있는 서버
  • Apache에 비해 더 빠르게 데이터를 제공한다. -> 경량화된 Web Server
  • 핵심은? 빠르다!

내가 현재 듣는 Quick Lab은 GCP ESSENTIAL 의 'CREATING A VIRTUAL MACHINE'이다.

Google Compute Engine은 다양한 OS를 실행하는 가상머신을 만들고 나서, NGINX web server를 요 가상머신에 연결시킨다. 

 

톰캣으로 웹 서버를 만든다고 하면 나는 아파치 웹서버를 썼다고 말할 수 있는 건가?

-> 톰캣에 아파치의 기능이 포함되어 있군..!

 

우선, 다른 사이트에 나온 내용 중 이해하는 데 도움된 내용이 있어서 정리할 겸 적어봤다. 

 

Web Server는 정적인 요청을 처리하는 서버이다. 

Web Application Server 는 동적인 요청을 처리하고, JSP와 Servlet이 실행될 수 있는 환경을 제공한다. 웹서버로부터 요청이 오면 컨테이너가 받아서 처리하고, 컨테이너는 web.xml을 참조하여 해당 서블릿에 대한 쓰레드를 생성한 다음 httpServeletRequest와 httpServletResponse 객체를 생성하여 전달한다. 컨테이너는 서블릿을 호출한다. 호출된 서블릿의 작업을 담당하게 된 쓰레드는 doPost()와 doGet()을 호출하여 이 메소드를 통해 동적페이지를 response객체에 담아 컨테이너에 전달하며, 컨테이너는 전달받은 response객체를 http response 형태로 바꾸어 웹서버에 전달하고 생성된 쓰레드를 종료하고 httpServletRequest, httpServletResponse 객체를 소멸시킨다.  WAS가 처리한 걸 웹서버가 받아서 응답해준다. (출처 : https://jeong-pro.tistory.com/84)

 

+ Recent posts