资讯动态

SolidTime在Rocky Linux 9.5上的时间同步与调度实践

发布时间:2026/10/14 19:20:35 来源:尧图企业网站定制
1. SolidTime 到底是什么为什么我坚持装在了 Rocky Linux 9.5 上上个月我排查一个跨机房调度问题两台机器的时间就差 2.4 秒结果让凌晨的批量任务整体偏移了近十分钟线上数据对不齐日志还原出来的“事实顺序”全是错的。这种问题最气人的地方在于它不报错只会悄悄把业务结果带偏。后来我把 SolidTime 完整部署在 Rocky Linux 9.5 上整套系统的时间秩序才算真正稳定下来。SolidTime 不是一个单纯的时间同步工具。它由三块组成时间同步引擎、任务调度器、统一时间戳采集接口。你可以把系统自带的 chrony 理解成一块手表的内部校准它负责让内核时钟本身走得准而 SolidTime 干的事情更像是让所有员工的手表都显示同一个时间并且让排班表、刷卡记录、审计流水全部按同一口径执行。也就是说chrony 解决“机器时间对不对”SolidTime 解决“业务时间乱不乱”。1.1 我眼里的分工SolidTime 和 chrony、cron 到底怎么协作很多人第一次看到 SolidTime 会问系统里已经有 chrony 了也有 cron、systemd timer为什么还要多装一个服务我在实际部署里的理解是这样的chrony 负责往内核喂时间它管的是CLOCK_REALTIME这个底层精度一旦网络中断或者上游源失效它最多只能告诉你“当前不可用”cron 和 systemd timer 则只负责触发它们不会考虑不同节点之间的时间口径差异也不会把任务的执行历史、触发结果、时间戳统一存下来。SolidTime 恰好补的是中间这一层。它有自己的一套上游时间源协商逻辑会从多个 NTP 源里做多数对齐不是为了“追平均时间”而是为了把异常源剔除掉。然后在它的调度器里任务可以定义成“北京时间每天上午 9 点执行”系统内部一率转成 UTC 存储节点之间永远不会因为时区设置不同而执行出偏差。最后它的时间戳采集接口又给上层应用提供统一、单调递增的时间凭证审计系统拿到的是同一把尺子量出来的数据。选型对比我做了个很直接的表格能力chronycron / systemd timerSolidTime核心时钟校准负责不负责依赖但会做二次校验多节点时间口径统一不负责不负责负责跨时区任务调度不支持仅本机时区任务级时区定义调度结果留痕无靠日志内置审计存储时间戳服务接口无无有所以部署 SolidTime 不等于把 chrony 扔掉反而要先把 chrony 调稳。它更像个“应用层时间中台”底下接系统时钟上面接业务服务。1.2 为什么选 Rocky Linux 9.5而不是其他发行版或容器这次部署我选 Rocky Linux 9.5理由不复杂。它和主流企业级发行版保持长期兼容生命周期长不会出现某个依赖库突然升级后服务不适配的问题其次它对 SELinux、systemd 这些基础组件的集成度比较完整我可以在 systemd 单元文件里直接用ProtectSystemstrict、ReadOnlyPaths这类安全沙箱参数对时间同步这种对文件权限敏感的服务来说非常合适。还有一点是包管理的兼容性。Rocky 使用 RPM/DNF 体系自建仓库非常方便。我把 SolidTime 的 RPM 包放进内部仓库以后所有机器都能通过dnf install统一安装补丁更新也能走同一条链路。相比在每个节点上手动解压二进制包这种交付方式要可控得多。1.3 为什么我们最终没有把 SolidTime 容器化容器化当然是好东西但时间同步服务对它不太友好。首先是时钟精度容器默认共享宿主机内核时钟你想在容器里单独做时间偏差控制实际绕不开宿主机的CLOCK_REALTIME影响隔离的效果很有限。其次是调度依赖SolidTime 的任务调度器要和节点上的文件系统、日志目录、本地任务交互走容器卷映射会多一层权限和路径映射排查问题时不直观。更重要的是SolidTime 本身需要以低权限系统用户长期运行而 Rocky Linux 9.5 的 systemd 对这类守护进程支持得非常完善资源限制、重启策略、安全沙箱都写在单元文件里这比容器编排再套一层反而清爽。所以我们的最终方案是系统服务直接跑在宿主机上由 systemd 托管必要的数据目录单独分区挂载。2. 部署前先把环境理顺系统时钟、端口放行与软件仓库很多人都想跳过环境准备直接安装但时间同步类服务最怕“底层时钟本来就乱”。我在部署前会先花半小时把三件事理清楚。2.1 系统时钟先确认底子是干净的先看当前时间状态timedatectl status重点看两行System clock synchronized: yes和NTP service: active。如果显示 no就先把系统的 chrony 服务拉起来dnf install -y chrony systemctl enable --now chronyd timedatectl set-ntp true timedatectl status顺手检查一下上游源是否正常chronyc sourcestats -v chronyc tracking我遇到过一种情况机器本来有自带的 NTP 服务但配置的是机房内网地址解析失败后系统一直不报错只是时间慢慢漂。所以我会在这些命令的输出里确认源是^*状态也就是当前已同步而不是^?表示不可达。这一步做好后面 SolidTime 的偏差检测才有意义。2.2 端口规划与防火墙边界SolidTime 默认需要几个端口这是我在测试环境里固定下来的规划服务端口协议用途solidtime-api11811TCPREST/API 与控制台访问solidtime-sync11812UDP节点间时间同步协商solidtime-metrics11813TCP监控指标采集之所以单独拆一个 UDP 端口给节点间同步是因为多节点之间需要高频交换时间戳样本用 TCP 会带来额外的握手开销而且同步数据本身允许丢失重发UDP 反而更轻量。放行命令如下firewall-cmd --permanent --add-port11811/tcp firewall-cmd --permanent --add-port11812/udp firewall-cmd --permanent --add-port11813/tcp firewall-cmd --reload firewall-cmd --list-ports如果节点之间的网络有更细的访问控制建议只对 SolidTime 的网段放行不要对所有来源开放。时间同步协议本身是明文交换时间戳虽然我们有 token 校验但减少暴露面永远是对的。2.3 自建软件仓库不用到处找包SolidTime 的 RPM 包我建议统一放到内部仓库不要在每台机器上手动下载散装包。我们的做法是准备一台内部文件服务器把 RPM 包和签名公钥放上去然后用createrepo生成仓库元数据createrepo /data/repo/solidtime/9.5在目标机器上新建仓库文件/etc/yum.repos.d/solidtime.repo[solidtime-release] nameSolidTime Release Repository baseurlhttp://repo.internal.example/solidtime/9.5/$basearch enabled1 gpgcheck1 repo_gpgcheck0 gpgkeyhttp://repo.internal.example/RPM-GPG-KEY-solidtime然后执行dnf clean all dnf makecache dnf repolist确认仓库被识别后再安装。离线环境也一样只要把仓库路径改成本地目录即可。这种方式的收益在升级时最明显——后续发布小版本只需要把 RPM 放进仓库并重新运行createrepo所有节点执行一次dnf update就完成了不会出现“这台机器 1.2那台机器 1.6”的碎片化。3. 安装动作与 systemd 落盘低权限账号、目录隔离、开机自启3.1 安装命令与 RPM 包里有什么仓库配好后安装很简单dnf install -y solidtime-core rpm -ql solidtime-corerpm -ql能看到它安装的文件大致分成几类主程序在/usr/sbin/solidtime配置文件在/etc/solidtime/文档在/usr/share/doc/solidtime-core/。还有一个solidtime-cli命令用于日常诊断和任务管理。我注意到安装脚本会自动创建运行用户solidtime和几个目录这个细节很关键。时间服务不能直接用 root 跑否则一旦 API 被调用方误用权限范围就太大了。默认创建的目录包括/etc/solidtime/配置文件目录/var/lib/solidtime/数据目录存放调度历史、时间戳样本/var/log/solidtime/日志目录我检查过这几个目录的属主都是solidtime:solidtime权限是 750。如果你从旧版本升级安装脚本不会覆盖已有的配置这点做得很稳妥。3.2 目录隔离与日志轮转规划/var/lib/solidtime里会有调度任务执行记录和时间戳样本长期运行数据量不小。我强烈建议把数据目录单独挂到一个分区避免和根分区抢磁盘空间。如果是虚拟机就加一块独立数据盘挂载后把目录迁移过去systemctl stop solidtime mv /var/lib/solidtime /var/lib/solidtime.bak mkdir /var/lib/solidtime mount /dev/vdb1 /var/lib/solidtime chown solidtime:solidtime /var/lib/solidtime systemctl start solidtime对应挂载项写进/etc/fstab。这一步在安装后做最容易等跑了一段时间数据多了再迁移就麻烦很多。日志方面我在/etc/logrotate.d/solidtime里放了一份轮转配置/var/log/solidtime/*.log { daily rotate 30 compress delaycompress missingok notifempty create 0640 solidtime solidtime postrotate /usr/bin/systemctl reload solidtime /dev/null 21 || true endscript }保留 30 天的日志足够排查问题了太多反而乱。3.3 systemd 单元文件的安全与自愈安装完成后服务不会自动启动需要手动 enable。我先看一眼它自带的单元文件然后根据自己的环境改成下面这样[Unit] DescriptionSolidTime Time Synchronization and Schedule Daemon Afternetwork-online.target chronyd.service Wantsnetwork-online.target [Service] Typesimple Usersolidtime Groupsolidtime ExecStart/usr/sbin/solidtime serve --config/etc/solidtime/solidtime.yaml ExecReload/bin/kill -HUP $MAINPID Restarton-failure RestartSec5 TimeoutStopSec60 LimitNOFILE65535 ProtectSystemstrict ProtectHometrue ReadWritePaths/var/lib/solidtime /var/log/solidtime PrivateTmptrue NoNewPrivilegestrue [Install] WantedBymulti-user.target几个参数值得说明Restarton-failure保证非正常退出时自动拉起但不要用always否则配置写错会导致服务疯狂重启ProtectSystemstrict配合ReadWritePaths意思就是除了数据目录和日志目录其他路径对进程只读防止它被利用后乱写系统文件PrivateTmptrue避免共享 /tmp 目录的口子。改完之后systemctl daemon-reload systemctl enable --now solidtime systemctl status solidtime服务起来后先别急着配置业务任务把日志看一眼确认没有初始化错误再进入配置环节。4. 核心配置拆解时间源容错、调度口径和数据留存策略SolidTime 的配置集中在/etc/solidtime/solidtime.yaml里。我建议空出足够时间把每个字段看懂不要直接用别人给的默认配置。下面是基于我当前环境的一份精简配置我会逐段说明它解决什么问题。4.1 服务监听与 TLS 配置server: bind: 0.0.0.0 api_port: 11811 sync_port: 11812 metrics_port: 11813 tls: enabled: true cert: /etc/solidtime/tls/server.crt key: /etc/solidtime/tls/server.key request_timeout: 10s绑到0.0.0.0表示所有网卡都监听如果你的节点有多网卡建议收紧到业务网段的地址。TLS 我建议直接开因为时间戳接口会作为审计数据源明文传输会让中间人很容易篡改时间凭证。自签证书也够用关键是要在客户端做好证书校验。为了维护方便可以用一条命令生成内部证书mkdir -p /etc/solidtime/tls openssl req -x509 -newkey rsa:2048 -days 730 \ -nodes -keyout /etc/solidtime/tls/server.key \ -out /etc/solidtime/tls/server.crt \ -subj /CNsolidtime.internal.example chown -R solidtime:solidtime /etc/solidtime/tls chmod 600 /etc/solidtime/tls/server.key生产环境如果有内部 CA建议用内部 CA 签后续客户端配置信任链会更方便。4.2 时间源容错多数对齐不是平均对齐sync: strategy: majority source: - host: ntp.internal.example weight: 10 - host: ntp.backup.example weight: 5 - host: ntp.pool.example weight: 5 poll_interval: 15s abort_threshold: 50ms sample_window: 300strategy: majority的意思是三到五个上游源分别给出当前时间样本SolidTime 会丢弃明显偏离的源在剩余的正常源里做对齐。它不是为了算平均值而是相信“大多数源是一致的”。为什么这样做因为一个漂移源如果参与平均就会把整体时间带偏而多数对齐能直接把它踢出局。权重字段是给内部源更高优先级的比如内网源权重 10公网源权重 5在偏差接近时优先采纳内网源。abort_threshold: 50ms是检测异常偏移的阈值。生产上如果系统时间发生超过 50 毫秒的跳变SolidTime 会认为样本异常并触发保护逻辑而不是立刻把系统时间改过去防止一次错误的网络源导致全集群时间大幅跳动。4.3 调度任务的时区口径永远存 UTC只在展示层换时区scheduler: tasks: - name: daily-report description: 生成每日报表 schedule: 0 1 * * * timezone: Asia/Shanghai target: /usr/local/bin/generate-report.sh timeout: 300s retry: 3 tags: [report, business] persist_log: true max_history: 200000这里的坑我在测试时踩过。schedule里的 cron 表达式默认按 UTC 解析但我处的业务时区是Asia/Shanghai。如果直接写0 9 * * *而不指定 timezone任务会在 UTC 9 点也就是北京时间 17 点执行完全反了。所以我在每个任务里显式声明timezone: Asia/Shanghai内部存储时间戳统一转成 UTC展示时再转回当地时间。这里有一个经验原则系统、存储、传输环节全部用 UTC只有给人看的界面才做时区转换。这样无论服务器在哪个机房、运行哪个时区调度结果和审计记录都是可对比的。4.4 身份校验和审计选项security: auth: enabled: true token: 在配置文件里不要放明文生产上用环境变量注入 token_env: SOLIDTIME_TOKEN audit: enabled: true output: /var/log/solidtime/audit.log include_tasks: truetoken_env是读取环境变量来获取 token而不是把密钥写死在 YAML 里。我们用 systemd 的EnvironmentFile指向一个 root 才能读的文件运行用户只通过环境变量拿值这样既不影响启动又避免密钥落在配置库里。审计日志会记录每一次时间戳签发和任务执行结果。这个文件建议放到单独挂载的数据盘上并纳入日志轮转。5. 上线前的联调验证从时间偏差看任务调度是否可靠配置完成不等于可以上线。时间同步这类服务最怕的就是“看起来都在跑实际没人验证准确性”。我上线前会做三组测试。5.1 一键体检solidtime-cli doctor 查了哪些项SolidTime 自带一个诊断命令我的验证流程会先跑它solidtime-cli doctor正常输出大致是[OK] system clock synchronized: yes [OK] drift from reference source: 8.2ms [OK] majority source available: 3/3 [OK] data directory writable: /var/lib/solidtime [OK] scheduler persistence: enabled [OK] api endpoint reachable: https://127.0.0.1:11811其中我最关注的是drift from reference source它表示当前系统时间与 SolidTime 对齐后时间的偏差。稳定运行后这个值最好在 10 毫秒以内。如果偏差持续变大说明系统底层的 chrony 也没能把时钟稳住需要回头检查系统时钟源。5.2 模拟故障的三组结果我习惯在预发环境把服务搞坏几次观察它的恢复行为。三组测试结果很有参考价值测试场景操作方式预期结果实测恢复时间进程被杀kill -9主进程systemd 在 5 秒后拉起历史任务不丢约 6 秒上游 NTP 断网临时切断 UDP 11812 端口节点进入保守模式保持内存中含已知时间样本不产生新调度恢复网络后 15 秒内重新同步时钟回拨 1 秒临时执行date -s -1 second任务调度器拒绝在回拨窗口内触发任务并记录保护日志回拨异常解除后自动恢复第三组最容易出问题。时钟回拨如果发生在任务触发的瞬间可能导致任务时间戳是“过去时间”下游系统会认为数据过期。SolidTime 的处理方式是检测到回拨后暂停触发直到时间重新单调推进再过几秒才继续。这个行为要在预发环境里真实验证一次不要只信文档。5.3 业务接入先用命令行验证再接 SDK上线前我做了最直白的接口验证用一个 token 请求时间戳接口curl -sk https://127.0.0.1:11811/v1/timestamp \ -H Authorization: Bearer $SOLIDTIME_TOKEN返回示例{ epoch: 1736300000123456789, leap_indicator: no-warning, source_count: 3 }epoch是纳秒级单调时间戳source_count表示当前参与对齐的时间源数量。这个时间戳比单纯调系统 API 更可靠因为它是 SolidTime 在应用层完成多数对齐后签发的结果。后续业务接入只要统一走这个接口所有节点拿到的时间口径就完全一致了。6. 运行期踩过的四个坑监听、SELinux、时区与磁盘服务跑起来之后我陆续处理过几个实际故障每个都值得单独写一笔。6.1 “服务显示 active端口却连不上”IPv6 监听单向问题有一次在预发环境里部署后systemctl status solidtime显示服务正常运行ss -lntp也能看到端口监听但其他机器访问 11811 就是超时。后来仔细看发现监听地址是:::11811也就是只监听了 IPv6防火墙放行时只放行了 IPv4 段。解决方法很直接在配置里把server.bind从::改成0.0.0.0或者在防火墙里同时对 IPv6 放行。我最终选了前者因为实例暂时没有 IPv6 需求尽量简化网络路径。验证监听状态用ss -lntup | grep 11811看到0.0.0.0:11811才放心。6.2 SELinux 拦截日志写入从审计日志到正确调法Rocky Linux 的 SELinux 默认 enforcingSolidTime 默认写的几个路径可能不在允许列表里。第一次跑起来后我发现数据目录写不进文件但服务没退出只是不断重试。查看系统日志能看到 AVC 拒绝记录ausearch -m avc -ts recent输出里会明确看到denied { write }和具体的路径。处理方式有两个方向如果目录是标准数据目录建议给该路径设置正确的文件上下文而不是直接setenforce 0关掉 SELinux。可以用semanage fcontext -a -t var_lib_t /var/lib/solidtime(/.*)? restorecon -Rv /var/lib/solidtime关掉 SELinux 虽然一时省事但后续系统加固审计时会很被动。让它正常工作才是正路而且配置一次后面基本不会再遇到。6.3 时区缩写造成提前 8 分钟触发这个名字听起来夸张但真实发生过。我在一个任务配置里填了timezone: CST本意是北京时间结果任务的执行时间漂了不止 8 分钟。原因是CST这个缩写有歧义它可以代表 China Standard Time也可以代表 Central Standard Time美国中部时间和 Cuba Standard Time系统识别成了美国中部时间导致执行点偏移到不对的位置。从那之后我定了一条规矩配置里一律用 IANA 时区名比如Asia/Shanghai、UTC绝对不用三字母缩写。虽然写起来长但歧义彻底消失。DI 在审计时间戳时遇到缩写也应该在源头就把它拦下来。6.4 数据目录无节制增长保留期与轮转缺一不可运行两周后我发现/var/lib/solidtime的数据增长比预期快。任务执行历史、时间戳样本、审计日志三块都往里面写如果不在配置里设置保留期很快会吃满数据盘。我最后在配置里明确了清理策略persistence: retention_days: 90 max_history: 200000 prune_interval: 24h日志部分再用 logrotate 做轮转。这里最关键的是prune_interval不是等磁盘满了才清理而是每天执行一次数据清理保留最近 90 天。上线前我把这个参数调成1h观察过一轮清理行为确认旧数据能被正确删除后才改回24h。任何自动清理策略都要先在预发环境验证避免误删后续审计需要的数据。7. 我的实际体会与接下来可以扩展的方向整套部署做完我最深的体会是时间同步服务本身并不复杂复杂的是它和周边环境的耦合。系统时钟、防火墙、SELinux、时区口径、数据保留任何一个环节不严SolidTime 都很难稳定工作。尤其是时区和时间戳口径这一层如果不提前约定好后面接多少个业务系统就会冒出多少个“时间对不上”的问题。如果让我再做一次我会在项目一开始就把“统一时间戳接口”定义成基础设施而不是临时加装的中间件。所有业务模块的时间来源都走 SolidTime审计系统直接消费它的时间戳这样即使以后机房扩容、跨时区部署时间层面的适配成本也会小很多。后续我计划把 SolidTime 的指标接入监控面板重点盯 drift 和 source_count 这两个指标做到时间源异常时能第一时间收到告警。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑