一、背景简介
前两天接到一个项目是对当前核验系统升级改造,解决几个核心痛点及问题
- 现场部署服务无法实现高可用性,只能单机服务;
- 增强现场稳定性保障核验服务与数据能准确无误;
- 对于核验能够提供全视角观测能力,在事前、事中、事后都能够查询状态;
- 核验系统能够支持脱离公网环境独立运行;
二、演进前后架构
2.1 原有架构
2.2 新设计架构
- 描述:现场部署以入场口为最小部署单元,最小部署单元具备独立的业务能力,并允许在无网络的情况下保证业务可用性(核验,高可用)。
- fe与云端通讯方式:现场最小单元通过场馆有线(公网)/5G/iot 与云端通讯,目前场馆提供的有线网络为主要手段,如无有线,使用蜂窝网络,如人群数量巨大造成蜂窝网络阻塞,使用iot与云端通讯。
- fe与edge的通讯方式:与edge可通过公网ip,vpc,公网网关与edge通讯。
- 最小单元包含,闸机,路由器,前置机(边缘节点)。
- 数据流转:端设备通过sdk实现日志上报给fe,由fe(flume或任何cdc如sync)通过edge或者有线网络上报给edge作为边缘计算的数据接入点,或直接通过场馆公网上报。如没有网络需上传至局域网中心服务(lora)
- 数据下发:通过edge节点下发给容器configMap,由fe承接做后续动作或转发给设备端。
- 高可用:前置机由edge管控可维持app的副本数(含无网络情况),目前mariadb,hiveMqtt,xxx-acs-xxx已经容器化,可保证单node上的HA。如需多node支持,则edge可根据节点池写tag,相同的tag认为是一套边缘节点,可部署高可用服务集群。
三、实施落地
3.1 高可用性
- 环境需求
- Java应用xxx-acs-xxx数据库、MQ配置IP地址尽可能要固定;
- 边缘节点在接入时能够把预装组件和基础镜像都下载安装完成,并加入到edge集群资源池;(同时验证节点带到其它地域连网后可以正常使用,不需要删除重加)
- 边缘节点开启自治,保障在节点上运行的服务在异常后还可以正常拉起并运行;
- 部署架构
- 部署代码
| 服务名称 | IP 地址 | 备注 |
|---|---|---|
| xxx-acs-xxx | IP地址 192.168.95.90 端口 8080 | |
| hivemq | IP地址 192.168.95.90 端口 1883 映射端口:XXXX | 端口 8088、端口 8000 |
| mariadb | IP地址 192.168.95.90 端口 3306 映射端口:XXXX | 用户为root,密码 |
| 管理工具 | http://192.168.95.90:9000/ | admin xxxxxxxxx |
apiVersion: apps/v1
kind: DaemonSet
metadata:
annotations:
apps.openyurt.io/update-strategy: AdvancedRollingUpdate
apps.openyurt.io/max-unavailable: 30%
stack: java
workload: xxx-acs-xxx
labels:
app: xxx-acs-xxx
stack: java
version: prod
workload: xxx-acs-xxx
name: xxx-acs-xxx
namespace: prod
spec:
selector:
matchLabels:
stack: java
workload: xxx-acs-xxx
template:
metadata:
annotations:
stack: java
workload: xxx-acs-xxx
labels:
app: xxx-acs-xxx
stack: java
version: prod
workload: xxx-acs-xxx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: alibabacloud.com/nodepool-id
operator: In
values:
- np2b4819653fbe4c31b1fe295c3a1864e2
weight: 100
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nodepool.openyurt.io/hostnetwork
operator: In
values:
- "false"
hostNetwork: true
containers:
- command:
- java
- -Dfile.encoding=UTF-8
- -server
- -XX:+UseContainerSupport
- -XX:InitialRAMPercentage=65.0
- -XX:MaxRAMPercentage=65.0
- -XX:+UseConcMarkSweepGC
- -XX:+PrintGCDetails
- -XX:+PrintGCDateStamps
- -Xdebug
- -Xrunjdwp:transport=dt_socket,address=20000,server=y,suspend=n
- -Duser.language=zh
- -jar
- /data/code/ROOT.jar
env:
- name: POD_PORT
value: "8080"
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
envFrom:
- configMapRef:
name: runtime
image: h
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /bin/bash
- -x
- pullOut.sh
livenessProbe:
failureThreshold: 2
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: xxx-acs-xxx
ports:
- containerPort: 8080
hostPort: 8080
protocol: TCP
name: main-port
readinessProbe:
failureThreshold: 2
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 9
successThreshold: 1
timeoutSeconds: 2
resources:
limits:
cpu: "3"
memory: 2Gi
requests:
memory: 768Mi
securityContext:
allowPrivilegeEscalation: false
privileged: false
procMount: Default
readOnlyRootFilesystem: false
runAsNonRoot: false
startupProbe:
failureThreshold: 30
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data/code/
name: service-code
dnsPolicy: ClusterFirst
hostname: xxx-acs-xxx
imagePullSecrets:
- name: default-secret
initContainers:
- command:
- cp
- -a
- /opt/ROOT.jar
- /data/code/
env:
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: h
imagePullPolicy: IfNotPresent
name: copy-code
resources:
requests:
memory: 20Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /data/code/
name: service-code
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 95
volumes:
- emptyDir: {}
name: service-code
3.2 核验控制台
- 控制台监控
核验控制台原理接近抢票控制台
-
事前
- 核验数据与订单比对,48h,24h,12h,6h,3h,1.5h,30s各执行一次,包含实名信息(sql已有),比对错误生成比对结果,人工介入处理。可随时手动跑
- 人工核对核验规则,规则版本号。规则版本号为新概念,表述了核验规则最终的生效版本,由云端确认,同步给前置机。
- 拉起核验沙盒(xxx-acs-xxx),设定时间为核验开始时间,对现有所有的票进行核验,生成结果人工核对。沙盒设计见下一节。
-
到现场
- 前置机加入边缘节点,同步核验数据。
- 比对数据,核验规则版本号,边缘节点加入后自动启动app,sync后,启动比对,结果上报。
-
现场部署硬件部署完毕
- 端自检结果上报,自动从前置机同步配置信息,并核对当前客户端版本号,上报。(安卓自动更新app,是否可做)
- 现场测试,生产项目测试数据(是否可做),或测试项目验证硬件与前置机。
-
事中
- 业务核验监控大屏,边缘节点大屏,关键接口健康状态
- 核验数据,订单,即,用户数据 -> 所有系统数据的查询信息。(身份证查询票,票吗查询等),可支持手机。即快速定位用户是否有票,如确定,其实核验数据后续可补。
- 对于业务规则变更原则上走全量沙盒验证,核验中可抽取验证。
- 预案核验预案:同步预案:有全量同步接口
-
事后。。。。
3.3 核验沙盒
描述:沙盒可看成离线前置机核验全量票。
对于人脸等操作进行mock处理,或使用系统中现有照片。
- 根据项目的xxx-acs-xxx镜像拉起一套核验离线服务端(xxx-acs-xxx,mqtt,mariadb)
- xxx-acs-xxx启动后从云端拉取核验数据,项目数据,规则数据。
- 当xxx-acs-xxx ready,使用核验信息,调用fe,测试票的可通过性。上报结果,日志,并销毁沙盒。
- 安卓业务端也可纳入,需讨论可行性。