실무에서 새로운 프로젝트에 참여 했을 때 JSON 형태로 데이터를 활용하자고 제안한 적이 있습니다.
1. 개요
이유
실무에서 새로운 프로젝트에 참여 했을 때 JSON 형태로 데이터를 활용하자고 제안한 적이 있습니다.
이 방법으로 여러 데이터 타입을 유연하게 분석할 수 있었습니다.
기존의 RDB 형태로 데이터를 Type별/컬럼별로 분리하여 관리하면, 신규 Type 추가 시마다 테이블 스키마 변경 및 업데이트 과정이 필요했습니다.
이는 데이터 지연 및 관리 복잡성 증가로 이어질 수 있었습니다.
반면, JSON 형식의 데이터를 그대로 클라우드 분석 플랫폼에 저장하고,
이를 Function 기능을 통해 실시간으로 분석 및 조회하도록 개선하면서 다음과 같은 이점을 확인할 수 있었습니다:
- 운영 효율성 증대: 원본 JSON 데이터를 유지함으로써 ETL 과정을 단순화할 수 있었고, 변환으로 데이터가 지연되는 문제를 방지할 수 있었습니다.
- 데이터 모델링의 유연성: 새로운 Type의 데이터가 추가되어도 스키마 변경 없이 수용할 수 있어, 여러 스키마를 빠르게 분석 할 수 있었습니다.
- 쿼리 성능 향상: 필요한 주요 로그만 변환 및 추출하도록 Function을 활용하였고, 쿼리 속도가 개선되었고, 데이터 처리 효율성도 높아졌습니다.
- 향후 분석 가능성 증가: 구조화된 RDB 형태보다 JSON 형식의 반구조화 데이터를 그대로 사용함으로써, 추후 로그 데이터의 다양한 분석에 활용하기에도 용이했습니다.
이 경험을 계기로 NoSQL 기반의 유연한 데이터 구조가 빠르게 변화하는 요구 사항에 더 효과적으로 대응할 수 있음을 깨닫게 되었고,
NoSQL 중 하나인 MongoDB를 실습해 보고자 해당 프로젝트를 진행 하게 되었습니다.
목표
API 데이터를 배치 방식으로 수집하여 MongoDB에 저장하고, 이 데이터를 제한 없이 통합하여 제공하는 것이 목표입니다.
MongoDB의 장점인 유연한 스키마를 활용해 보고자 진행되었습니다. (각 데이터의 구조가 유동적이라고 가정)
MongoDB의 Document 모델 덕분에 스키마 변경 없이 다양한 형식의 데이터를 쉽게 저장하고 관리할 수 있습니다.
2.구조
시스템 아키텍처

- News API: 각 신문사의 뉴스 데이터를 수집합니다. (https://newsapi.org/ )
- Fluentd: 수집된 뉴스 데이터를 배치 방식으로 수집하고 전달합니다.
- MongoDB: Fluentd에서 전달된 뉴스 데이터를 저장합니다.
- Streamlit: MongoDB에 저장된 데이터를 활용하여 사용자에게 통합 뉴스 피드 페이지를 제공합니다.
3. 구현 과정
3.1. NewsAPI와 Fluentd 로 데이터 수집하기

Fluentd는 원하는 기능들을 플러그인 방식으로 설정 파일에 추가함으로써 사용할 수 있다.
전체적인 동작 흐름은 Input -> Filter -> Buffer -> Output 단계로 동작하며, 세부적으로 7개의 플러그인
(Input, Parser, Filter, Formatter, Storage, Buffer, Output)을 목적대로 자유롭게 활용할 수 있다.
아래서는 td-agent (Treasure Data에서 제공하는 Fluentd의 상용 패키지 버전) 사용합니다.
* td-agent는 Fluentd와 거의 동일한 기능을 제공하면서도 사용자 편의를 위해 몇 가지 개선 사항과 추가 기능을 포함하고 있어, 설치 및 관리가 더 쉽습니다.
* Fluentd는 원래 Ruby Gem 형태로 배포되어, 시스템에 Ruby 환경 설정이 필요합니다. 반면 td-agent는 Ruby 설치 없이 실행 가능합니다.
brew install td-agent # td-agent 설치
sudo /opt/td-agent/usr/sbin/td-agent-gem install fluent-plugin-mongo # 몽고디비 플러그인 설치

간단한 출력 테스트 를 위해 아래 쿼리를 설정파일에 붙여 넣습니다.
<system>
<log>
rotate_age 30
</log>
</system>
<source>
@type exec
@id input_exec_newsapi
command curl --ssl-no-revoke -X GET "https://newsapi.org/v2/top-headlines?country=us&apiKey=mykey"
tag "newsapi"
format json
run_interval 5m # 5분마다 실행
</source>
<filter newsapi>
@type record_transformer
enable_ruby true
<record>
# 상단 데이터 2개 출력
top_article ${record["articles"][0,2]}
</record>
remove_keys articles
</filter>
<match newsapi>
@type stdout
format json
</match>
실행 해봅시다.
sudo vi /etc/td-agent/td-agent.conf # 설정 파일 열기
/opt/td-agent/usr/sbin/td-agent -c /etc/td-agent/td-agent.conf # 기본 foreground로 실행하기
(또는 sudo launchctl start td-agent # 서비스 시작 : 로그가 /var/log/td-agent/td-agent.log에 남겨진다.)

3.2 MongoDB에 적재하기
다시 설정 파일을 열어 몽고 디비 연결로 수정해 줍니다.
해당 API 에서 추출할 컬럼을 정리해 <filter> 에 지정해 줍니다.
<system>
<log>
rotate_age 30
</log>
</system>
<source>
@type exec
@id input_exec_newsapi
format json
command curl --ssl-no-revoke -X GET "https://newsapi.org/v2/top-headlines?country=us&apiKey=myKey"
tag "newsapi"
run_interval 5m
</source>
<filter newsapi>
@type record_modifier # 인코딩 오류로 변경
char_encoding utf-8
# 원하는 컬럼을 지정
<record>
source ${record["articles"][0]["source"]}
author ${record["articles"][0]["author"]}
title ${record["articles"][0]["title"]}
description ${record["articles"][0]["description"]}
url ${record["articles"][0]["url"]}
urlToImage ${record["articles"][0]["urlToImage"]}
publishedAt ${record["articles"][0]["publishedAt"]}
content ${record["articles"][0]["content"]}
</record>
remove_keys status, totalResults, articles
</filter>
<match newsapi>
@type mongo
host mymongo_host
port 27017
database dbname
collection mycollectionname
# authentication
user user
password password
</match>
만약, mongodb atlas 클라우드 DB 사용 시에는 아래 처럼 연결해야 합니다.
<match newsapi>
@type mongo_replset
connection_string mongodb+srv://user:pass@cluster.mongodb.net/yourdb
replica_set atlas-xxxxx-shard-0
collection articles
ssl true
ssl_cert /tmp/tls/self-generated-cert.crt
</match>

3.3. streamlit 으로 뉴스 피드 페이지 보여주기
MongoDB 에 삽입된 데이터를 streamlit 페이지에 간단한 메시지로 가져옵니다.
추가로 임의의 다른 스키마 데이터를 삽입한 경우에도 통합하여 알림을 받을 수 있음을 확인 할 수 있습니다 !


4. 오류 해결
1.
td-agent-gem install fluent-plugin-mongo 실행시
current directory: /opt/td-agent/lib/ruby/gems/2.7.0/gems/bson-4.15.0/ext/bson
/opt/td-agent/bin/ruby -I /opt/td-agent/lib/ruby/2.7.0 -r ./siteconf20241106-88442-17z75qm.rb extconf.rb
creating Makefile
current directory: /opt/td-agent/lib/ruby/gems/2.7.0/gems/bson-4.15.0/ext/bson
make "DESTDIR=" clean
current directory: /opt/td-agent/lib/ruby/gems/2.7.0/gems/bson-4.15.0/ext/bson
make "DESTDIR="
compiling bytebuf.c
compiling endian.c
compiling init.c
compiling libbson-utf8.c
compiling read.c
read.c:142:5: warning: variable 'result' is used uninitialized whenever switch default is taken [-Wsometimes-uninitialized]
default:
^~~~~~~
read.c:146:10: note: uninitialized use occurs here
return result;
^~~~~~
read.c:131:15: note: initialize the variable 'result' to silence this warning
VALUE result;
^
= 0
1 warning generated.
compiling util.c
compiling write.c
linking shared-object bson_native.bundle
ld: warning: -multiply_defined is obsolete
ld: warning: ignoring duplicate libraries: '-lruby.2.7'
current directory: /opt/td-agent/lib/ruby/gems/2.7.0/gems/bson-4.15.0/ext/bson
make "DESTDIR=" install
make: /opt/homebrew/bin/gmkdir: No such file or directory
make: *** [.sitearchdir.time] Error 1
make install failed, exit code 2
Gem files will remain installed in /opt/td-agent/lib/ruby/gems/2.7.0/gems/bson-4.15.0 for inspection.
Results logged to /opt/td-agent/lib/ruby/gems/2.7.0/extensions/arm64-darwin-21/2.7.0/bson-4.15.0/gem_make.out
fluent-plugin-mongo 설치 중 발생한 오류는 주로 네이티브 확장을 빌드하는 과정에서 문제가 발생했음을 나타냅니다.
특히 make: /opt/homebrew/bin/gmkdir: No such file or directory 메시지는 GNU make를 찾을 수 없어서 발생하는 문제입니다.
⇒ 해결 방법: brew install coreutils 설치
2.
2024-11-10 00:27:06 +0900 [warn]: #0 got unrecoverable error in primary and no secondary error_class=Encoding::UndefinedConversionError error="\"\\xE2\" from ASCII-8BIT to UTF-8"

fluentd 에서 수집시 인코딩 문제입니다. 아래 링크에도 관련 내용이 나와 있습니다.
https://docs.fluentd.org/quickstart/faq#i-got-encoding-error-inside-the-plugin-how-to-fix-it
<filter newsapi>
@type record_modifier
char_encoding utf-8
</filter>
⇒ 해결 방법: record_modifier로 대체하여 사용
3.
[warn]: #0 emit transaction failed: error_class=Fluent::Plugin::Buffer::BufferChunkOverflowError error="a 17256 bytes record (nth: 0) is larger than buffer chunk limit size (10240)" location="/opt/td-agent/lib/ruby/gems/2.7.0/gems/fluentd-1.16.3/lib/fluent/plugin/buffer.rb:457:in `write'" tag="newsapi"
<buffer>
# 버퍼 크기 증가
chunk_limit_size 50m # 각 버퍼 조각의 최대 크기
total_limit_size 200m # 전체 버퍼의 최대 크기
</buffer>
⇒ 해결 방법: 버퍼 크기 증가
4.
W, [2024-11-06T02:50:04.231519 #92158] WARN -- : MONGODB | Error checking cluster.xxxxxx.mongodb.net/?readpreference=nearest:27017
: SocketError: getaddrinfo: nodename nor servname provided, or not known
[error]: #0 unexpected error error_class=ArgumentError error="Host 'mongodb://myuser:mypassword@cluster.xxxxxx.mongodb.net/:27017'
should not contain protocol. Did you mean to not use an array?"
소켓 에러 또는 host 명 오류
저 같은 경우는 mongodb atlas 클라우드 DB 사용했기 때문에 일어났습니다.
해당 연결에 따라 @type을 지정해 줍니다.
⇒ 해결 방법: @type mongo → @type mongo_replset
참고 :
https://jangseongwoo.github.io/fluentd/fluentd_install/
https://my-trash-code.tistory.com/71
마침.
'4. Project > ㅤ📝 개인 프로젝트' 카테고리의 다른 글
| AI Project Control Board 구축 하기 (0) | 2026.07.06 |
|---|---|
| 구글 Antigravity 활용하여 뉴스피드 대시보드 생성하기 (0) | 2026.07.06 |
| Fluentd + MongoDB 통합 뉴스 피드 구축(2) (1) | 2024.11.30 |