运维咖啡吧

享受技术带来的乐趣,体验生活给予的感动

从ansi_up到xterm提升了几十倍性能

无论是任务系统还是作业系统都会去执行linux命令或脚本,命令或脚本的输出也会实时展示在Web页面上,在终端中执行命令或脚本可以输出颜色,主要是因为这些有颜色的文字周围包含了颜色相关的ANSI码,例如:\033[31m运维咖啡吧\033[0m

如何在Web页面上输出时同样展示颜色呢,这里我用到了ansi_up.js,ansi_up是一个简单易用的Javascript库,可将包含ANSI颜色转义码的文本转换为HTML。纯前端插件使用起来确实简单,只依赖一个js文件,示例代码如下:

<script src="../ansi_up.js" type="text/javascript"></script>
<script type="text/javascript">
  var ansi_up = new AnsiUp;

  var string  = "\033[35m 运维咖啡吧 \033[0m"
  var html = ansi_up.ansi_to_html(string);

  $('#J_details').append(html);
</script>

这么使用一直没有问题,直到刚刚,小伙伴跟我说,执行了一个作业,日志输出到一半开始报错,之后前端页面直接卡死无法使用,简单排查就定位到了问题,这个作业是去一组主机上过滤日志文件输出错误日志,错误日志太多执行结果较大,不过也就2MB,ansi_up性能有限已经无法渲染,问题定位到了,如何解决

我先是查了ansi_up的文档,没有找到解决的方案,然后问了最懂程序员的AI搜索引擎,他给了我答案

修复ansi_up.js这个难度太大,Jupyter这个也不懂,但是xterm.js我熟啊,之前在做webssh项目时就是通过xterm.js来实现前后端的实时交互的。xterm是一个专业的前端终端组件,可以直接在浏览器中实现一个命令行终端应用,功能强大、配置复杂,但基本使用较为简单,示例代码如下:

<html>
  <head>
    <link href="/static/plugins/xterm/xterm.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div id="terminal"></div>

    <script src="/static/plugins/xterm/xterm.js"></script>
    <script>
      var term = new Terminal();
      term.open(document.getElementById('terminal'));
      term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
    </script>
  </body>
</html>

通过term.write写数据,实际测试下来,一次性60MB的数据也能正常渲染,几十倍的性能提升,是真的强大。虽然这个问题解决了,渲染恢复了正常,但发现了更为严重的问题,作业执行过程中日志是先写入缓存的,日志输出太大会导致缓存被占满从而进程OOM,同时日志展示也不会分页,一次请求占用几十上百MB的内存,很快就导致系统OOM

日志输出太多实际上就失去了意义,根本也看不过来,由于大量的数据传输,前端体验也会变差,还提升了系统OOM的风险,限制日志输出大小似乎成了最好的解决方式,说干就干,代码比较简单

# 输出日志超过2M则强制结束
if len(old_log) > 2 * 1024 * 1024 or len(new_log) > 2 * 1024 * 1024:
    details = '输出日志超大,当前作业已被系统强制结束'

判断下当前的日志记录大小以及新产生的日志大小是否超过2MB,如果超过则直接终止作业,同时提示用户调整

至此问题才算完全解决。我不禁在想,我们都喜欢自由,不设限制,但有些时候受限才是为了更自由