ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Erlang/OTP 嵌入式系统启动脚本 start 完全指南:从 run_erl 到 start_erl 的 Unix 启动链路解析

Erlang/OTP 嵌入式系统启动脚本 start 完全指南:从 run_erl 到 start_erl 的 Unix 启动链路解析 编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载本文以 ERTS 官方手册页 start_cmd.md 为核心骨架结合 OTP 仓库中真实的start脚本源码、start_erl/run_erl手册及release_handler实现系统讲解 Erlang/OTP 在 Unix 嵌入式目标系统上的启动机制。读完你将掌握start脚本的用法与参数、start_erl.data数据文件的格式与升级语义、日志与进程管控手段并能独立定制一套适用于自身嵌入式设备的启动脚本。一、start脚本是什么在 Erlang/OTP 中start是一个面向Unix 嵌入式系统embedded target system的示例启动脚本。官方手册页对它的定位只有一句话“OTP start script example for Unix”即它是演示“如何在 Unix 上以嵌入式模式embedded mode启动 Erlang 系统”的样板脚本。嵌入式模式与普通交互式开发模式的关键区别在于嵌入式系统通常没有交互式 shell、没有键盘显示器Erlang 虚拟机需要作为系统守护进程在开机时自动拉起并且要能够承受节点重启、日志落盘、远程接入调试等生产环境诉求。start脚本正是这条链路的总入口。该脚本的真实实现位于仓库 erts/etc/unix/start.src其头部注释明确写道# This program invokes the erlang emulator by calling run_erl. # It should only be used at an embedded target system. # It should be modified to give the correct flags to erl (via start_erl), # e.g -mode embedded -sname XXX # # Usage: start [Data]注意两点start必须由使用者根据自身系统修改如追加-mode embedded -sname XXX它是四个启动程序中唯一需要用户动手定制的程序它本身并不直接启动 beam 虚拟机而是通过run_erl间接调用start_erl再由start_erl调用对应版本的erlexec拉起仿真器——这是一条完整的调用链详见下文第三节。二、用法与参数start的完整用法start_cmd.mdstart [ data_file ]唯一的可选参数data_file— 指定要读取的start_erl.data文件路径。省略时使用默认值。此外在调用start之前可以设置环境变量RELDIR用于指定发布文件release files所在的目录。仓库 erts/etc/unix/start.src 中对应的解析逻辑为if [ -z $RELDIR ] then RELDIR$ROOTDIR/releases fi START_ERL_DATA${1:-$RELDIR/start_erl.data}即若未设置RELDIR则默认取安装根目录/releasesdata_file参数缺省时默认使用$RELDIR/start_erl.data。2.1RELDIR与start_erl.dataRELDIRrelease directory是新发布包的安装目录也是 release handlerm:release_handlerSASL 应用保存发布信息的地方。start_erl.data文件就位于该目录下内容格式为两个空格分隔的字段ERTS 版本号 发布版本号例如安装脚本 erts/etc/unix/Install.src 在安装时生成echo %I_VSN% %I_SYSTEM_VSN% $ERL_ROOT/releases/start_erl.data它告诉start_erl当前系统应该使用哪个版本的erts-版本号目录下的可执行文件、哪个发布目录下的.boot与sys.config文件。每次新发布都会引入新的数据文件该文件由 Erlang 侧的 release handler 自动生成详见第五节。三、启动调用链start → run_erl → start_erl → erlexec嵌入式系统的启动是一个接力过程。系统文档 system/doc/embedded/embedded.md 的“Starting Erlang”一节给出了完整流程机器启动时调用startstart调用run_erl由后者建立管道与日志设施使操作员可以远程接入run_erl执行start_erlstart_erl依据start_erl.data调用正确版本的erlexec位于ERL_INSTALL_DIR/erts-版本/bin并带上正确的-boot与-config参数。仓库中真实的start脚本erts/etc/unix/start.src就是这条链路的落点$ROOTDIR/bin/run_erl -daemon /tmp/ $LOGDIR exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA而系统文档 system/doc/embedded/embedded.md 给出的“默认行为示例脚本”更为直观#!/bin/sh # Usage: start [DataFile] # ROOTDIR/usr/local/otp if [ -z $RELDIR ] then RELDIR$ROOTDIR/releases fi START_ERL_DATA${1:-$RELDIR/start_erl.data} $ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log exec $ROOTDIR/bin/start_erl \ $ROOTDIR $RELDIR $START_ERL_DATA /dev/null 21 下面逐个环节展开。四、run_erl输出重定向、日志轮转与远程接入run_erl是 Unix 专属程序职责是重定向被启动命令的标准输入/标准输出使全部输出可被记录到日志同时让to_erl能连接到 Erlang 控制台从而对嵌入式系统进行远程监控与调试。其用法run_erl_cmd.mdrun_erl [-daemon] pipe_dir/ log_dir exec command arg1 arg2 ...参数说明参数含义-daemon强烈建议使用。使run_erl完全脱离控制终端在后台运行命令立即返回不使用它则需要用 shell 技巧才能彻底脱离终端。必须是命令行第一个参数pipe_dir/命名管道目录通常为/tmp/。必须以/结尾如/tmp/epipes/而非/tmp/epipesto_erl默认也使用/tmp/log_dir日志目录包含一个记录run_erl自身进度与告警的run_erl.log以及最多 5 个、每个最大 100 KB、记录命令 stdin/stdout 内容的日志文件数量与大小均可通过环境变量调整exec command arg1 arg2 ...空格分隔的待执行命令字符串第二字段通常是erl之类的命令名4.1 日志文件轮转机制运行期间run_erl将所有输出原样写入名为erlang.log.N的日志文件N为整数。当日志“写满”默认 100 KB时转而写入erlang.log.(N1)当N达到上限默认 5后N重新从 1 开始最旧的日志文件被覆盖复用。系统文档 system/doc/embedded/embedded.md 给出了滚动序列示例erlang.log.1 erlang.log.1, erlang.log.2 erlang.log.1, erlang.log.2, erlang.log.3 erlang.log.1, erlang.log.2, erlang.log.3, erlang.log.4 erlang.log.2, erlang.log.3, erlang.log.4, erlang.log.5 erlang.log.3, erlang.log.4, erlang.log.5, erlang.log.1 ...每行中最右侧的文件是最新日志。一个细节为标示最新文件run_erl会删除最旧日志以在序列中“留洞”——因此实际存在的日志文件数最多比RUN_ERL_LOG_GENERATIONS少 1。4.2 存活时间戳ALIVE 消息若 Erlang shell 无输出但虚拟机仍存活run_erl会向日志写入一条ALIVE时间戳若 Erlang 有输出但距上次输出已超过 5 分钟默认也会写入时间戳。格式为 ALIVE date-time-string date-time-stringdate-time-string默认按本地时间、以 ANSI-Cstrftime格式%a %b %e %T %Z %Y生成例如 ALIVE Thu May 15 10:13:36 MEST 2003。4.3 run_erl 环境变量run_erl_cmd.md环境变量作用默认值 / 范围RUN_ERL_LOG_ALIVE_MINUTES无输出多久后写ALIVE消息分钟15最小 1RUN_ERL_LOG_ACTIVITY_MINUTESErlang 静默多久后输出加时间戳分钟RUN_ERL_LOG_ALIVE_MINUTES div 3最小 1RUN_ERL_LOG_ALIVE_FORMAT指定strftime格式字符串如%e-%b-%Y, %T %Z可得到15-May-2003, 10:23:04 MET%a %b %e %T %Z %YRUN_ERL_LOG_ALIVE_IN_UTC非0时所有时间以 UTC 显示不影响 Erlang 自身输出SASL 侧可设utc_log应用变量为true对齐0RUN_ERL_LOG_GENERATIONS日志文件份数写满后复用旧文件5最小 2最大 1000RUN_ERL_LOG_MAXSIZE单个日志文件切换阈值字节100000最小 1000最大约 2^30RUN_ERL_DISABLE_FLOWCNTRL定义后禁用 pty 的输入/输出流控避免误按 Ctrl-S 阻塞整个 Beam 进程甚至阻塞作为监督者的 heart 进程写日志未定义4.4 to_erl接入嵌入式控制台to_erl用于附加attach到由run_erl启动的、正在运行的 Erlang 运行时系统Usage: to_erl [pipe_name | pipe_dir]pipe_name默认为/tmp/erlang.pipe.N。接入后即可在 Erlang shell 中执行普通命令按Ctrl-D断开连接而不退出 Erlang 系统。所有经由该 shell 的交互都会被记录到日志目录。五、start_erl读取数据文件并启动正确版本的仿真器start_erl的职责是以-boot和-config参数启动 Erlang 仿真器而这两个参数指向的位置从start_erl.data读取。每个新发布引入新的数据文件该文件由 Erlang 的 release handler 自动生成system/doc/embedded/embedded.md。5.1 Unix 侧的行为示例系统文档给出的start_erl行为脚本#!/bin/sh # Usage: start_erl RootDir RelDir DataFile [ErlFlags ...] # ROOTDIR$1 shift RELDIR$1 shift DataFile$1 shift ERTS_VSNawk {print $1} $DataFile VSNawk {print $2} $DataFile BINDIR$ROOTDIR/erts-$ERTS_VSN/bin EMUbeam PROGNAMEecho $0 | sed s/.*\/// export EMU export ROOTDIR export BINDIR export PROGNAME export RELDIR exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $*即从start_erl.data中解析出ERTS_VSN与发布VSN定位erts-ERTS_VSN/bin/erlexec以-boot RELDIR/VSN/start、-config RELDIR/VSN/sys启动仿真器再追加其余 Erlang 选项如-heart -sname cp1。5.2 Windows 侧start_erl.exe 与分隔符Windows 上的start_erl是一个独立的 C 程序源码 erts/etc/win32/start_erl.c虽然与其他平台同名但功能不同它由erlsrv服务程序调用读取start_erl.data后启动 Erlang并配合 release handler 在“带仿真器重启的升级”中增删-data选项。其用法start_erl [erl options] [start_erl options]必选— 分隔符之前的所有内容作为传给erl程序的选项之后的内容作为start_erl自身的选项。源码中的 split_commandline() 从命令行末尾反向搜索完成切分。start_erl自身识别以下选项选项必选性说明-reldir release root当未设置环境变量RELDIR且未给-rootdir时为必选发布树根目录典型为Erlang root\releasesstart_erl.data默认就位于该目录若只给了-rootdir则假定该目录为Erlang root\releases-rootdir Erlang root directory当未给-reldir且环境无RELDIR时为必选Erlang 安装根目录其下包含lib、releases、erts-Version若只给了-reldir/RELDIR则假定 Erlang 根为发布目录的上一级-data data file name可选指定release root下另一个数据文件相对或绝对路径均可。仅供 release handler 升级时使用正常运行不应使用且数据文件名一般不允许改-bootflags boot flags file name可选相对于发布目录即release root下存放.boot文件的子目录的文件名该文件内容会追加到 Erlang 启动命令行便于为不同发布配置不同仿真器选项在 start_erl.c 中这些选项由 parse_commandline() 解析-data、-rootdir、-reldir、-bootflags、-noconfig随后read_datafile() 用fscanf(fp, %s %s, ver, rel)从start_erl.data读取 ERTS 版本与发布版本——从源码结构看数据文件的“两字段空格分隔”格式在 Windows 与 Unix 两侧完全一致complete_options() 根据RELDIR环境变量、注册表键Software\Ericsson\Erlang\版本等补齐缺失的路径并拼接出erts-版本\bin仿真器目录start_new_node() 用CreateProcessW启动erl.exe -boot VsnDir\start -config VsnDir\sys-noconfig时省略-config并等待其退出、透传退出码。手册同时给出三条运维注意点start_erl_cmd.md源码随发行版分发便于本地定制如循环重启检测但必须保持-data选项的上述语义release handler 才能正常工作仿真器通过注册表键按数据文件中的版本查找升级前新仿真器必须已正确安装start_erl并不绑定某个仿真器版本release handler 在仿真器重启时不会修改erlsrv的-machine选项——请把可能定制过的start_erl放在升级时不会被覆盖的位置。5.3 start_erl.data 与发布升级start_erl.data由 release handler 在安装/升级时写入。在 lib/sasl/src/release_handler.erl 的prepare_restart_new_emulator/5中可以看到升级“带仿真器重启”时的处理Data EVsn Vsn, DataFile write_new_start_erl(Data, RelDir, Masters), %% Tell heart to use DataFile instead of start_erl.data case os:type() of {win32,nt} - write_ini_file(RootDir, EVsn, Masters), prepare_restart_nt(Release, PRelease, DataFile); {unix,_} - StartP check_start_prg(StartPrg, Masters), case heart:set_cmd(StartP DataFile) of ok - ok; Error - throw({error, {heart:set_cmd() error, Error}}) end end.其中 write_new_start_erl/3 把新数据写入RelDir/new_start_erl.data再通过heart:set_cmd/1让 heart 在需要时以新数据文件重启——这正是手册中“-data选项由 release handler 在带仿真器重启的升级中增删”的实现落点。六、把 start 集成进嵌入式系统6.1 开机自启init.d 脚本真正的嵌入式系统必须随系统启动而启动。system/doc/embedded/embedded.md 建议将如下脚本加入/etc/rc3.d文件名推荐为S75otp.system需 root 拥有且可读#!/bin/sh # File name: S75otp.system # Purpose: Automatically starts Erlang and applications when the # system starts if [ ! -d /usr/bin ] then # /usr not mounted exit fi killproc() { # kill the named process(es) pid/usr/bin/ps -e | /usr/bin/grep -w $1 | /usr/bin/sed -e s/^ *// -e s/ .*// [ $pid ! ] kill $pid } case $1 in start) # Start the Erlang emulator su - otpuser -c /home/otpuser/otp/bin/start ;; stop) killproc beam ;; *) echo Usage: $0 { start | stop } ;; esac其中/home/otpuser/otp/bin/start正是本文主角start脚本。文档还提示killproc流程可与erl_call -n Node init stop组合实现优雅停机前提是节点以分布式模式运行killproc本身不能删除其目的是从运行级 3多用户网络切换到运行级 2多用户无网络时停掉 Erlang。6.2 必须设置的环境变量TERM从S75otp.system自动启动时TERM必须设置最小配置为TERMdumb加到start脚本中即可。HEART_COMMAND若用于看门狗重启可设HEART_COMMAND/usr/sbin/reboot此时需将/usr/sbin/reboot权限改为chown 0与chmod 4755详见m:heart手册页。6.3 定制示例命名节点 heart TERM系统文档给出的“给节点命名为cp1、追加HEART_COMMAND与TERM”的定制版start#!/bin/sh # Usage: start [DataFile] # HEART_COMMAND/usr/sbin/reboot TERMdumb export HEART_COMMAND TERM ROOTDIR/usr/local/otp if [ -z $RELDIR ] then RELDIR$ROOTDIR/releases fi START_ERL_DATA${1:-$RELDIR/start_erl.data} $ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log exec $ROOTDIR/bin/start_erl \ $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname cp1 /dev/null 21 注意-heart -sname cp1是追加在start_erl之后的 Erlang 选项会一路透传给最终启动的 beam。6.4 无盘/只读客户端节点若启动的是无盘和/或只读的客户端节点start_erl.data位于主节点的客户端目录START_ERL_DATA行应改为CLIENTDIR$ROOTDIR/clients/clientname START_ERL_DATA${1:-$CLIENTDIR/bin/start_erl.data}同时若 SASL 配置参数static_emulator为truestart_erl的-boot/-config必须改为固定位置客户端无法动态读取新的start_erl.databoot/config 文件始终取自同一位置只是新发布安装后内容更新release_handler会在新发布永久化时把文件复制到主节点客户端目录的bin下exec $BINDIR/erlexec -boot $CLIENTDIR/bin/start \ -config $CLIENTDIR/bin/sys $*6.5 Windows 侧的对应物erlsrv start_erlWindows 嵌入式系统不需要start脚本而是通过erlsrv将 Erlang 仿真器注册为 Windows 服务erlsrv_cmd.md。使用 release handling 时服务的Machine必须设为类似start_erl.exe的程序且Args中要包含及所需选项服务命名必须遵循NodeName_Release约定NodeName为节点名之前的部分Release为当前发布版本。服务环境中额外提供ERLSRV_SERVICE_NAME与ERLSRV_EXECUTABLE两个变量可据此编写 heart 重启命令文件echo off %ERLSRV_EXECUTABLE% stop %ERLSRV_SERVICE_NAME% %ERLSRV_EXECUTABLE% start %ERLSRV_SERVICE_NAME%七、源码中的真实用例与测试佐证仓库里可以找到start脚本的两处真实用法进一步印证其语义安装流程脚本 erts/etc/unix/Install.src 在安装时将start.src中的占位符替换后生成可执行的start并复制到$ERL_ROOT/bin随后L119写入初始start_erl.data形成一套完整的嵌入式目标系统。升级测试测试套件 erts/test/upgrade_SUITE.erl 在构建目标系统时创建start_erl.data与sys.config并从测试数据目录复制start.src、替换其中的%FINAL_ROOTDIR%等变量erts/test/upgrade_SUITE_data/start.src 中可见测试版脚本追加了-sname otp_upgrade -heart用于验证嵌入式启动与升级流程。这些证据表明start不是摆设而是 OTP 嵌入式部署中“安装即生成、启动即使用”的标准入口。八、总结程序平台职责startUnix嵌入式启动总入口唯一需要用户修改调用run_erlrun_erlUnix重定向 stdin/stdout、滚动日志、提供to_erl接入点to_erlUnix附加到运行中的 Erlang shellCtrl-D脱离start_erlUnix / Windows读取start_erl.data以正确-boot/-config启动对应版本仿真器erlsrvWindows将start_erl/erl注册为 Windows 服务掌握这条链路后你就可以根据自己的嵌入式设备定制start设置节点名与TERM、配置HEART_COMMAND看门狗、调整run_erl日志轮转参数、乃至支持无盘客户端的静态启动从而构建一套可远程运维、可平滑升级的 Erlang/OTP 嵌入式运行环境。延伸阅读仓库内start 手册页 run_erl 手册页 start_erl 手册页 erlsrv 手册页嵌入式系统用户指南含to_erl、init.d 集成、客户端节点等完整章节start 脚本源码 Windows start_erl 源码 安装脚本 Install.srcrelease_handler 实现 升级测试套件赞分享编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载相关推荐Erlang/OTP 嵌入式系统守护利器run_erl 命令完全指南Erlang/OTP 嵌入式系统守护利器run_erl 命令完全指南 导读 run_erl 是 Erlang/OTP 运行时系统ERTS中面向 Unix编程语言语言运行时标准库编译器并发编程Erlang/OTP erl_call 命令完全指南从 Shell 脚本远程调用与启动分布式 Erlang 节点Erlang/OTP erl_call 命令完全指南从 Shell 脚本远程调用与启动分布式 Erlang 节点 erl_call 是 Erlang/OTP编程语言语言运行时标准库编译器并发编程Erlang/OTP 嵌入式系统启动器 start_erlWindows 平台 Release 处理与仿真器启动机制深度解析Erlang/OTP 嵌入式系统启动器 start_erlWindows 平台 Release 处理与仿真器启动机制深度解析 导读 start_erl 是 E编程语言语言运行时标准库编译器并发编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表