内容简介:从遗留技术栈升级里,我学到的八件事
几周前,当我使用 Mifa 主题刷新我的博客时,我发现了一件不得了的事情:我的博客使用的 Python 版本是 2.7,而不是我预期的 3.5。并且我用的 Django 版本是 1.9,它是 2015 年的版本。这些让我意识到,如果我再不做点什么,我的博客可能就维护不了了。
毕竟 Django 已经 2.0 了,而 Python 2.7 即将(好多年了)成为过去式了。
尽管我在之前的文章,讲述了一系列的遗留系统的问题,其中之一就是遗留技术栈。因为技术栈老旧而导致系统难以维护,并不是我们想要的结果,只是当它并不是我们的第一优先级事务时,短期的技术栈老旧也是可以接受的。
于是,我决定要去升级我的博客的技术栈了,理想中的步骤很简单:
- 升级核心框架
- 迁移应用代码
- 迁移数据库
只是在这个过程中,遇到一系列的坑。真实的步骤如下所示:
- 创建全新的环境
- 使用线上的数据进行测试及数据库迁移
- 更细力度的版本管理控制,方便回滚
- 优先升级次要组件的版本,以方便向上兼容性
- 一步步升级核心框架
- 必要时,自己编写组件代码
- 清理掉不需要的代码、文件
- 上线前使用线上的环境进行预部署
接着,让我来一步步复述这个过程。
1. 创建全新的环境
如上一篇文章《 荐书《遗留系统:重建实战》:当你面对一坨代码时,你应该这么做 所说,我们应该对环境搭建这个任务进行计时,以便于找出系统的瓶颈。
首先,我遇到的第一个问题是:MBP 上没有环境。因为之前笔记本的硬盘坏了,上面的大部分资料都丢失了,因此我需要从头搭建一个环境。
对于我而言,这是一次相当不错的机会,它可以验证系统的本地配置是不是正确的。然后,我发现新的系统上也没有安装 virtualenv,于是不得不重从搭建一个环境。
然后,我按照我在博客源码上的 README,发现并没有搭建成功。这种感觉就像你拿着一本产品说明书,发现上面说的都是错的一样。
简单的总结一下这个阶段的几个原因:
-
本地配置文件
local_settings.py
文件不存在 - 没有对数据为空的情形进行判断
当然还有其它一些问题,让我再细细说来。
2. 使用线上的数据进行测试及数据库迁移
在我早期的项目中,我们一般会拥有一份半年前的线上环境,用于在 staging(模拟环境)环境上进行测试。它可以用数据证明,这些功能本身是相当可靠的。
搭建环境的过程中,我尝试创建一个全新的测试数据库。但是,想一想发现这样做容易出现问题,于是便想找份线上的环境的数据库进行测试。虽然我并没有将我的各种环境充分的自动化,但是我会定期手动将数据库(SQLite3)备份到 AWS S3 上——我最初选择使用 SQLite 3 的主要原因是,备份方便,不需要占用额外的服务器资源。 对于一般的应用来说,使用 MySQL/MariaDB 才是正确的选择 。SQLite 3 是我在博客设计初期做的一个错误的决策,当时 Too Young。未来,可能会将数据库切换到 DynamoDB 上。
再回到线上数据的这一问题上,除了应对数据本身的变化之外。还有一点是,Django 或者 Mezzanine 在升级的时候,都需要进行 数据库迁移 。
我之前将 Mezzanine 1.3 升级到 Mezzanine 3.0 的过程中,遇到一系列的数据库问题,最后不得不重建数据库。这个惨痛的经历告诉了我,数据库迁移是一个大坑。
3. 更细力度的版本管理控制,方便回滚
是的,即使你更新了个小依赖,也要确保使用了版本管理。它可以让我们随时能回滚到上一次个性,以确保迁移的正常。
如果你在某一时刻,你同时更新了 A、B、C 依赖,那么可能因此修改大量的代码。而在修改代码的过程中,一旦出错的话,那么回滚的难度就变得相当的大。
于是我提交的步伐,比以往的正常时候都更小了。小到只更新一行配置,我也会做一个提交。
反正最后是迁移成功了,不能证明这个策略是不是对的。但是,这样做是对的。
4. 优先升级次要组件的版本,以方便向上兼容性
对于项目中用到的一些辅助软件,如使用 djangorestframework
作为 RESTful API 框架,我优先升级了它们。对于这些框架而言,他们在兼容低版本的同时,也会兼容更版本的软件。但是高版本的 Django,有可能并不会兼容低版本的其它软件。因此,优先升级这些组件,可以保证核心组件可以更容易迁移。而不是在升级核心框架的同时,查看是否有这些次要组件带来的问题。
过去我一般不会采用固定依赖版本的方式来运行部署,如 Ruby 中的 Gemfile,Node.js 中的 Yarn.lock,Python 中采用的方式是:
django==1.10.7 Mezzanine==4.2.3 bleach==1.5 djangorestframework==3.7.7 django-uuslug django-cors-headers djangorestframework-jwt django-widget-tweaks==1.4.1 markdown==2.6.11
如上所见,我只会在重要的组件中,采用 fix 的版本号,主要是为了方便升级。对于次要组件来主,这种策略相当的成功。
5. 一步步升级核心框架
好了,现在到了最大的坑里,升级 Django 版本。
事实证明,直接对着 CHANGELOG 来修改代码,是最简单的一种升级方式。
起先我直接改 Django 改成了 2.0.1 版本,发现一系列的不兼容——主要是 Mezzanine CMS 引起的问题,于是只能转到 1.10.7。
然而,从 1.9.6 到 1.10.7 算是一个大的升级,为 2.0 移除了一系列不兼容的 API,如:
- 新的 TEMPLATES 配置,旧的版本中使用多个模板配置,而新的版本中只需要一个配置即可。
-
旧的
urls.py
全部升级,在新的 Django 中统一了路由的写法。 -
不再需要的
future
标签,future 可以在低版本的 Python 上运行一些新的语言特性。
在迁移的过程中,还发现了一个第三方组件不支持新版本的 Django。
6. 必要时,自己编写组件代码
使用开源软件,便意味着:在你使用的过程中,作者有可能随时会弃坑;因此,随时要做好填坑的准备。在我迁移的过程中,也遇到了这样的问题。
默认使用的 markdown 编辑器, mezzanine_pagedown
中的 urls.py
使用的 pattern 已经被抛弃了。而这个 repo 几乎已经陷入了不维护的状态,于是我只得引入这个库到我的项目中,然后自己去修复这些问题。
好在升级起来还是蛮很容易的,后来仔细一读代码发现,这个库只是对 markdown 库进行了一些封装。因此,自己动手写了一个 markdown 的封装。
7. 清理掉不需要的代码、文件
早期使用 python manage.py collectstatic
的时候,留下了不同版本的静态文件,如早期的 jQuery 1.4.2、jquery-1.7.1.min.js、jquery-1.7.2.min.js 等等。
因此,便直接删除了旧的静态文件,这些文件有:
- 静态文件库
- 不使用的代码
就现在而言,清理这些旧文件,并不会带来额外的收益。但是,未来就不好说了。
8. 上线前使用线上的环境进行预部署
我在我的服务器上获取最新的版本,创建了新的虚拟环境,然后测试:
python manage.py runserver 8888
代码看来似乎是好的,于是我更新了启动脚本里的 虚拟环境
的路径,并使用启动脚本来运行服务。结果,系统并没有启动起来——原因是少了 gunicorn。
我忘了在 requirements.txt
中加油入 gunicorn
的依赖,
于是,我重新启动了服务,打开了 phodal.com,发现 500 了又。mdzz,
去看了看日志,发现线上使用了 memcached 作为数据缓存,这个配置写在 local_settings.py
文件中,但是没有添加在依赖中。
怪我咯。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Haskell School of Music
Paul Hudak、Donya Quick / Cambridge University Press / 2018-10-4 / GBP 42.99
This book teaches functional programming through creative applications in music and sound synthesis. Readers will learn the Haskell programming language and explore numerous ways to create music and d......一起来看看 《The Haskell School of Music》 这本书的介绍吧!