You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EVM代码版本存储机制、OTP热重载作用及Erlang热重载原理探究

哈喽,我来帮你把这些问题拆解清楚,结合Erlang/Elixir生态的实践来解答:

问题1:Erlang VM(EVM)代码版本存储与OTP在热重载中的角色

先澄清下,这里你提到的EVM应该是指Erlang Virtual Machine(Erlang虚拟机)对吧?咱们分两部分说:

  • EVM存储代码版本的方式:Erlang VM会为每个加载的模块维护版本信息,模块的版本通过编译时的标识(比如编译时间、校验和)来区分。当一个模块被加载后,VM会把它的版本数据存在内部的模块表中。每个Erlang进程在调用模块函数时,会绑定到它启动时加载的模块版本——也就是说,旧进程会一直使用旧版本的代码,直到进程退出或者主动触发代码切换。
  • OTP在热重载中的核心作用:OTP不是单纯提供热重载的工具,而是定义了一套平滑热替换的标准流程:
    • 提供了基础的代码加载API,比如code:load_file/1、code:purge/1,用来加载新模块、清理无引用的旧模块;
    • 所有OTP行为模式(比如gen_server、gen_statem、supervisor)都内置了code_change/3回调函数,让开发者可以在热重载时处理进程状态的迁移——比如把旧版本的进程数据转换成新版本能识别的格式,保证服务不中断;
    • 监督树结构确保了进程在热重载时的稳定性,比如如果某个进程在代码切换中出现问题,监督者可以自动重启它,避免整个服务崩溃。
问题2:Erlang热重载工作原理与Ranch的实践

Erlang的热重载是它的核心特性之一,咱们先讲原理,再结合Ranch的场景说实践:

Erlang热重载的核心原理

Erlang热重载的本质是代码多版本共存+进程平滑切换,关键步骤如下:

  1. 编译新模块:将修改后的代码编译成.beam文件(Erlang的字节码文件);
  2. 加载新模块到VM:通过code:load_file/1或者工具(比如Elixir的r/1命令)将新模块加载到VM中,此时VM中同时存在旧版本和新版本的模块;
  3. 进程代码切换:对于使用OTP行为的进程,会触发code_change/3回调,开发者在这个回调里处理状态迁移,进程会从旧版本代码切换到新版本;而普通进程如果没有绑定OTP行为,会继续使用旧版本代码,直到进程退出;
  4. 旧版本清理:当没有任何进程引用旧版本的模块时,VM的垃圾回收机制会自动清理旧版本的代码。

Ranch中的热重载实践(保持TCP连接)

Ranch作为Erlang生态中常用的TCP池库,它的设计天然适配Erlang的热重载机制,能保证TCP连接不中断:

  • Ranch的架构分为监听进程和工作进程:监听进程负责接受新的TCP连接,然后把连接交给工作进程处理。热重载时,监听进程可以通过OTP的code_change回调平滑切换到新版本代码,不影响已经建立的连接;
  • 已经建立的TCP连接由工作进程维护,这些工作进程如果需要更新代码,不需要立即中断连接——可以等当前请求处理完成后,通过监督树重启工作进程,或者在code_change中完成代码切换,保证连接始终保持;
  • 你提到的测试方式(用mix run或iex -S mix启动服务,telnet localhost 8000测试),实操时可以这样验证:
    1. 启动服务后,用telnet建立连接并发送请求;
    2. 修改Ranch的回调处理模块(比如自定义的ranch_protocol实现),重新编译;
    3. 在iex中执行r YourModuleName重载模块,或者调用:code.load_file(YourModuleName);
    4. 此时已有的telnet连接不会断开,发送请求依然能正常处理;新建立的telnet连接会使用新版本的处理逻辑。

内容的提问来源于stack exchange,提问作者LoranceChen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:17:49