엣지 게이트웨이: Node-RED·Telegraf·NiFi로 현장 데이터 라우팅
📍 현재 위치: 제2부 "공정 포착하기"입니다. 신호는 이미 생물반응기(bioreactor)에서 OPC UA로 빠져나와 MQTT 브로커(broker)에 도착했습니다(이전 장). 이제 우리는 그 데이터를 수집하고, 변환하고, 다음 단계로 라우팅하는 게이트웨이(gateway)를 구축하고, 세 가지 오픈소스 도구 중 어느 것이 그 일을 맡을지 결정합니다.
엣지 게이트웨이를 **공장의 우편실(mailroom)**이라고 생각해 보세요. 현장 곳곳의 센서들이 봉투(측정값)를 끊임없이 떨어뜨립니다. 우편실은 그것들을 분류하고, 이상한 형식으로 도착한 것은 다시 라벨을 붙이며, 어느 봉투를 어느 부서로 보낼지 정하고, 그리고 결정적으로 자신이 다룬 모든 봉투에 대한 기록부를 유지합니다. 엉성한 우편실은 우편물을 잃어버립니다. 규제(regulated) 우편실은 몇 달이 지난 뒤에도 정확히 어느 봉투를, 언제, 어디에서 받았고, 어디로 보냈는지를 말해 줄 수 있습니다. 이 장에서는 세 종류의 우편실을 만들고, 각 작업에 맞는 올바른 우편실을 고릅니다.
엣지 게이트웨이는 플랫폼 전체의 단층선 위에 자리합니다. OT(운영 기술, operational technology — 공정을 구동하는 제어기, 스키드(skid), 센서)와 IT(이를 의미 있게 만드는 데이터베이스, 대시보드, 분석)가 만나는 이음매입니다. OT 쪽에서 데이터는 OPC UA와 Modbus로 말하며 격리된 제어 네트워크 위에 살고, IT 쪽에서는 MQTT, SQL, HTTP로 말합니다. 무언가가 그 중간에 서서, 검증된(validated) 제어 루프(control loop)는 결코 건드리지 않으면서 통역하고, 버퍼링하고, 라우팅해야 합니다. 그 무언가가 바로 게이트웨이이며, 이것을 제대로 해내는 것이 규제 기관에 제출할 수 있는 데이터와 그저 완전하기를 바라는 데이터 사이의 차이를 만듭니다.
이 장에서 다루는 내용
- OT/IT 가교가 왜 존재하며, 게이트웨이가 그 이음매에서 무엇을 해야 하는지.
- 우리가 출하하는 세 가지 오픈소스 도구 — Node-RED(로우코드 플로우), Telegraf(선언적 수집), Apache NiFi(보장된 전달 + 재현 가능한 출처 정보) — 와 각각이 진정으로 잘하는 일.
- 이들이 브로커에서 히스토리안(historian,
ts.sensor_reading)과 배치 모델(batch model)로 데이터를 어떻게 라우팅하는지, 실제로 보게 될 롱 포맷(long-format) 행과 함께. - 솔직한 부분: 전달 의미론(at-least-once 대 exactly-once), 감사 추적(audit-trail)의 공백, 그리고 OSS 게이트웨이가 검증된 진실의 기록(record-of-truth)으로 작업을 넘기는 지점.
이음매: 게이트웨이가 실제로 하는 일
게이트웨이는 데이터베이스도 아니고 대시보드도 아닙니다. 그 역할을 압축하면 사우스바운드–변환–노스바운드(southbound–transform–northbound) 파이프라인입니다. 사우스바운드로는 현장 프로토콜을 말합니다. 생물반응기가 게시하는 OPC UA 주소 공간(address space)을 구독하고 [1], 더 오래된 스키드에 대해서는 Modbus 레지스터를 폴링(polling)합니다. 중간에서는 정규화합니다. 3725라는 원시 레지스터 값이 37.25 °C가 되고, 벤더의 태그가 우리의 정규(canonical) BR101.Temp.PV가 되며, 누락된 단위가 채워집니다. 노스바운드로는 정제된 레코드를 그것이 살아야 할 곳으로 라우팅합니다. 통합 네임스페이스(Unified Namespace) 토픽으로 MQTT 브로커에 올리거나, 곧장 TimescaleDB로 보냅니다.
바로 이 형태 — Modbus/MQTT/OPC UA를 위한 사우스바운드 프로토콜 변환 계층과, 네트워크 끊김이 결코 샘플을 떨어뜨리지 않도록 수집과 전송을 분리하는 캐시를 갖춘 모듈형 엣지 게이트웨이 — 에 대한 동료 심사(peer-reviewed) 참조 설계가 2026년에 발표되었습니다 [2]. 그 분리가 핵심 전부입니다. 현장은 데이터 생산을 결코 멈추지 않지만, 네트워크는 때때로 그것을 실어 나르기를 멈춥니다. 로컬에 버퍼링했다가 링크가 돌아오면 전달하는 게이트웨이만이 완전한 기록을 보존합니다. 임베디드 하드웨어 위의 OPC UA 게이트웨이에 대한 또 다른 분석은 그 반대편의 긴장을 정량화합니다. OPC UA는 풍부하고 무겁고 자기 기술적인(self-describing) 스택인 반면, MQTT는 가벼운 발행/구독(pub/sub) 전송이어서, 게이트웨이는 으레 무거운 OPC UA를 사우스바운드로 읽고 가벼운 MQTT를 노스바운드로 내보냅니다 [3].
OT/IT 이음매로서의 엣지 게이트웨이: 사우스바운드로 현장 프로토콜을 읽고, 중간에서 정규화·버퍼링하며, 노스바운드로 브로커와 히스토리안으로 라우팅합니다. Node-RED, Telegraf, NiFi는 같은 파이프라인 위에서 각기 다른 지점을 차지합니다. Original diagram by the authors, created with AI assistance.
세 가지 도구, 세 가지 작업
세 가지를 모두 출하하는 이유는 어떤 단일 도구도 모든 축에서 이기지 못하기 때문입니다. 비결은 도구를 작업에 맞추는 것입니다.
Node-RED — 로우코드 플로우 편집기
Node-RED는 브라우저 기반의 로우코드(low-code) 편집기로, 작은 기능 노드들을 *플로우(flow)*로 연결합니다. 플로우 자체는 JSON으로 저장되며 Node.js 위에서 실행됩니다 [4]. 어떤 아이디어를 현장에 올리는 가장 빠른 방법입니다. mqtt in 노드, 페이로드를 재구성하는 function 노드, 그리고 postgres 노드를 끌어다 놓고 연결하면 바로 수집이 시작됩니다. 데몬(daemon)을 결코 직접 작성하지 않을 공정 엔지니어도 기꺼이 Node-RED 플로우를 만듭니다.
플로우가 JSON이기 때문에, 다른 코드형 구성(config-as-code) 산출물과 마찬가지로 Git 안에 살아 있습니다. 브로커에서 Sparkplug 페이로드를 받아 메트릭 하나를 골라내 히스토리안에 행을 삽입하는 최소 플로우는 다음과 같습니다 — 이것은 현실적인 Node-RED 플로우 익스포트로, 컴패니언 저장소의 core 프로파일에서 테스트된 산출물은 아닙니다. 게이트웨이는 옵트인(opt-in) capture 프로파일 뒤에서 실행됩니다:
// edge/node-red/flows.json (realistic config — capture profile, not in the core compose)
[
{ "id": "mqtt-in", "type": "mqtt in", "topic": "spBv1.0/Newark/DDATA/BR101/+",
"qos": "1", "broker": "mosquitto", "wires": [["to-row"]] },
{ "id": "to-row", "type": "function", "name": "sparkplug -> sensor_reading",
"func": "const m = msg.payload.metrics[0];\nmsg.payload = {\n ts: new Date(m.timestamp).toISOString(),\n tag: m.name, value: m.value, unit: m.properties.unit,\n quality: m.is_null ? 0 : 192, batch_id: flow.get('batch_id')\n};\nreturn msg;",
"wires": [["to-pg"]] },
{ "id": "to-pg", "type": "postgresql", "name": "ts.sensor_reading",
"query": "INSERT INTO ts.sensor_reading (ts,tag,value,unit,quality,batch_id) VALUES ($1,$2,$3,$4,$5,$6)" }
]
Node-RED의 강점은 동시에 한계이기도 합니다. 기본 인증과 얇은 권한 모델만 제공하므로, GxP 환경에서는 엔터프라이즈 애드온 없이는 누가 플로우를 바꿨는지 증명하거나 세밀한 역할을 부여할 수 없습니다. 우리는 이를 프로토타이핑 및 가벼운 접착(glue) 계층으로 취급하며, 그 점을 분명히 밝혀 둡니다.
Telegraf — 선언적 수집
Node-RED가 상호작용형이라면, Telegraf는 그 정반대입니다. 전적으로 TOML 파일로 구성되는 단일 Go 바이너리로, 입력(inputs)·프로세서(processors)·애그리게이터(aggregators)·출력(outputs)이라는 플러그인 모델을 선언적으로 조합합니다 [5]. 캔버스도 없고 클릭도 없습니다. 구성을 작성하고 버전 관리하면, 에이전트는 매번 정확히 파일이 말하는 대로 합니다. 그 결정성(determinism)이야말로 꾸준하고 높은 빈도의 메트릭 수집에서 바라는 바입니다.
브로커의 UNS 토픽을 소비해 PostgreSQL/TimescaleDB로 곧장 쓰는 Telegraf 구성은 짧습니다 — 역시 현실적인 capture 프로파일 산출물이며, 그렇게 표기되어 있습니다:
# edge/telegraf/telegraf.conf (realistic config — capture profile)
[agent]
interval = "5s"
flush_interval = "5s"
omit_hostname = true
[[inputs.mqtt_consumer]]
servers = ["tcp://mosquitto:1883"]
topics = ["bioproc/Newark/+/+/+"] # UNS: enterprise/site/area/line/unit
data_format = "json"
json_time_key = "ts"
json_time_format = "2006-01-02T15:04:05Z07:00"
[[outputs.postgresql]]
connection = "host=postgres user=bioproc password=bioproc dbname=bioproc"
table_template = "INSERT INTO ts.sensor_reading (ts,tag,value,unit,quality,batch_id) VALUES (...)"
그 단순함의 대가는 Telegraf가 수집하고 전달할 뿐, 메시지별 감사 추적은 제공하지 않는다는 것입니다. 파싱할 수 없는 메시지를 충실히 버리고 넘어갑니다. 스택 상태(health) 모니터링에는(운영 장에서 정확히 그 용도로 재사용합니다) 이상적입니다. 규제 배치 기록(batch record)에 대해서는 수집기(collector)이지 진실의 기록 시스템(system of record)은 아닙니다.
Apache NiFi — 보장된 전달과 재현 가능한 출처 정보
세 번째 도구는 데이터가 규제 대상일 때 제값을 하는 도구입니다. Apache NiFi는 데이터를 FlowFile로 삼아 프로세서들의 방향 그래프(directed graph)를 통해 라우팅하며, 자신이 생성·분기·복제·수정·전송하는 모든 FlowFile에 대해 질의하고 *재현(replay)*할 수 있는 저장소에 **출처 이벤트(provenance event)**를 기록합니다 [6]. 이것이 어떤 오픈소스 엣지 도구가 종단 간(end-to-end) 데이터 흐름 감사 추적에 가장 가까이 다가간 모습입니다. 사후에 NiFi에 "이 레코드의 계보(lineage)를 보여 줘"라고 물으면, 누가/무엇이/언제/무엇으로부터를 재구성해 줍니다 — W3C PROV 온톨로지가 엔터티(entities), 활동(activities), 에이전트(agents)로 정의하는 바로 그 형태입니다 [7]. 그 기록이 몇 달 뒤에도 방어 가능해야 할 때, 그 관리 연속성(chain of custody)이 바로 그 기능입니다.
NiFi의 더 가벼운 형제인 MiNiFi는 같은 발상을 소스까지 밀어 내립니다. "정보의 완전한 관리 연속성을 갖춘 데이터 출처의 생성"을 위해 명시적으로 설계된, 디바이스 바로 옆에서 동작하는 작은 풋프린트(footprint)의 에이전트입니다 [8]. 스키드 옆의 제약된(constrained) 엣지 박스에서 MiNiFi가 수집하고 출처를 찍은 뒤, 중앙 NiFi로 넘깁니다.
대가는 무게입니다. NiFi는 자체 출처 저장소와 콘텐츠 저장소를 갖춘 JVM 애플리케이션(Java 21, RAM 약 2 GB)이며, 그래서 항상 켜져 있는 core 스택이 아니라 옵트인 capture 프로파일 뒤에 자리합니다. 독자는 이 장을 위해서만 이를 띄웁니다. 그 출처 정보는 nifi.properties에서 구성되며, 관련 행 — 현실적인 구성이며 core 프로파일 산출물은 아닙니다 — 은 다음과 같습니다:
# edge/nifi/nifi.properties (realistic config — capture profile, provenance enabled)
nifi.provenance.repository.implementation=org.apache.nifi.provenance.WriteAheadProvenanceRepository
nifi.provenance.repository.directory.default=./provenance_repository
nifi.provenance.repository.max.storage.time=180 days
nifi.provenance.repository.indexed.fields=EventType, FlowFileUUID, filename, ProcessorID
max.storage.time을 보관 요건에 맞춰 설정하면, NiFi는 그 기간 동안 자신이 다룬 모든 FlowFile에 대한 재현 가능한 기록을 유지합니다.
데이터가 도착하는 곳
어느 도구가 라우팅하든, 데이터는 같은 대상으로 수렴합니다. 공유 플랫폼 스키마에 정확히 한 번 정의되어 배치 모델과 조인되는 히스토리안 하이퍼테이블(hypertable) ts.sensor_reading입니다. 대상 데이터베이스 자체는 항상 켜져 있는 core 프로파일로 올라옵니다. examples/platform/compose/compose.yaml에서:
# examples/platform/compose/compose.yaml
services:
postgres:
# timescale/timescaledb IS PostgreSQL + TimescaleDB, so the historian
# hypertable and the ISA-88/95 batch model live in one joinable database.
image: timescale/timescaledb:2.17.2-pg17
profiles: ["core"]
environment:
POSTGRES_USER: ${POSTGRES_USER:-bioproc}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-bioproc}
POSTGRES_DB: ${POSTGRES_DB:-bioproc}
ports: ["5432:5432"]
volumes:
- pgdata:/var/lib/postgresql/data
- ../db:/docker-entrypoint-initdb.d:ro # 00-60 schema files run on first init
mosquitto:
image: eclipse-mosquitto:2.0.22
profiles: ["core"]
ports: ["1883:1883"]
주석에 담긴 의도적 선택에 주목하세요. TimescaleDB는 곧 PostgreSQL이므로, 높은 빈도의 센서 이력과 ISA-88/95 배치 맥락이 조인할 수 있는 하나의 데이터베이스에 함께 삽니다. 게이트웨이의 유일한 임무는 깨끗한 행을 안착시키는 것이며, 의미는 조인에서 나옵니다. 그 조인은 이후 장들이 만들어 갑니다.
게이트웨이가 만들어 내는 행은 더없이 단순합니다. 롱 포맷, 행당 측정값 하나입니다. 다음은 examples/datasets/fedbatch_timeseries_10min.sample.csv에서 가져온 실제 형태입니다:
ts,tag,value,unit,quality,batch_id
2026-01-05 00:00:00+00:00,BR101.Agitation.PV,81.4323,rpm,192,BATCH-2026-001
2026-01-05 00:00:00+00:00,BR101.Agitation.SP,81.6008,rpm,192,BATCH-2026-001
2026-01-05 00:00:00+00:00,BR101.DO.PV,40.8224,%sat,192,BATCH-2026-001
저 quality 열은 장식이 아닙니다. 192는 Good에 해당하는 OPC UA StatusCode(0x00C0 = 192)이며, 게이트웨이는 그 품질 플래그를 손대지 않고 그대로 실어 날라, 대시보드나 검토자가 나중에 진짜 판독값과 불확실하거나 나쁜 판독값을 구분할 수 있게 합니다. 그 필드를 엣지에서 버리는 것은 전형적인 데이터 무결성 자책골입니다 — 모든 값이 똑같이 신뢰할 만해 보이도록 소리 없이 만들어 버린 셈이죠.
컴패니언 저장소에서는 5장부터 13장까지가 이 수집 경로를 한 조각씩 쌓아 올립니다. 이후의 맥락화(contextualization)와 ALCOA+ 장들이 곧바로 질의할 대상을 갖도록, 저장소는 전체 적재를 한 번에 수행하는 스크립트 하나도 함께 출하합니다 — examples/tools/load_datasets.py입니다. 그 시계열 로더는 교과서적인 대량 수집(bulk ingest)으로, 운영용 게이트웨이가 노스바운드로 묶어 보내는 바로 그 모습입니다:
# examples/tools/load_datasets.py
def load_timeseries(conn) -> int:
df = pd.read_parquet(DATA / "fedbatch_timeseries.parquet")
buf = io.StringIO()
df[["ts", "tag", "value", "unit", "quality", "batch_id"]].to_csv(buf, index=False, header=False)
buf.seek(0)
with conn.cursor() as cur:
cur.execute("TRUNCATE ts.sensor_reading")
with cur.copy("COPY ts.sensor_reading (ts, tag, value, unit, quality, batch_id) "
"FROM STDIN WITH (FORMAT csv)") as copy:
copy.write(buf.read())
return len(df)
같은 스크립트는 오프라인 실험실 데이터를 다른 스키마로 라우팅하기도 하며, 그 세부는 게이트웨이 이야기에서 중요합니다. 쓰기 전에 귀속 가능한 행위자(attributable actor)를 찍는다는 점에 주목하세요 — set_config('app.user', 'loader', ...) — 덕분에 데이터베이스의 감사 트리거가 누가 그 행을 들여왔는지 기록합니다:
# examples/tools/load_datasets.py
def load_offline(conn) -> int:
df = pd.read_csv(DATA / "offline_assays.csv", parse_dates=["sample_time"])
n = 0
with conn.cursor() as cur:
cur.execute("SELECT set_config('app.user', 'loader', false)")
for _, r in df.iterrows():
cur.execute(
"INSERT INTO lab.sample (sample_id, batch_id, sample_time, sample_point, sample_type) "
"VALUES (%s,%s,%s,%s,'in_process') ON CONFLICT (sample_id) DO NOTHING",
(r.sample_id, r.batch_id, r.sample_time.to_pydatetime(), r.sample_point))
...
return n
전체는 책이 그대로 인쇄하는 make 타깃 하나로 실행합니다:
make load # load the datasets into the running stack (historian + lab + genealogy)
# -> loaded: 322560 sensor readings, 1344 offline results, 66 release results, 30 genealogy edges
솔직한 부분: 전달 의미론과 감사 공백
여기서부터는 파는 일을 멈추고 고백을 시작합니다. 게이트웨이의 가장 중요한 약속은 완전성(completeness) — 현장이 만들어 낸 모든 측정값이 실제로 도착했다는 것 — 입니다. 그것이 ALCOA+의 "C"(Complete)이며, MHRA의 데이터 무결성 지침은 이를 명시적으로 거론합니다. 데이터는 완전해야 하며, 소리 없이 버려지는 것이 없어야 합니다 [9]. FDA의 cGMP 데이터 무결성 Q&A는 반대편에서 같은 요구를 합니다. 모든 cGMP 데이터는 완전하고, 신뢰할 수 있으며, 정확해야 합니다 [10].
엣지에서의 완전성은 결국 **MQTT 서비스 품질(Quality of Service, QoS)**로 귀결됩니다. MQTT 명세는 세 단계를 정의합니다. QoS 0(at-most-once — 쏘고 잊기, 메시지가 유실될 수 있음), QoS 1(at-least-once — 전달은 보장되나 중복 가능), QoS 2(exactly-once — 네 단계 핸드셰이크를 대가로 보장되고 중복 제거됨) [11]. 위의 Node-RED 플로우는 일부러 "qos": "1"로 설정했습니다. 바이오공정 데이터에서는 측정값을 한 번 잃느니 두 번 받아(그리고 (ts, tag)로 중복 제거하는 편)가 낫기 때문입니다. 대역폭을 아끼려고 QoS 0을 고르는 것은, 규제 맥락에서는 자신의 기록을 불완전하게 만들기를 선택하는 셈입니다.
하지만 QoS는 전송만 보호합니다. 변환이 예외를 던지거나, 디스크가 가득 차거나, 프로세스가 흐름 중간에 재시작될 때 게이트웨이 내부에서 무슨 일이 일어나는지에 대해서는 아무 말도 하지 않습니다. 바로 여기가 Node-RED와 Telegraf가 부족하고 NiFi가 빛나는 지점입니다. NiFi의 FlowFile 모델은 트랜잭션적이고 그 출처 저장소가 모든 메시지의 운명을 기록하므로, 버려지거나 다시 라우팅된 레코드가 소리 없이 사라지는 대신 보이고 재현 가능합니다 [6]. 감사받을 수 있는 기록에서 "다 통과한 것 같아요"는 답이 아닙니다. "모든 FlowFile에 대한 출처 이벤트가 여기 있고, 데드레터(dead-letter) 관계에 실패가 0건 있습니다"가 답입니다.
그리고 NiFi의 출처 정보조차 Part 11 감사 추적이 아닙니다. 그것은 데이터 흐름이 무엇을 했는지를 말해 줄 뿐, 규제 대상 값이 변경된 데 대한 불변·서명된, 누가·왜·어떤 사유로의 기록을 그 자체로 제공하지는 않습니다. 그것은 데이터베이스의 몫입니다 — 신뢰(trust) 장들에서 우리가 구축하는 시스템 버전 관리 이력과 해시 체인(hash chain)이지, 게이트웨이의 몫이 아닙니다. 솔직한 역할 분담은 이렇습니다. 게이트웨이는 데이터가 도착함을 보장하고 어떻게 흘렀는지를 기록합니다. 히스토리안과 배치 모델은 검증되고, 감사 추적되며, 서명 가능한 진실의 기록이 됩니다. 어떤 엣지 도구도 그 자체로 준수(compliant) 기록은 아닙니다.
왜 중요한가
하류의 모든 것 — 대시보드, 맥락화, 지식 그래프, 소프트 센서(soft-sensor), 감사 추적 검토 — 은 데이터가 완전하고 올바르게 라벨링되어 도착했다고 가정합니다. 엣지 게이트웨이는 그 가정이 얻어지거나 조용히 깨지는 곳입니다. 품질 플래그를 버리거나, QoS 0을 고르거나, 관리 연속성이 없는 수집기를 쓰면, 방어할 수 없는 데이터 위에 아름다운 플랫폼을 쌓을 수 있습니다. 각 작업에 맞는 올바른 도구를 고르세요 — 프로토타이핑에는 Node-RED, 대규모 수집에는 Telegraf, 흐름이 증명 가능해야 할 때는 NiFi — 그러면 책의 나머지는 쌓아 올릴 가치가 있는 기반을 갖게 됩니다.
실제 현장에서는
실제 mAb 라인에서 게이트웨이가 시뮬레이터와 대화하는 일은 드뭅니다. Emerson DeltaV 같은 DCS나 Siemens 제어기와 OPC UA로 대화하고, 독립형 스키드와는 Modbus나 S7로, IT 쪽의 AVEVA PI 같은 상용 히스토리안과 대화합니다. 그런 시스템들은 노트북에서 돌아가지 않고 라이선스로 잠겨 있는데, 그래서 우리 컴패니언 저장소는 OPC UA 생물반응기를 모킹(mocking)하고 무거운 게이트웨이를 옵트인 프로파일 뒤에 출하합니다 — 통합 코드는 진짜지만, 벤더 고유의 까다로운 부분은 여기서 행사되지 않습니다. 정확히 이런 종류의 디지털 통합을 위해 지어지고 있는 파일럿 규모(pilot-scale) cGMP 시설 — 델라웨어 대학교의 NIIMBL SABRE 시설(2024년 4월 착공한 공공-민간 cGMP 파일럿 시설, cGMP = current Good Manufacturing Practice) 같은 곳 — 이 실제 디바이스 엣지 테스트가 일어나는 무대입니다.
이 계층에 대한 솔직한 OSS 대 상용 평결: 오픈소스 게이트웨이는 가교 작업을 진정으로 잘 해냅니다 — Node-RED, Telegraf, NiFi는 모두 운영 등급(production-grade)이며, NiFi의 출처 정보는 진짜 차별점입니다. 이들이 기본으로 주지 않는 것은 검증된 시스템 래퍼(wrapper)입니다. 벤더 책임성, 턴키(turnkey) Part 11 감사 추적, 적격성 평가된 고가용성(high availability), 그리고 IQ/OQ/PQ 문서 작업이죠. 상용 엣지 플랫폼(Ignition, HighByte, 히스토리안 벤더 자체 커넥터)은 그 래퍼를 팝니다. OSS로도 훨씬 적은 라이선스 비용에 대략 같은 데이터 결과에 도달할 수 있지만 — GxP의 마지막 한 구간(last mile)은 여러분이 검증할 몫이며, 그 작업은 실재합니다.
핵심 용어
- 엣지 게이트웨이(edge gateway) — OT/IT 이음매에 있는 디바이스/소프트웨어로, 현장 프로토콜을 읽고, 데이터를 변환하고, 버퍼링하고, 제어 루프를 바꾸지 않으면서 다음 단계로 라우팅한다.
- OT / IT — 운영 기술(Operational Technology, 격리된 제어 네트워크의 제어기·스키드·센서) 대 정보 기술(Information Technology, 데이터베이스·대시보드·분석).
- 사우스바운드 / 노스바운드(southbound / northbound) — 현장 프로토콜 쪽(디바이스를 향해 아래로) 대 데이터 플랫폼 쪽(IT를 향해 위로)을 가리키는 게이트웨이 용어.
- Node-RED — 브라우저 기반 로우코드 플로우 편집기; 플로우는 JSON으로 저장되고 Node.js 위에서 실행됨; 프로토타이핑에 탁월하나 RBAC은 약함.
- Telegraf — 단일 바이너리, 플러그인 구동, TOML 구성 방식의 수집 에이전트; 결정적이며 메시지별 감사 추적은 없음.
- Apache NiFi / MiNiFi — 재현 가능한 FlowFile 단위 출처 정보(관리 연속성)를 갖춘 JVM 데이터흐름 도구; MiNiFi는 그 작은 풋프린트의 엣지 에이전트.
- 출처 정보 / 데이터 계보(provenance / data lineage) — 데이터 레코드의 누가/무엇이/언제/무엇으로부터 이력을 기록한 것; W3C PROV-O가 표준 어휘(엔터티, 활동, 에이전트).
- QoS (MQTT) — 전달 보장: QoS 0 at-most-once(유실 가능), QoS 1 at-least-once(중복 가능), QoS 2 exactly-once.
- 품질 플래그(quality flag) — 각 값과 함께 실려 소비자가 좋은 판독값과 불확실/나쁜 판독값을 구분하게 해 주는 OPC UA
StatusCode(예:192= Good). - ALCOA+ "완전성(Complete)" — 어떤 데이터도 소리 없이 유실되지 않도록 요구하는 데이터 무결성 속성; 게이트웨이의 전달 보장이 이를 지킨다.
다음 이야기
이제 게이트웨이는 깨끗하고 품질 플래그가 붙은 스트림을 히스토리안으로 안정적으로 라우팅합니다. 하지만 라우팅은 소스만큼만 좋습니다. 다음 장 **상류 포착: 생산 생물반응기(Upstream Capture: The Production Bioreactor)**에서는 파이프라인을 공정의 심장 — 유가식(fed-batch) CHO 생물반응기 그 자체 — 으로 겨누고, 14일 배치가 펼쳐지는 동안 그 설정값(setpoints), 공정값(process values), OPC UA 품질 코드, ISA-88 단계(phase) 맥락을 포착하여, 행의 스트림을 살아 있는 배양에 관한 이야기로 바꿔 놓습니다.