ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SLASH23 시청 및 정리
    개발하면서/타인글보면서 2024. 8. 16. 15:00
    반응형

    오래간만에 개발자 행사 영상을 찾아보았다.

    토스 SLASH23에 발표된 영상 중 개인적으로 관심 가는 영상 3개를 시청하고 정리했다.

    회사에서 처리량 올리는 게 필요해서 그런지 세 번째 발표가 재밌었다. 실제 해볼 만한 것도 많았다.

    https://toss.im/slash-23

     

    1. 머신러닝으로 더 똑똑하게 증권 뉴스 제공하기

    https://www.youtube.com/watch?v=dnxaTrKJr0c

     

    종목 매칭 모델

    본인이 투자하거나 관심 있는 종목의 뉴스만 본다.

    유저에게 제공하는 뉴스는 언론사로부터 받는데 두 가지 문제점이 있다.

    1. 모든 뉴스에 대해서 종목 매칭을 해서 제공하지 않는다
    2. 부정확한 종목 매칭이 된다.

    Classification Model을 구축하기 위해 RoBERTa, ELECTRA, BERT 등을 실험했고 최종적으로 BERT를 선택했다.

     

    모델 학습하는 데 사용하는 데이터셋은 언론사에서 제공하는 뉴스를 사용하는데 종목 매칭이 하나 이상 된 경우만 데이터셋으로 사용했다.
    모델이 판단하기 어려운 Hard Negative Sample이 존재했기 때문이다.

     

    하지만 더욱 다양한 학습을 위해 Unlabeled 데이터셋(종목매칭이 하나도 되지 않은 뉴스) 중에서
    Informative 한 데이터셋을 선택하는 방법인 Active Learning 방법론을 사용했다.

     

    종목마다 매칭 난이도는 달라서 종목별 난이도 스코어를 Acquisition Function에 추가했다. 삼성전자와 삼진

    난이도 계산은 데이터셋과 실제 예측값의 비율로 사용했다.

     

    신규 상장 종목들의 뉴스도 주기적으로 학습해야 하므로 자동화 pipeline이 필요해서 Argo Workflow로 구축했다.

     

    뉴스 중요도 측정 모델

    널리 쓰이는 방법은 각 뉴스의 CTR 기반으로 뉴스 추천하는 방법인데 데이터의 신뢰도가 쌓일 때까지 시간이 걸린다.

    하지만 주식투자를 위한 뉴스는 시의성이 중요하다.

    주식 특성상 뉴스 발행 당시의 주가 흐름을 보고 중요도를 판단했다.

     

    해외 뉴스 모델 구축하기

    mBART 활용, AIHub에 공개한 말뭉치를 활용했는데 AiHub 데이터는 영어 금융 명사는 학습하기 어렵다.

     

    2. 프로파일러로 시스템 성능 향상시키기

    https://www.youtube.com/watch?v=tZjjqhnwtYY

     

    1. Pinpoint 이용사례

    Spring cloud config를 이용해서 설정값을 가져오는데 응답이 느린 경우가 있었다.

    암호화된 필드를 모두 복호화하는 걸 발견했고 단일 스레드를 멀티스레드로 변경했다.

     

    2. Heapdump 이용사례

    Dominator Classes 확인 & MAT OQL로 세부 데이터 확인했다.

     

    3. Jemalloc 이용사례

    컨테이너에 할당된 메모리 양보다 더 많이 사용하려는 경우가 있다.

    Heap은 옵션으로 최대 사용량을 정할 수 있어 문제 되지 않고,

    Native Memory 사용량 증가가 문제가 된다.

    mmap은 Jemalloc으로 발견되지 않는다.

    옵션 설정
    LD_PRELOAD=/usr/lib/libjemalloc.so
    MALLOC_CONF=options
    
    시각화
    jeprof --show_bytes --pdf jeprof.heap

     

    4. Async-Profiler 이용사례

    JFR의 경우 IntelliJ -> Open Profiler Snapshot으로 확인 가능하다.

    . ElasticSearch date time 타입, Spring Cloud Gateway route

     

    5. Strace, Perf Trace 이용사례

    Redis 응답속도 개선 사례

     

    6. Unix Domain Socket 이용사례

    Istio는 총 3개의 커넥션 생성

    1. 요청 보내는 클라이언트와 Client-Side Proxy에 커넥션

    2. Client-Side Proxy와 Server-Side Proxy에 커넥션

    3. Server-Side Proxy와 Applicaiton server에 커넥션

     

    7. Binary Ninja 이용사례

    외부 라이브러리를 사용하다가 스스로 문제 원인을 파악하고 싶은 경우에 활용하면 좋다.

     

     

    3. 실시간 시세 데이터 안전하고 빠르게 처리하기

    https://www.youtube.com/watch?v=SF7eqlL0mjw

     

    거래소(KRX)에서 전문 데이터를 토스 증권에 끊임없이 보낸다.

     

    낮은 지연시간 + 빠른 장애복구가 최우선 목표로 삼고 있다.

     

    시세 플랫폼은 총 3가지 파트로 구성되어 있다.

    1. 수신부: 거래소가 제공하는 시세 데이터를 UDP 멀티캐스트 그룹에 접속해서 읽어오는 역할(수신시각을 Header에 포함)
    2. 처리부: 비즈니스 로직이 모여있는 곳, 처리 결과를 Redis에 저장하거나 실시간 정보를 서비스들에게 바로 전달
    3. 조회부: REST API를 서비스들에게 제공

    문제: 처리부가 장애 나면 모든 게 멈춰짐, 장애복구를 해도 데이터가 오염되었기 때문에 복구에 시간이 더 걸림

    해결: 처리부와 Redis replica 구성

     

    문제: 처리부가 replica로 구성되어 있는데 처리부가 다양한 서비스로 확장된다면 수신부의 성능 저하

    해결: 메시지 브로커 활용  (1. UDP multicast.  2. Kafka.   3. Redis Pub/Sub 고려했는데 Redis 선택(낮은 지연시간)

     

    처리부가 하는 일은 크게 두 가지로 나뉜다.

    하나는 TCP Socket으로부터 데이터 읽는 일이고, 다른 하나는 비즈니스를 처리하는 것이다.

    문제: TCP는 송신속도가 수신속도보다 빠른 경우 데이터 유실 되는 것을 방지하기 위해 수신 버퍼가 가득 차면 보내지 않는다.

    1. 수신자는 Socket 수신 버퍼를 기준으로 한 번에 받을 수 있는 양, Window Size를 송신자에게 보낸다.
    2. 송신자는 Window Size만큼의 데이터만 보내서 데이터 유실을 방지한다.

    해결: 수신버퍼가 가득 차는 것을 방지하기 위해 비즈니스 처리는 별도 Thread에게 위임한다.

     

    문제: 처리 성능을 높이기 위해 멀티 쓰레딩을 사용한다면 비즈니스 처리 순서가 역전될 수 있다.

    해결: 멀티 쓰레딩 대신 하나의 Thread만 사용하는 EventLoopGroup(NIO, Epoll, KQueue)을 사용한다.

     

    문제: 순서를 보장하기 위해 JSON을 객체로 변환하는 작업이 필요한데 NioEventLoop CPU 자원을 많이 사용한다.

    해결: 처리부의 EventLoop 개수만큼 Redis Channel을 나누고 처리부는 채널명을 보고 EventLoop를 찾는다.

       

    EventLoop 구현

    Spring에서 제공하는 ThreadPoolTaskExecutor의 corePoolSize = maxPoolSize = 1로 설정

    Queue가 꽉 찰 경우를 위한 정책은 DiscardOldestPolicy를 사용했다.

    queueCapacity는 서비스마다 다름

     

    EventLoopGroup 구현

    List<ThreadPoolTaskExecutor> 사용

    리스트 개수를 줄이기 위해 노력했는데 이는 EventLoop 개수를 의미하는데 늘어날 경우 Context Switching 비용이 증가하기 때문이다.

    그렇다고 너무 줄이면 EventLoop의 Backpressure가 발생해서 지연시간이 훨씬 늘어난다.

     

    문제: EventLoop 개수를 적절한 수준으로 줄이고 싶다.

    해결: Non-Blocking I/O 사용,   Local Cache 사용,   무거운 작업을 위한 별도 EventLoopGroup 사용

       

    문제: 처리량이 올라가지 않는다.

    해결: netstat -na | grep <port number> 또는 ss -t dst:<port number>

    Recv-Q > 0 지속적으로 크다면   
    1. NioEventLoop 확인 (데이터 변환, 객체 생성 혹은 로깅등 제거하거나 다른 Thread 위임)
    2. CPU Profiling
    3. NioEventLoop 여러 개 사용하기

     

     

     

    반응형

    댓글

Designed by Tistory.