ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Apache Kafka란 - 이론 공부 내용
    Kafka 2021. 9. 12. 00:02

    카프카의 등장배경

    아파치 카프카(Apache Kafka)미국의 대표적인 비즈니스 인맥 소셜네트워크 링크드인(LinkedIn)에서 처음 개발된 분산 메시징 시스템이다. 

    현재 데이터 파이프라인을 구축할 때 가장 많이 고려되는 시스템 중 하나이다.

    (Data Pipeline-데이터를 생성해서 무사히 저장하기까지 일련의 과정을 데이터 파이프라인이라고 한다)

     

    kafka는 비즈니스 특화 서비스인 링크드인에서 처음 출발했고,

    링크드인 사이트가 급속도로 성장하면서 발생하는 내부 여러 이슈들을 해결하기 위해 탄생하였다.

    linkedin 기존 데이터파이프라인

     

    위의 아키텍처처럼 링크드인의 엔드 투 엔드(End to End) 연결 방식의 아키텍처는 많은 문제점이 있었다.

     

    1.  첫 번째로는 실시간 트랜잭션(OLTP) 처리와 비동기 처리가 동시에 이뤄지지만 통합된 전송 영역이 없으니 복잡도는 증가할 수밖에 없었다. 또한 문제가 발생했을 때, 조치를 취하려면 여러 시스템에서 확인해야 했다.
    2. 두 번째로는 데이터 파이프라인 관리의 어려움이다. 실시간 트랜잭션 데이터 베이스, 아파치 하둡 등 많은 데이터 시스템들이 있는데, 이러한 시스템은 저장된 동일한 데이터를 개발자나 개발 부서에서 각기 다른 방법으로 파이프 라인을 만들고, 유지하게 되어 있었다. 하지만 통합 데이터 분석을 위해 데이터 파이프라인들을 서로 연결되어야 할 때, 각 파이프라인별로 데이터 포맷과 처리하는 방법들이 완전히 달라서 데이터 파이프라인을 확장하기 어려웠고, 데이터 파이프라인을 조정하고 운영하는 것은 엄청난 노력이 필요하게 되었다.

    kafka  도입 후 데이터파이프라인

    이러한 문제점을 타파하기위해 링크드인 개발자들은 다음과 같은 목표 목표로 새로운 시스템을 직접 만들기 시작하였다.

     

    Kafka 개발 당시 지향점

    1. producer와 consumer의 분리
    2. 메시징 시스템과 같이 영구 메시지 데이터를 여러 consumer에게 허용
    3. 높은 처리량을 위한 메시지 최적화
    4. 데이터가 증가함에 따라 스케일아웃이 가능한 시스템

    이었다.


    카프카의 구조

    Publisher Subscriber 모델

     Publish-Subscribe 모델은 데이터를 만들어내는 publisher(Producer, 생산자), 소비하는 subscriber(Consumer, 소비자) 그리고 사이에서 중재자 역할을 하는 broker 구성된 느슨한 결합(Loosely Coupled) 시스템이다.

    이런 느슨한 결합을 통해 Publisher나 Subscriber가 죽을 시, 서로 간에 의존성이 없으므로 안정적으로 데이터를 처리할 수 있다. 또한 설정 역시 간단하게 할 수 있다는 장점이 있다.

     

     또, 이 모델은 topic에 입력된 데이터를 여러 consumer가 서로 다른 처리를 하기 위해 여러 번 가져올 수 있는 데이터 분포 모델이다. consumer가 broker로부터 메시지를 직접 가져가는 pull방식(=polling 구조)으로 동작하기 때문에 consumer는 자신의 처리 능력만큼의 메시지만 가져와 최적의 성능을 낼 수 있다. 이는 대용량 처리에 특화되어 있다고 할 수 있다.

     

     

    Broker(Kafka)

    Topic과 Partition

    일단, 메시지는 topic으로 분류되고, topic 여러 개의 파티션으로 나눠 질 있다. 하나의 토픽에 여러 개의 consumer 각각 다른 목적으로 존재한다.

     

     파티션내의 칸은 로그라고 불리고, 데이터는 칸의 로그에 순차적으로 추가된다. 추가된 메세지의 상대적인 위치를 나타내는게 offset이다. offset 소비를 했다는 표시이고, topic안에 있는, 파티션에 존재하는 offset 위치를 통해서, 이전에 소비했던 offset위치를 기억하고 관리한다. 이러한 특징 덕분에 Consumer 죽었다가 다시 살아나도, 이전에 마지막으로 읽었던 위치부터 다시 읽어들일 있다. 그렇기 때문에 fail-over 대한 신뢰가 존재한다.

     

     하나의 토픽에 여러 개의 파티션을 나눠서 메세지를 쓰는 이유는 메세지가 Kafka의 해당 토픽에 쓰일 때, 쓰는 과정도 시간이 소비된다. 천건의 메세지가 동시에 Kafka에 쓰여진 하나의 파티션만 있다고 생각해보면, 메세지가 하나의 파티션에 순차적으로 추가될 텐데, 처리하는데에 오래 걸리고 버거워진다. 따라서 여러 개의 파티션을 두어서 분산저장을 하는 것이다. 그러면 쓰는 처리가 병렬로 처리되기 때문에 시간이 그만큼 절약하게 된다. 하지만 늘린 파티션은 절대로 줄일 없기 때문에, 운영 중에 파티션을 늘려야 하는건 조심해야한다.

     


    Consumer

    consumer는 consumer API와, consumer API로 구성된 애플리케이션을 말한다. 엄밀하게 말해서, consumer는 kafka cluster의 구성요소가 아니다. 쉽게 생각해서 kafka cluster와 연결되어있다고 볼 수 있다.

    일반적으로 consumer가 토픽을 구독(Subscribe) 혹은 읽는다(Read)고 하는데, 이는 consumer가 토픽 파티션에 저장된 메시지들을 가져오는 것을 말한다. Kafka consumer는 더욱 효율적이고 유연한 메시지 구독을 위해 3가지 특징을 가지고 있다. 

     

     

    Polling 구조

     첫 번째는 polling 구조(pull방식)이다. 일반적으로 다른 메시징 큐는 메시지 큐에서 메시지를 Push 한다. 이걸 Kafka로 예를 들면 broker가 consumer로 메시지를 보내는 방식이다.

    하지만 이런 Push 방식의 가장 큰 단점은 메시지 큐가 consumer의 처리 성능을 염두해야 한다. 즉, 메시지 큐가 consumer로 메시지를 Push 할 때 consumer 환경, 처리 능력을 고려해야 한다.

     

     하지만 Kafka는 consumer가 broker로부터 메시지를 요청하는 Polling 구조로 설계되었다. 즉, consumer는 자신이 원하는 만큼의 메시지를 broker로 요청한다. 

    이러한 구조의 가장 큰 장점은 각 consumer가 자신의 환경에 메시지 구독 성능을 최적화할 수 있다는 것이다. 추가로 broker는 consumer가 요청하는 것만큼 메시지를 전달해주면 되기 때문에 더 이상 consumer의 환경을 고려할 필요가 없다. 

     

     

    단일 토픽의 멀티 consuming

     

    여러 서비스 앱에서 동일한 토픽을 구독할 수 있다.

    하나의 토픽에 서로 다른 consumer 애플리케이션이 동시에 구독할 수 있다.

    위 그림에서처럼 하나의 토픽(Topic A)을 consumer App 1과 App 2이 동시에 구독할 수 있다.

    이렇게 단일 토픽에 대한 멀티 cunsuming이 가능한 이유는 consumer가 메시지를 읽을 때 broker의 메시지가 삭제되는 것이 아니고, 각 consumer가 어느 토픽 파티션의 어느 오프셋까지 읽어갔는지 consumer 오프셋(__consumer_offset)이라는 토픽에 저장되기 때문에 독립적으로 구독할 수 있다. 

     

     

    consumer 그룹

    다음 특징은 consumer 그룹이다. 

    broker는 하나의 토픽을 여러 파티션으로 병렬 구성하여 처리하며 성능을 높인다. 하지만 둘 이상의 파티션을 하나의 consumer로만 처리한다면 성능 상의 문제가 발생할 수 있다.

    그래서 Kafka consumer는 하나 이상의 consumer가 Consumer Group을 구성하여 하나의 토픽을 구독할 수 있다.

    하나의 토픽 내에 여러 파티션을, 한 컨슈머 그룹 내에 여러 컨슈머가 컨슈밍한다.

    consumer 그룹 내의 consumer는 토픽 파티션의 소유권을 나눠 갖는다. 

    예를 들어, 위 그림은 파티션 4개로 이루어진 토픽을, 3개의 consumer가 consumer 그룹을 구성하여 구독하는 모습이다. consumer 0은 파티션 0의 소유권을 가지고 구독한다. 마찬가지로 consumer 1은 파티션 1과 2의 소유권을 가지고 구독한다. 이처럼 같은 consumer 그룹의 consumer들은 소유권을 가진 파티션만 구독한다.

     

    consumer 그룹은 하나의 topic 대한 책임을 갖고 있다.

    어떤  그룹내의 consumer가 down되는 상황으로 예를 들면, 만약 down 된 consumer 원래 파티션1에 대해서 소비를 맡았을때, 더 이상 파티션1에 대한 소비를 없는 상황이다. 이런 상황에선 Rebalance 일어난다.

     

    Rebalance 가용한 consumer 사이에 에서 파티션을 재조정해주는 작업이다.

    offset 정보를 그룹내에서 서로 간의 공유하고 있기 때문에, 파티션 재조정을 통해서 다른 consumer가 파티션1의 소비를 이어서 하게 된다. down 직전의 offset위치를 알고 그 다음부터 소비하면 문제가 없어지는 것이다.

     

    Consumer group 반드시 해당 topic 파티션이 consumer group consumer 1:n 매칭이 되야한다.

    파티션에 같은 그룹내의 여러 consumer가 매칭될 없고, 만약에 파티션 수보다 consumer group내의 consumer 수가 많다면 파티션이 매칭되지 않은 consumer 아무것도 안하는 상태가 된다.

    반대로 consumer 여러 파티션을 담당할 있다. 그렇기 때문에 파티션을 늘릴 때는, Consumer 개수도 고려해야한다.

     


    Producer

     producer는 보통 Kafka producer API와 그 API로 구성된 애플리케이션을 말한다. producer 또한 kafka cluster의 구성 요소는 아니다.

    producer는 broker에 특정 토픽을 지정하여 메시지를 전달하는 역할을 담당한다. 즉, producer는 broker를 통해 메시지를 발행(Publish) 한다. 이 때 메시지를 전달할 대상을 명시하지는 않으며, 관련 메시지를 구독(Subscribe) consumer가 broker에게 요청하여 가져가는 방식이다.

     

    producer를 통해 전달되는 메시지의 구조

    메시지의 구조

    • 토픽(topic)
    • 토픽 내에 특정 파티션 위치 (partition)
    • 메시지 생성 시간(timestamp)
    • 메시지 키(key)
    • 메시지 값(value)

    이런 식으로 구성된다. 

     

     

    메시지 전달 과정

    producer는 4가지 과정을 통해 메시지를 broker로 전달한다.

    이 과정은 broker에 메시지를 전송할 수 있도록 변환하거나, 필요한 값을 지정해주는 과정이다.

    1.     직렬화 (Serializer)

    2.     파티셔닝 (Partitioner)

    3.     메시지 배치 (Record Accumulator)

    4.     압축 (Compression)

    5.     전달 (Sender)

    메시지가 broker로 전달되는 과정

    직렬화

    producer는 먼저, 전달 요청 받은 메시지를 직렬화 한다. 직렬화(Serialization)는 Serializer가, 지정된 설정을 통해 처리하며, 메시지의 키와 값을 바이트 뭉치 형태로 변환한다.

     

    파티셔닝 및 메시지 배치

    직렬화 과정을 마친 메시지는 Partitioner를 통해 토픽의 어떤 파티션에 저장될지 결정되는데, 이 과정을 파티셔닝(Partitioning)이라 말한다. Partitioner는 정의된 로직에 따라 파티셔닝을 진행하는데, 별도의 Partitioner 설정을 하지 않으면, 파티션들에게 골고루 전달할 수 있도록 파티셔닝을 하는 Round Robbin 형태로 파티셔닝을 한다.

    다만, 이 과정은 메시지 전달 요청에 파티션이 지정되지 않았을 경우에만 진행된다. 따라서 메시지 전달 요청에 특정 파티션이 지정되었을 경우에는 별도의 파티셔닝 없이 해당 파티션으로 전달되도록 지정되는 것이다.

     

    압축

    만약 메시지 압축이 설정되었다면, 설정된 포맷에 맞춰 메시지를 압축한다. 압축된 메시지는 broker로 빠르게 전달할 수 있을뿐더러, broker 내부에서 빠른 복제가 가능하도록 한다. 그렇게 때문에 메시지 압축 설정은 많은 경우에 고려될 수 있다. 압축 형식은 LZ4. gzip, snappy 등이 있다.

     

    전달

    파티셔닝과 압축을 마친 후, producer는 메시지를 TCP 프로토콜을 통해 broker 리더 파티션으로 전송한다.

    하지만 네트워크 전송은 매우 무거운 작업이기 때문에 메시지마다 매번 네트워크를 통해 전달하는 것은 비효율적이다.

    그래서 producer는 지정된 만큼 메시지를 저장했다가 한 번에 broker로 전달한다. 이 과정은 batch processing이라고 하며, producer 내부의 Record Accumulator(RA)가 담당하여 처리한다. RA는 각 토픽 파티션에 대응하는 배치 큐(Batch Queue)를 구성하고 메시지들을 레코드 배치(Record Batch) 형태로 묶어 큐에 저장한다.

     

    각 batch 큐에 저장된 레코드 batch들은 때가 되면 각각 broker에 전달된다. 이 과정은 Sender가 처리한다. Sender는 스레드 형태로 구성되며, 관리자가 설정한 특정 조건에 만족한 레코드 batch를 broker로 전송한다. 이때, Sender 스레드는 네트워크 비용을 줄이기 위해 piggyback 방식으로 조건을 만족하지 않은 다른 레코드 배치를 조건을 만족한 것과 함께 broker로 전송한다. 

    같은 broker로 보내야하는 토픽 파티션이 있으면 함께 전송

    여기서 Piggyback이란 '등 뒤에 업다'라는 뜻이다.

    위 그림을 예로 들면, 토픽 B의 파티션 1(B_1)의 큐에 레코드 batch가 전송할 조건을 만족했다고 가정했을 때, Sender는 해당 레코드 batch를 가져와 3번 broker로 전송할 준비를 한다.

    이때, 토픽 A의 파티션 2(A_2)가 전송 조건을 만족하지 않았더라도 같은 3번 broker에 전송돼야 하므로, Sender는 A_2 레코드 batch를 업어 한번에 3번 broker로 전송한다. 

    이로 인해 자연스럽게 네트워크 비용을 줄일 수 있다고 한다.

     

    Sender 스레드의 메시지 전송 요청과 응답

    broker에 네트워크 전송 요청을 보낸 Sender는, 설정해둔 값에 따라 broker의 응답을 기다리거나 혹은 기다리지 않는다. 이는 producer 설정 값 중 Acks와 관련이 있다.

    (Acknowledgments: producer가 메시지를 보내고, 그 메시지를 kafka가 잘 받았는지 확인할지 말지 결정하는 옵션)

     

    만약 응답을 기다리지 않는 설정인 경우, 메시지 전송에 대한 과정이 끝난다.

    하지만 응답을 기다리는 경우, 메시지 전송 성공 여부를 응답으로 받는다. 이때, broker에서 메시지 전송이 실패한 경우에는, 설정해둔 재시도 횟수에 따라 재시도한다. 재시도 횟수를 초과한 경우에는 예외로 처리한다.

    반대로 성공한 경우에는 메시지가 저장된 정보(메타데이터)를 반환한다. 저장된 정보에는 메시지가 저장된 토픽, 파티션, 오프셋, 타임스탬프 정보를 가지고 있다.

     


    Broker(Kafka)

    Kafka Broker는 Producer와 Consumer 사이에서 메시지를 중계한다

    Kafka Broker는 일반적으로 'Kafka'라고 불리는 시스템을 말한다.

    Producer와 Consumer는 별도의 애플리케이션으로 구성되는 반면, Broker는 Kafka 자체이다.

    따라서 'Kafka를 구성한다' 혹은 'Kafka를 통해 메시지를 전달한다'에서 Kafka는 Broker를 의미한다.

     

    Broker 내부 동작 요소

    Kafka Broker는 Producer로부터 메시지를 발행받아 이를 저장하고, consumer로 전달한다.

    이 과정을 위해 Broker 내부에는 다양한 동작 요소들이 존재한다.

     

    컨트롤러

    컨트롤러(Controller)는 한 클러스터에서 하나의 Broker에 부여되는 역할로, 마치 지휘자와 같은 역할을 한다.

    컨트롤러는 나머지 Broker들의 생존 여부(liveness)를 체크한다.

    그리고 만약 임의의 Broker가 중단되었을 경우, 해당 Broker에 있었던 리더 파티션을 탈락시키고 다른 팔로워 파티션들 중 하나를 리더로 뽑는다(leader election). 

     

    컨트롤러가 중단되는 경우에는 주키퍼가 이를 감지하여 새로운 컨트롤러를 선출한다. 이 과정은 cunsuming의 fail-over(실패 극복) 전략 중 중요한 부분이다.

    (주키퍼는 kafka cluster를 구축할 때 꼭 필요한 요소이다. kafka의 상태를 확인하고 문제 발생 시 재조정하는 역할을 수행한다. 이후 설명 참고.)

     

     

    메시지 저장과 메시지 파일 관리

    Broker는 Producer로부터 전달되는 메시지를 로그(log) 형태로 디스크에 저장한다.

    로그는 새로운 쓰기 작업이 중간에 삽입되지 않고, 오로지 끝에서만 삽입되는 (append-only) 특징을 가진다. 쓰기 작업이 끝에서만 이뤄지므로 Broker에 이미 쓰인 메시지(로그)는 변경이 불가하다. 하지만 빠른 쓰기 작업이 가능해진다.

    Broker 파티션에 메시지를 쓰고 읽는 모습  

    각 네모 칸은 메시지를 나타내며, 숫자는 오프셋을 나타낸다. 쓰기 작업은 오직 끝에서만 진행되며, 오프셋은 메시지 삽입에 따라 순차적으로 증가한다

    Producer는 오직 끝에만 쓰며, consumer는 오프셋을 기준으로 차례차례 읽어나간다

     

     

    Kafka(Broker) clsuter 구성요소

     

     Broker는 한 대 이상의 노드로 클러스터를 구성할 수 있다. 이때 Broker의 여러 가지 메타 정보를 저장 관리해주는 주키퍼(Zookeeper)가 필요하다.

    Kafka를 구성할 때는 한 대 이상의 주키퍼로 구성된 주키퍼 클러스터와, 한 대 이상의 Broker로 구성된 Broker(Kafka) 클러스터로 구성된다.

    주키퍼(Apache ZooKeeper)

    주키퍼는 현재 Kafka에 필수적이다. 주 역할은 분산 시스템의 메타 정보를 관리하고, 필요시에는 분산 시스템의 마스터를 선출한다. 

    예를 들면, Kafka 클러스터를 구성하면 주키퍼에는 Kafka 클러스터의 식별 정보부터 현재 살아있는 Broker 정보, 나아가 권한 정보 등이 저장된다. 또한, Kafka Broker들 중 Controller Broker를 뽑는 역할을 담당한다.

     

    동일한 주키퍼 클러스터에 멀티 Kafka 클러스터를 구성할 수 도 있다.

     

     

    bootstrap

     Bootstrap 설정은, consumer, producer가 접근하려는 토픽 파티션의 메타데이터를 요청하기 위한 설정이다.

    개별 Broker는 클러스터 전체 데이터를 가지고 있지 않기 때문에 클라이언트(consumer, Producer)는 Broker와 연결하여 Broker 내부의 자원에 접근하기 위해, 클라이언트가 접근하고자 하는 자원의 위치를 알아야 한다. 

     

    위 그림을 예로, Producer가 토픽 1의 파티션 1(topic1-partition1)에 메시지를 발행하려면 Producer는 해당 토픽 파티션이 전체 Broker 클러스터 중 몇 번 Broker에 위치하는지 알아야 한다.한다.

    따라서 Kafka는 클라이언트가 Kafka와 처음 연결될 때, 자원들의 메타데이터를 공유하기 위해 bootstrap.servers 설정을 요구하게 된다. 

     

    bootstrap.servers 설정은 클라이언트가 접근하는 토픽 파티션의 메타데이터를 요청하기 위한 설정이다. 하지만 입력되는 설정 값은 클러스터의 모든 브로커 호스트일 필요가 없다. 이는 설정 값의 호스트 정보를 기준으로 순차적으로 메타데이터를 요청하고, 만약 성공할 경우에는 그 메타데이터를 이용하기 때문이다.


    Kafka의 특징

     

    다중 producer, 다중 consumer

    Kafka의 토픽에 여러 producer가 동시에 메시지를 전송할 수 있다. 마찬가지로 Kafka 토픽의 메시지를 여러 consumer들이 동시에 읽어 갈 수 있다.

    뿐만 아니라 하나의 producer가 여러 토픽에 메시지를 전송할 수도 있으며, 하나의 consumer가 여러 토픽에서 메시지를 읽어 갈 수도 있다.

    특히 하나의 메시지를 여러 consumer가 읽어 갈 수 있는 면이 Kafka의 큰 강점으로 작용한다.

    이러한 다중 producer, 다중 consumer 시스템 덕분에, 하나의 Kafka 시스템을 통해 다양한 애플리케이션이 데이터를 주고받을 수 있게 되었으며, 데이터의 생산자/소비자 관계도 유연하게 구성할 수 있게 되었다.

     

     

    고가용성(high availability) 및 확장성(scalability)

     Kafka는 수평적인 확장(scale horizontally, scale out)을 위해 클러스터를 구성한다.

    Kafka를 통해 유통되는 메시지가 늘어나면 Kafka broker의 부담(Load)이 증가하게 되어 클러스터의 규모를 확장할 필요가 있다. Kafka는 여러 broker들의 클러스터링을 위해 사용하는 아파치 주키퍼를 통해 broker의 추가 및 장애 상황을 간단하게 대응할 수 있다.

     

    그리고 Kafka 클러스터 위에서 producer가 전송한 메시지는 여러 broker들을 통해 중복 저장이 된다. 이를 Replication이라고도 하고, 메시지들이 replication 되어 장애 상황에서도 고가용성(High Availability)을 보장하게 된다.

     

    상황을 예로 들어 설명해보면,

    Broker 3대가 띄워졌다고 가정하고, 3개의 파티션이 동일하게 3개의 Broker로 복제되는 경우, broker 3대 중에서 하나만 leader가 되고, 나머지 둘은 follower 가 된다.

    producer가 메시지를 쓰고, consumer가 메세지를 읽는 건 오로지 leader가 전적으로 역할을 담당한다.

    나머지 follower들은 leader와 싱크를 항상 맞추다가 혹시나 leader가 죽었을 경우, 나머지 follower 중에 하나가 leader로 선출되어서 leader의 역할을 수행한다.

    따라서 만약 한 broker에 장애가 생기더라도 중복 저장된 복사본을 consumer에게 전달할 수 있으므로 장애 상황에 대비할 수 있다.

     

     

    디스크 순차 저장 및 처리(sequenctial store and process in disk)

     메세지를 메모리 큐에 적재하는 기존 메세지 시스템과 다르게 Kafka는 메세지를 디스크에 순차적으로 저장다.

    이로서 얻는 이점은

     

    1. 서버에 장애가 나도 메시지가 디스크에 저장되어 있으므로 유실 걱정이 없다.

    2. 디스크가 순차적으로 저장되어 있으므로 디스크 I/O가 줄어들어 성능이 빨라진다.

     

    분산처리

     분산처리가 가능하다는 것도 특징이다.

    Kafka는 파티션(Partition)이란 개념을 도입했기 때문에 여러 개의 파티션을 서버들에 분산시켜 나누어 처리할 수 있다. 이로서 메시지를 상황에 맞추어 빠르게 처리할 수 있다.

     


     

    출처 및 참고

    https://always-kimkim.tistory.com/entry/kafka101-producer

    https://engkimbs.tistory.com/691 

    https://www.linkedin.com/pulse/kafka-consumer-overview-sylvester-daniel
    https://always-kimkim.tistory.com/entry/kafka101-consumer 

    https://www.linkedin.com/pulse/kafka-producer-overview-sylvester-daniel

    https://mapr.com/ebooks/streaming-architecture/chapter-04-apache-kafka-overview.html

    https://engineering.linecorp.com/ko/blog/how-to-use-kafka-in-line-1/

    https://always-kimkim.tistory.com/entry/kafka101-configuration-bootstrap-servers

     

JackCokebb dev blog