我们有一个 Django 应用通过 uwsgi 跑在阿里云的 ECS 上,所用的系统是 Ubuntu 16.04,uwsgi 是通过 supervisord 来管理的,每个应用都在单独的 virtualenv 中运行,这就是大概的软件运行环境。
因为一些软件没有升级,阿里云一直提示存在安全漏洞,所以我就想把 ECS 上的系统升级一下。升级的过程并没有什么什么问题,毕竟用的阿里云自己维护的源,基本上不会出现什么版本依赖之类的问题。
出错场景
升级完成后重新启动 Django 应用,发现应用启动不起来,uwsgi 报错
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
ImportError: cannot import name 'HAS_TLSv1_3'
原因分析
从异常入手查找原因
抛出的异常意思是在_ssl
模块中没有HAS_TLSv1_3
的属性,于是我就去Python 文档中查询了一下这个属性,它的解释是这样的:
ssl.HAS_TLSv1_3
Whether the OpenSSL library has built-in support for the TLS 1.3 protocol.
New in version 3.6.3.
看到New in version 3.6.3.
的字样,再去查系统的升级记录,我发现刚刚执行的升级中就把宿主机的 Python 从3.6.2升级到了3.6.3,此时我隐隐约约觉得就是因为此次升级导致了 uwsgi 启动时的报错。
但我升级的是宿主机的 Python,它又是如何影响到了 Virtualenv 中的 Python 呢?各位别急,我们接着往下挖。
HAS_TLSv1_3
的定义
我们接着再去看抛出异常的那行代码,它在 Python 的标准库的ssl.py
的118行,具体内容如下:
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
我们可以看到,抛出异常就是因为Python解释器从_ssl
模块中导入HAS_TLSv1_3
时,出现了导入异常。
而_ssl
模块是用C语言编写的,它被编译进入了Python解释器中,它的代码位于 Python 源码的