Browsed by
Category: 学习

学海无涯

parseInt

parseInt

云通信系统的用户偶尔向我们反馈,分机的状态显示总是离线状态。我们从后台检查状态是正确的,检查其他用户的分机状态也都很正常,但是这位用户查询的结果确实总是离线状态。这事颇有些蹊跷,引起了我很大的兴趣去研究发生了什么。

检查之后的结果也很简单。后台返回的状态数据是字符串形式,而前端 javascript 脚本是按照整数进行判断,自然无法正常显示状态。但是为什么有些又能正确显示呢?

进一步检查后发现这与 MySQL 数据库的版本有关。我们的云系统有很多服务器,都是采用 Debian 的系统,同时也是采用 Debian 默认自带的数据库。旧 Debian 系统中的 MySQL 数据库版本比较陈旧,返回查询结果时都是采用字符串格式,哪怕字段是整数类型,返回的结果也是转换成字符串。而新的 Debian 系统已经将默认的数据库替换成 MariaDB,返回结果时严格遵循字段的类型,不会进行这类转换。

用户的虚拟通信系统部署在不同的 Debian 节点上,返回查询结果时就存在上述转换方面的差异。

解决方式自然也不复杂。可以从服务器端解决,也可以从前端解决。服务器端升级 Debian 系统就会同时将数据库升级到 MariaDB,自然就能返回整数类型的结果。当然也可以从 PHP (包括 pdo层)解决,由 PHP 对查询结果强制进行转换,将字符串又转换成整数即可。但是出于稳定性方面的考虑,我们一般不太愿意直接升级服务器系统(包括 PHP 等中间层),各节点的升级总是按年制定计划,不太可能为了这样一个小问题兴师动众地升级系统。

因此最后的解决方案就是对前端 JavaScript 脚本做一点修改。JS 提供了 parseInt 函数进行转换(如果是浮点数就是 parseFloat),无论服务器返回的是字符串还是整数,经转换后都可以按照整数进行判断。

此事反映出(1)我们对web、数据库等方面的技术技能比较欠缺,缺乏足够理解;(2)测试范围不够广泛,没有涵盖所有的用户类型;(3)系统配置不够一致,存在新旧并存的现象。我个人觉得后续工作要着力解决第(3)点的情况,尽量做到(包括开发、测试、线上)只有一个版本、只有一种系统。

Windows 10 启动慢

Windows 10 启动慢

小孩用一台 ThinkPad 笔记本上网课,最近发现启动很慢,启动阶段往往耗时将近 3 分钟。这台笔记本是我以前开发工作的笔记本,已经升级了 SSD 硬盘、加装了 16G 内存,似乎不应该这么慢。

孩子反映以前也很快,只是最近才变慢,因此怀疑是某次 windows 升级后(当然也不排除小孩误操作)改动了设置。在网络上搜索了一下,检查启动配置后发现被设置为“正常启动”,修改为“有选择地启动”后,启动时间缩短到十几秒。

修改方式很简单,如下:(1)按键 Win+R 后,输入 msconfig,启动管理界面。(2)设置为“有选择的启动”。

配置“有选择的启动”
有选择的启动
奇怪的 SIP 呼叫流程

奇怪的 SIP 呼叫流程

最近几天帮助泰国的朋友检查一个呼叫业务流程,其中涉及很多细节和业务流程,不过让我觉得特别意外的是他使用的 VoIP 运营商的 SIP 呼叫流程。首次遇到这样的流程,请先参考下图的概要描述:

奇怪的 SIP 呼叫流程
奇怪的 SIP 呼叫流程

这个流程的奇怪之处在于:(1)VoIP 运营商发起呼叫时,INVITE 消息的媒体地址居然是“0.0.0.0”,这很明确告诉被叫:主叫只发送媒体流、甚至根本不处理媒体流;(2)被叫应答后,VoIP 运营商再次发起 reINVITE 流程,此时才真正指示出自己的真实媒体地址(当然也包括最终的媒体编码)。

通常的 SIP 呼叫流程在发起呼叫时就明确指示自己的真实媒体信息,因此在被叫应答后,没有必要再发起 reINVITE 流程。然而这家运营商为什么要放弃传统做法、采用这么奇怪的流程呢?

这家运营商是美国的一家运营商,而且规模很大,其设备供应商也是一家世界级的大软件公司(非常、非常大),因此这个流程肯定不是随意修改的结果,必定有其特殊的目的。仔细揣摩后,我认为它可能是为了节省媒体资源才这么做。

被叫方一般会振铃几秒、十几秒、甚至几十秒后,才可能应答。另外,呼叫量特别大时,统计上只有10%左右的呼叫最终才会应答。这家运营商采用这个流程,只需要在被叫真正应答之后才开始分配媒体资源,考虑到这是一家规模很大的运营商,这种流程确实可以节省很多的媒体资源。

VoIP 网络往往是主叫播放回铃音,因此这是个非常聪明、折中的呼叫流程,确实只有在被叫侧应答之后才处理真实媒体流。然而现实网络组网是非常复杂的,这个聪明到有些投机取巧的方法有固有的缺陷,请参考下图:

183 带媒体信息
被叫放音,183 消息携带 SDP。

被叫侧如果对接了传统的 PSTN 网络,例如 VoIP 网关,很有可能直接返回 183 消息并携带被叫的媒体信息。传统的 PSTN 网络往往是被叫侧播放回铃音,并且也有一些被叫侧放音的业务(例如“彩铃”),此时这家 VoIP 运营商就有问题了。

由于它告诉给被叫的地址是“0.0.0.0”,因此被叫振铃音(或者业务音)就无法传达到主叫侧。VoIP 运营商可以向被叫发送 UPDATE 消息来传递自己的真实媒体信息,但被叫未必会支持 UPDATE 消息,这个是扩展消息,不是所有的 SIP 设备都必须支持。而且 PSTN 网络往往会要求对 18x 消息用 PRACK 流程确认,因此即便支持 UPDATE 消息,这个特殊流程实际也急剧放大了被叫侧振铃阶段流程的复杂度。

这也就是我们的泰国朋友遇到的问题。

解决方式是在 VoIP 运营商与 PSTN 网络之间架设 miniSIPServer:

(1)miniSIPServer 与 VoIP 之间建立完全应答的呼叫通道;

(2)miniSIPServer 与 PSTN 之间维持正常的呼叫流程;

(3)miniSIPServer 判断被叫侧是否自己放回铃音(或者业务音),如果(a)被叫没有放音,则 miniSIPServer 主动给 VoIP 运营商放回铃音(或者呼叫等待音),而如果(b)被叫有放音,miniSIPServer 则直接建立两边的通道,让主叫直接听被叫的放音。

巴菲特致股东的信(2021,中英文版)

巴菲特致股东的信(2021,中英文版)

巴菲特最新的致股东的信,虽然是2022年写的信,但是内容是总结伯克希尔2021年的年度表现,在伯克希尔官网上也是标记为2021,因此本文的标题也跟随标记为2021年的信(以往是按发表时的年份来标记)。

同时,将巴菲特的信从1977-2021年归纳、汇编到一个文档中,有一些排版上的调整,方便阅读、检索、和学习。

单独翻译了2021年度的信,这两年的信越来越短了,大概很多重复的内容都移到年报中去了。另外一个原因可能是老人家年岁也大了,写信确实也耗时耗力。

最后说明:(1)欢迎转载;(2)转载时请标明来源;(3)未经许可,不得用于任何商业应用。

  • 2021年的信,英文原版;[下载]
  • 1977 – 2021年的信,英文汇编;[下载]
  • 2021年的信,中文版。[下载]
  • 如果您发现翻译问题,请 email 至:Z2lsc29ueWlAbXNuLmNvbQ== 非常感谢!
Debian (bookworm) + php8.1

Debian (bookworm) + php8.1

更新了一下软件库,发现 php 版本升级到 php8.1。不过糟糕的是,升级程序直接卸载了以前的 php7 版本,然后又没有安装 apache2 新的 php8.1 模块,导致 apache2 没有解析和运行 php 文件。

解决方式也简单,重使能模块即可。注意,该命令要用 sudo 权限运行。

sudo a2enmod php8.1

以前升级 Debian 似乎没有遇到这个问题,默认应该就安装新的模块版本,或者保留原有的版本。不知道是不是这个环境的 Debian 是 sid 版本的原因?

2021年读书列表

2021年读书列表

全年看书不多,尤其是最近业余时间都花在研究投资方面,其他杂书都是囫囵吞枣:

巴菲特之道
巴菲特的信(1977-2000)
段永平投资问答录
费雪论成长股获利

查理·芒格传
朱自清散文选
傅雷家书
冯唐:有本事
人类群星闪耀时
蔡澜旅行食记
银河帝国 – 基地七部曲
银河帝国 – 机器人五部曲

现代操作系统原理与实现

openEuler 的苦难体验

openEuler 的苦难体验

下午忙完工作、又临近周末,想着抽点时间体验一下 openEuler 系统,毕竟这是华为隆重推出、并且捐赠的系统,据说会成为国内各大系统的上游版本,有点类似 Debian 的意思。简单查了点资料,openEuler 大概是走 CentOS 或者 RHEL 的路子,着重在企业级系统的开发和部署上,听上去似乎很合我的胃口,我在 Debian 上也主要是开发企业用的软件(比如 miniSIPServer 软件 ^_^)。

从网上下载了 ISO 安装包,名字比较古怪,openEuler-20.03-LTS-SP2。从字面意思大概是 20.03 版本的第二个迭代版本,这个版本是长期支持版本。又顺手查了一下对应的生命周期,“长期”是指5年。这个5年是从20年03月开始算起,不是从SP2 发布开始算起。之所以觉得名字古怪,从网站的内容看,还以为需要下载三个版本,如下图。似乎应该先安装 20.03 LTS,然后安装 SP1,然后安装 SP2,但是看了一下安装包大小,没可能一个补丁那么大啊,这是学习 Windows 的命名方式? 事实证明,直接下载、安装 SP2 就可以了。

openEuler 下载页面
openEuler 下载页面

下载 iso 包中断了几次,显然是我的 300M 光纤宽带不够给力。转到阿里云的镜像站点下载,同样在中断几次之后,终于下载成功。

手头上没有实机,因此只能麻烦 openEuler 在 VirtualBox 中先凑合一下了。

第一次安装……失败。安装界面的按钮居然是在左上角!我一直按照以往的经验在右下角找“下一步”按钮,以为是 VirtualBox 的原因导致无法显示按钮。愤怒地升级 VirtualBox 后,重新安装,终于无意中找到了左上角的按钮……对不起,VirtualBox,错怪你了。

第二次安装……失败。安装倒是顺利完成,进入黑暗的命令行界面,然后……网络不通!难道要自己从命令行配置网卡、路由?我只是 Linux 用户,不是专家,书到用时方恨少。一定是哪出错了,以前安装别的发布版本(我的意思是 Debian 或者 Ubuntu),从来没出现这么奇怪的要求。上网查了安装指导文档(请点击此处),果然是自己没注意安装界面中开启网络。

第三次安装……失败。同样顺利地完成安装,进入无比黑暗的命令行界面,然后……网络还是不通!重新看文档,怪自己太粗心。原来安装时开启网络,只是在安装时有效,不等于安装后自动开启网络(真的,这个说起来有点挠头),需要在安装时,进入网络属性配置里,选定“自动以优先级连接”,然而这个项在界面里是英文 Connect automatically with priority(中英文混杂,很有港味、很 fashion!):

openEuler 网络配置
openEuler 网络配置项

第四次安装……失败。精心配置好网络,选中必要的选项,顺利进入依然黑暗的命令行界面,然后按照文档的指导(请点击此处)安装 XFCE,太棒了!重启后看到了久违的图形界面,然后登录……然后登录……然后登录……(很不幸,每次输入用户密码后,闪一下,又回到输密码的界面)

第五次安装……失败一半。淡定地配置好网络,进入暗黑无界的命令行界面,然后按照文档的指导(请点击此处)安装 DDE 界面。不愧是国产精品,非常顺利,这次可以登录,也可以使用各种软件了!只是有个小小的遗憾,系统没有自动调整界面大小,因此整个图形界面小小的。这个我懂,安装 VirtualBox 增强功能就可以了。将 VirtualBox 增强功能的虚拟光盘手工 mount 到目录后(Debian 以及后续尝试的 CentOS 都可以自动mount),运行编译,很快就……失败了!查了一下log,是调用 access_ok 函数时出错,从网络上检索的信息看,大概是 openEuler 合并了 5.x 内核的代码,但是自身内核版本号还是 4.x,企业级 Linux 玩得这么骚气吗? CentOS/RHEL 也这样? 要搞定这个问题,需要改源码……我只是想安装 openEuler 体验一下……

但是 DDE 确实值得一提!速度非常快,如果不是上述界面过小的原因,那就是 DDE 这两年进步确实很大。以前曾经体验过 Deepin 的版本,当时感觉界面还比较混乱、速度也不太让人满意,这次大有改观。唯一奇怪的是,我觉得“高效模式”比“时尚模式”更好看,这大概是我自己杀马特审美的错。

五次安装之后,窗外的天空已经黑得像个命令行界面,我沉痛地决定放弃了,下一个 LTS 版本出来后再体验吧。

2021-11-27 更新:

考虑到 openEuler 的令人迷惑的行为,是否是目前 RHEL/CentOS 系列的常态?下载了 CentOS stream 8(也是个令人迷惑的版本)安装,对比 openEuler 确实大部分都相同,当然也有小部分不一样:

(1)安装按钮都在左上角。看来这是新一代安装工具的标配了。

(2)网络配置默认都没有打开,都需要手工打开,而且要修改配置中的项才能在安装后自动启动网络。但 CentOS 的完成度明显更高,至少界面语言是统一的,没出现混杂的情况。

(3)CentOS 的软件设置更丰富,实际上丰富很多。安装完成后,可以直接进入图形界面。

CentOS 软件选择
CentOS 软件选择

(4)安装完成后都无法安装 VirtualBox 增强功能。CentOS 的 log 显示的是另一个与“map_vm_area”函数相关的错误。简单检索后得出相同的结论:也是 merge 了 5.x 内核的内容,但是内部版本号还是停留在 4.x。 企业级 Linux 玩得这么骚气,有点令人意外,这和掩耳盗铃有什么区别?

2021-11-27 再次更新:

由于 openEuler 和 CentOS Stream 都遇到了无法正常编译 VitualBox 增强工具的情况,都需要修改增强工具的源码才能编译成功,因此思考 VirtualBox 自己是不是会解决这个问题? 查了一下 changelog,在 VirtualBox 6.1.20 版本的发布日志中明确提到:

Linux Guest Additions: Fixed kernel module build for RHEL 8.4 beta and CentOS Stream

看起来的确是解决了问题,因此重新下载最新的 VirtualBox V6.1.30,果然成功了! 如下图示:

CentOS Stream 完全展开
CentOS Stream 完全展开

解决完CentOS Stream的问题后,猜测 openEuler 是否也可以一起解决了? 于是第六次安装 openEuler,然后……失败了。看来 VirtualBox 并没有解决 access_ok 函数的问题,估计 openEuler 相关人员也没有提交类似的问题给 VirtualBox ……

Apache 日志分析工具:goaccess

Apache 日志分析工具:goaccess

如果统计、分析网站日常的访问情况,无疑优选 Google Analytics。不过由于众所周知的原因,访问稍显麻烦,而且有时候希望了解更细节一些的东西,因此最好直接检查 Apache 的日志来获取相关信息。日常维护时,同步检查日志也有助于尽早发现问题。

推荐采用一个非常小巧的工具:goaccess,这个工具基本不依赖第三方库(似乎有一个地理位置信息的库),Debian 系统自带,使用也非常简单,呈现的信息足够丰富、有序。

使用以下命令安装:

sudo apt install goaccess

可以直接读取 Apache 的日志文件进行分析,例如:

goaccess /var/log/apache2/access.log

Apache 的历史日志都保存为 .gz 格式,可以直接重定位方式进行分析,例如:

zcat -f /var/log/apache2/access.log*.gz | goaccess --log-format=COMBINED

goaccess 还有其他一些很棒的功能,例如实时显示、html格式等,有兴趣的话可以进一步了解。日常维护则上述命令足以。

公共 DNS 服务器

公共 DNS 服务器

在路由器配置中,通常可以指定 DNS 服务器,如果不单独指定,那默认就是运营商给定的 DNS 服务器。考虑到国情在此,建议指定 DNS 服务器。

国内有很多家服务商能提供公共 DNS 服务,例如腾讯(DNSPod)、阿里等。综合这几年的使用情况看,采用腾讯和Cloudflare 两家的 DNS 服务器作为主备,对于我(坐标:深圳电信)是个比较好的选择。

通常,我设置 Cloudflare 家的 DNS 服务器作为主服务器,腾讯家的 DNS 服务器作为备用服务器。这两家也都支持 IPv6 以及 DoH 等,充分满足需要,下面列示这两家的信息。

Cloudflare:

IPv4: 1.1.1.1
IPv6: 2606:4700:4700::1111
DoH:  https://cloudflare-dns.com/dns-query

腾讯:

IPv4:119.29.29.29
IPv6: 2402:4e00::
DoH:  https://doh.pub/dns-query

如果使用 Firefox 浏览器并采用 DoH,默认就是 Cloudflare 的 DoH,无需额外配置。

Firefox 中的 DoH 配置
DoH in Firefox

Javascript 模板字符串

Javascript 模板字符串

在编写 JS 代码时(例如我们的小网站、或者 miniSIPServer 的 web 管理界面),拼接字符串是件很头疼的事情,尤其是字符串本身又可能包含单引号(‘)或者双引号(“)的情况时,简直头晕眼花。

显然,这样的痛苦不是仅仅一小部分人才有,因此有人(ES6规范?)聪明地引入了“模板字符串”这么一个语法糖,顺利解决了问题。在 JS 文件中,采用反单引号“`”,即键盘左上角那个引号,和“${}”即可完成拼接,如以下示例:

<div>`My name is ${usrName}`</div>