Gunicorn 驱动工厂模式 Flask 应用

之前用 uWsgi 部署过 Django 应用,但当时的开发和部署都还手生,有很多不合理的地方,最近写的一个 Flask 应用,用了另一个 wsgi 容器 —— Gunicorn,并且利用工厂模式对不同开发环境进行了隔离。工厂模式下的 Flask 应用在用 Gunicorn 部署时,需要做一点针对性的改动。 基础的 Flask 应用部署 先写一个最简单的 Flask 应用 hello: # hello.py from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return "Hello World!" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) 然后用 Python 去解释执行这段脚本即可,Flask 内置了简易的 HTTP Server 来处理请求。 当然这仅仅供本地测试的运行方式,线上部署的方案,通常是采用 wsgi 程序来驱动 Flask / Django 应用。Gunicorn 是性能比较好的一个方案(有时间我会做一次 Gunicorn 与 uWsgi 的性能压测对比)。Gunicorn 的驱动 hello 应用的命令如下: gunicorn -w 4 -b 127.0.0.1:5000 hello:app Gunicorn 的常用运行参数说明:...

JDK 8 中 HashMap 的工作原理

Java 容器类中,HashMap 是一个绕不开的重点,无论是实际开发还是求职面试。由于对 JDK 6 下 HashMap 的讨论已经很多了,而且 JDK 8 对 HashMap 做了比较大的改进,本文仅对 JDK 8 中 HashMap 的实现和工作原理做一点粗浅的讨论。 文中 Java 代码均基于 OpenJDK 8 引入 为了便于切入话题,先写一段最简单的 HashMap 样例代码: public class HashMapTest { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put("China", "Beijing"); map.put("Japan", "Tokyo"); map.put("Korea", "Seoul"); for (String country : map.keySet()) { // set a break point String capital = map.get(country); System.out.println(country + "--" + capital); } } } 在 for 循环处进入断点,查看变量,IntelliJ IDEA 中显示如下: 变量 map 包含 table 属性和 entrySet 属性。其中,table 属性是一个长度为 16 的 Map....

Spring AOP 本地模拟线上 RPC

成熟的互联网公司内部一般都会有多个线上环境,像在 JD,就有测试环境,预发布环境,生产环境。开发过程通常是现在本地编写代码,功能差不多了提到测试环境,再到预发布联调,测试通过再提交上线包部署到生产环境。但这是理想状况,实际开发中会有上下游系统联调的问题。 JD 的项目绝大多数都已经服务化了,服务的提供者和消费者分别在服务中心注册,消费者就能调用服务者的接口。但由于 JD 内部系统繁多,各有不同的开发团队维护各自的项目,除了生产环境和预发布环境能保证各系统间能互联互通,很多情况下,本地运行或在测试环境上运行时,没法调用到服务提供者的接口,这就很尴尬了,因为测试资源的不到位,只能上预发布环境进行上下游系统的对接联调,这是很烦人的,比较好的开发方案是,如果测试环境不完善,就把预发布环境上服务接口的真实数据截流并重定向到本地文件,把它打包成一个本地的测试数据源,以后直接在本地运行就行了。 如何拦截数据?这就需要 AOP 大显身手了。Spring AOP 可以通过 BeanNameAutoProxyCreatoraaaa 自动代理目标 bean,属性 beanNames 和 interceptorNames 分别设置要代理的目标 bean 列表和拦截器数组。这样就很方便的实现了对目标 bean 的切入拦截。 简单说下具体的实现流程: 当线上运行时,通过拦截器对目标 bean 内部方法的拦截,将方法调用的结果持久化到结果文件中; 当本地运行时,拦截器就不走远程调用,而是直接从结果文件中读取真实的调用结果。 下面给出大致的拦截服务调用数据的代码: <!--spring-aop-config.xml --> <beans> <!--method interceptor --> <bean id="rpcInterceptor" class="com.isudox.utils.RpcInterceptor"> <property name="mode" value="online"/> <property name="fileName" value="/home/sudoz/dev/local-rpc-data.properties"/> </bean> <!--auto proxy --> <bean id="rpcAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>remoteService1</value> <value>remoteService2</value> <value>remoteService3</value> <value>remoteService4</value> </list> </property> <property name="interceptorNames"> <list> <value>rpcInterceptor</value> </list> </property> </bean> </beans> import org....

Docker 部署 GitLab

前几天给自己的域名添加了子域名 git,用来访问自己搭建的 GitLab。顺便实践了一把 Docker 的应用部署。 GitLab 的外部依赖很多,有 Nginx、Rails、Postgres、Redis、MySQL、unicorn、Go 等。如果单独安装各个依赖,一大堆的配置会让人抓狂。如果用官网提供的 omni 集成包,除非是全新的服务器,否则很大可能就导致依赖的重复安装,比如进程里有多个 Nginx、MySQL,很容易把服务器环境弄得很乱。像 GitLab 这样的程序,其实很适合用 Docker 来部署,一则和实机环境隔离开,另外运行性能相当好。 安装 Docker 环境 安装配置 惯例,以 Debian 8 为参考,把 Docker 官方维护的 deb 包添加到系统的 APT 源内,创建文件 /etc/apt/sources.list.d/docker.list: deb https://apt.dockerproject.org/repo debian-jessie main 更新源,安装 docker-engine 包,执行 ps -ef | grep docker 查看 Docker 的进程, root 2885 1 0 09:40 ? 00:00:10 /usr/bin/dockerd --raw-logs root 2897 2885 0 09:40 ? 00:00:00 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc sudoz 21053 6463 0 14:54 pts/0 00:00:00 grep --color=auto --exclude-dir=....

为子域名安装 SSL 证书

今天把小站所在 Linode 服务器升级到了 4G 2CPU 的配置,可以搞搞大新闻了,打算用 Docker 部署下 GitLab 作为和前辈小伙伴们写作开发的代码库,把 GitLab 绑定到小站的子域名下。另外还得再加上 SSL 证书。 Docker 部署 GitLab 的事后面再写,先记下给子域名安装证书的事。 解析子域名 从域名提供商买到域名后,可以用在多个不同的网站上。比如经常可以看到类似这样的域名,bss.example.com,blog.example.com,其实这俩是彼此独立的网站,但是都访问到 sample.com 域名下,这就是在同一域名下部署多个网站的范例。 域名和 IP 通过 DNS 关联在一起,所以无论常见多少个子域名,都是要通过 DNS 解析到关联 IP 的服务器上。如果要新增子域名,需要在提供 DNS 解析服务的提供商处建立一条解析,将子域名关联到根域名的 IP 上。 本人小站的域名是从 Godaddy 上购买,但域名解析服务是并没有用 Godaddy 默认提供的服务,而是用了 Linode 提供的免费解析服务。但操作都是相同的,在 DNS 的 zone file 中添加一条 A/AAAA 记录: git A 45.33.47.109 git AAAA 2600:3c01::f03c:91ff:fe18:68b6 添加完后等待 DNS 服务更新,大概 15 分钟后就能 ping 通这条新建的子域名。这就意味着对子域名的访问已经通过 DNS 解析指向了我的 Linode 服务器上。 现在要完成的就是通过 HTTP Server 将访问请求打到网站的目录下,我是用 Nginx,在 Nginx conf 里添加子域名解析的针对性配置或者泛子域名解析的通用配置。较新版本的 Nginx 的多站点配置默认保存在 /etc/nginx/conf....

JetBrains IDE Vim 模式的方案

之前的一篇博客翻译了 IntelliJ IDEA 的默认快捷键操作。快捷操作的功能覆盖面已经很全了,但如果想进阶键盘流,可能还需要一点文本编辑上的快操,比如 Vim 模式。用户有需求,良心厂商 JetBrains 就自己开发了一款强大插件 Ideavim,模拟 Vim 编辑器的操作。 在安装 ideavim 插件后,IDE 可能会处在几种不同的模式下: Vim 模拟器关闭模式(Vim Emulator off) Vim 模拟器开启模式(Vim Emulator on) Vim 命令模式(Command mode) Vim 插入模式(Insert mode) Vim 末行命令模式(Last line mode) 当关闭 Vim 模拟器时,IDE 的 Keymap 会恢复到安装 Ideavim 之前的状态,因此最好是在自己自定义设置并熟悉 IDE 自带的 keymap 后安装 Ideavim 插件。开启/关闭 Vim 模拟器的快捷键可以北自定义,默认的切换快捷键是 Ctrl + Alt + V,这个切换方式和 IDE 自带的快捷键冲突,可以考虑改成更合适的映射。我把切换 Vim 开关状态的快捷键修改成了 Ctrl + ;,这样,如果 Caps 键映射成 Ctrl 键,左手右手一个慢动作,可以很方便的开启/关闭 Vim 模拟器。 Vim 模拟器关闭状态下就不多讲了,之前都翻译过。在 Vim 模拟器开启后,IDE 就拥有了 Vim 编辑器的强大功能(不是全部,但也很强大了)。Vim 的三个模式基本都耳熟能详了,命令模式下的键盘动作会被识别为命令,而不是字符输入,比如 a 进入 append 输入,i 进入 insert 输入,x 删除光标所在的字符,X 删除光标之前的字符,dd 删除光标所在行,yy 复制当前行,p 粘贴等。插入模式就是正常的文本输入编辑,Esc 键退出插入模式,或者 Ctrl + [。末行命令模式是从命令模式下按 : 键进入,可以执行保存、退出、set:options 等操作。...

开始使用 PostgreSQL

最近开始做的一个课余项目用 Flask + PostgreSQL + Bootstrap 快速开发。之前本地开发和生产部署都用 MySQL,而 PostgreSQL 是关系型数据库阵营中的另一大高手。这俩的口号放在一起看相当好玩。 一个自称 “The world's most popular open source database”,另一个自称 “The world's most advanced open source database”。论针锋相对,我就服这俩。→_→ 至于 MySQL 和 PostgreSQL 之间的比较,可以参考 Digital Ocean 社区里的一篇文章,写的很详细,顺便还拉上了 SQLite。 SQLite vs MySQL vs PostgreSQL: A Comparison Of Relational Database Management Systems 菜鸟入门三板斧,安装、配置和使用—— 安装 服务器端我习惯用 Debian 系统。Debian/Ubuntu 内置的 APT 源已经包含了 PostgreSQL,但版本上会稍滞后于 PostgreSQL 最新版本。如果像我一样激进的,可以把 PostgreSQL 官方维护的 APT 源加进 Debian/Ubuntu 的 APT 列表中。比如在 Debian 系统下,新建文件 /etc/apt/sources.list.d/pgdg.list,添加源地址和版本,再导入该源的签名。 deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main wget --quiet -O - https://www....

Hexo 主题美化

小站有段时间没折{no}腾{zuo}前{no}端{die}了,在浏览别的个人站时总会时不时被里面的设计吸引到,最近闲着没事干,就把别人的主题抄袭过来,嘿嘿。 头像旋转 Pacman 主题布局非常大气,最有心的设计在我看来就是底栏的可旋转的圆形头像,非常可爱。相比之下,鄙人小站侧边栏头像就显得很呆板了。那就抄过来! 可以知道,这是一个鼠标的 hover 事件,因此先找到位于 source/css/_common/components/sidebar/sidebar-author.syl 模板文件里侧边栏头像的样式 .site-author-image .site-author-image { display: block; margin: 0 auto; padding: $site-author-image-padding; max-width: $site-author-image-width; height: $site-author-image-height; border: $site-author-image-border-width solid $site-author-image-border-color; } 首先要做的事就是把原头像图通过 css 样式改成圆形头像。通过修改 border-radius 属性就可以改图片四个角的圆角程度。另外针对不同内核的浏览器也能分别指定。再加上属性变化的动画效果 transition。 .site-author-image { border-radius: 50%; -webkit-border-radius: 50%; -moz-border-radius: 50%; transition: 1.4s all; } 圆角效果完成后,再做 hover 动作。添加 .site-author-image:hover 样式,由 rotate() 方法实现,旋转 360° .site-author-image:hover { -webkit-transform: rotate(360deg); -moz-transform: rotate(360deg); -ms-transform: rotate(360deg); -transform: rotate(360deg); } OK,成就达成。 侧边滚动条 Yilia 也是 GitHub 上非常受欢迎的一款 Hexo 主题, 虽然我用的不是 Yilia 主题,但是不妨碍我喜欢它的侧边滚动条,灰色系的性冷淡风很契合我的小站。所以我就把这个样式挪到了我的小站里。 为了不影响小站原主题的样式,最好不要直接在原有样式上做修改。在 source/css/_custom 里的 custom....

LeetCode 21-25

本篇记录 LeetCode 算法部分第 21 至 25 题。 Merge Two Sorted Lists 第 21 题 Merge Two Sorted Lists 将两个有序链表合并成一个新的有序链表。 题目不复杂,取两个指针分别往下遍历两个链表的每个节点,逐次指向节点的值,取其较小值,并移动该指针,另一指针不动。继续往下比较,知道其中有一个指针到达末端为止。 循环解法: // MergeTwoSortedLists.java v1.0 // Definition for singly-linked list. // public class ListNode { // int val; // ListNode next; // ListNode(int x) { val = x; } // } public class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode res = new ListNode(0); ListNode temp = res; while (l1 !...

Spring MVC 集成 Thymeleaf

在狗厂,我所接触的项目里,Spring 的视图解析器采用最广泛的就是 Velocity。最近也一直在想前后端分离的事,略显古老的 Velocity 并不是前后端分离的好选择。还好,近几年 Java Web 诞生了一款新的视图解析器——“百里香叶” Thymeleaf,就像它的名字一样美妙。 和 Velocity 类似,Thymeleaf 支持通过 @Controller 注解的映射方法返回模板名称;模板支持 Spring Expression Language;支持在模板中创建表单,表单验证。(这就比较像 Jinja2 了)。 模板标准方言 引入 Thymeleaf 的模板标准语言中绝大多数 processors 都是 attribute processors,这就意味着浏览器可以正常地表现 XHTML/HTML5 模板文件,即使是在模板引擎没有加载的情况下,因为浏览器会忽略额外的 attribute。这就是 Thymeleaf 比前辈 JSP 厉害的地方之一。来看下面的 input 标签,JSP 里会加入浏览器无法直接识别的代码: <form:inputText name="userName" value="${user.name}" /> 而 Thymeleaf 模板标准语言会这样写: <input type="text" name="userName" value="James Carrot" th:value="${user.name}" /> 浏览器能直接识别上述 Thymeleaf 的 input 标签,而且还能在加载模板引擎后,由后端返回的数据渲染 value 值。也就是这一特性,可以让前后端工程师在同一个模板文件上协作开发,避免了从静态页面到模板页面的转换,前后端并行开发,这就是未来的趋势,也被称作 Natural Templating,页面即模板,模板即页面。 标准表达式语法 基本表达式 Thymeleaf 模板方言里最重要的就是它的标准表达式语法了。Thymeleaf 的表达式有: 简单表达式: 变量表达式:${....