fix: 对齐技术架构补齐传输 mTLS 与结构化 JSON 日志(NFR 9 章)

架构核对发现 2 处差距,本次补齐:
- Kafka 上行支持 SSL/SASL_SSL 双向 mTLS(8.2 服务间 mTLS 边缘网关↔总线)
- 网关日志支持结构化 JSON 输出(NFR 可维护:统一日志规范)
- 配置示例与 README 验收口径同步更新
This commit is contained in:
2026-08-04 15:46:09 +08:00
parent f49c0920d4
commit 098125164d
8 changed files with 481 additions and 7 deletions
+35 -1
View File
@@ -29,11 +29,24 @@ class KafkaSink:
topic_prefix: str,
spool: SpoolStore,
batch_size: int = 500,
security: Optional[dict] = None,
):
"""
Args:
bootstrap_servers: Kafka 地址列表(逗号分隔);
topic_prefix: 上行 topic 前缀(模板化 `{prefix}.{device}.points`);
spool: 本地缓存(断点续传);
batch_size: 单批上限;
security: 传输安全配置(NFR 9 章:服务间 mTLS)。
约定字段:protocol(PLAINTEXT|SSL|SASL_SSL)、ca_location、
cert_location、key_location、sasl_username、sasl_password。
其中 SSL/SASL_SSL + ca/cert/key = 边缘网关↔总线双向 mTLS。
"""
self.bootstrap_servers = bootstrap_servers
self.topic_prefix = topic_prefix
self.spool = spool
self.batch_size = max(1, batch_size)
self.security = security or {}
self._producer = None
self._degraded = False # True = Kafka 不可用,仅保留 spool
self._lock = threading.Lock()
@@ -42,6 +55,27 @@ class KafkaSink:
self._connect()
# ------------------------------------------------------------------
def _producer_config(self) -> dict:
"""组装 confluent-kafka producer 配置(含 mTLS/SASL 透传)。"""
conf = {"bootstrap.servers": self.bootstrap_servers}
protocol = self.security.get("protocol", "PLAINTEXT").upper()
conf["security.protocol"] = protocol
if protocol in ("SSL", "SASL_SSL"):
for key, kafka_key in (
("ca_location", "ssl.ca.location"),
("cert_location", "ssl.certificate.location"),
("key_location", "ssl.key.location"),
("key_password", "ssl.key.password"),
):
if self.security.get(key):
conf[kafka_key] = self.security[key]
if protocol == "SASL_SSL":
conf["sasl.mechanism"] = self.security.get("sasl_mechanism", "PLAIN")
if self.security.get("sasl_username"):
conf["sasl.username"] = self.security["sasl_username"]
conf["sasl.password"] = self.security.get("sasl_password", "")
return conf
def _connect(self) -> None:
"""尝试连接 Kafka;失败则降级(不阻断采集)。"""
try:
@@ -51,7 +85,7 @@ class KafkaSink:
self._degraded = True
return
try:
self._producer = Producer({"bootstrap.servers": self.bootstrap_servers})
self._producer = Producer(self._producer_config())
except Exception as exc:
logger.warning("Kafka 初始化失败(%s),降级为 spool-only 模式", exc)
self._degraded = True