用 Java 扩展 Nginx(nginx-clojure 入门实战)
本篇概览
今天咱们以 Java 程序员的视角,来聊聊如何用 Java 来扩展 Nginx 的能力,全文由以下内容组成:
什么是 Nginx
什么是 Nginx 扩展
扩展 Nginx,意义何在?
想用 Java 扩展 Nginx 会有问题吗?
主角登场:nginx-clojure 模块,让 Java 扩展 Nginx 成为显示
总的来说这是一篇从概念到实践的入门文章,接下来,一起开始愉快的 nginx-clojure 之旅吧!
关于 Nginx
以欣宸自己为例,nginx 对 java 程序员来说并不陌生,下图应该是最常见的使用场景了:反向代理
关于 Nginx 扩展
除了反向代理,nginx 的模块化机制让 nginx 具备了更多丰富的特性,例如 ngx_http_log_module(日志)、ngx_http_rewrite_module(重定向)等
除了官方模块,还有很多强大第三方模块可以选择,如下图,更多详情参考:https://www.nginx.com/resources/wiki/modules/
大名鼎鼎的 OpenResty 就是基于 Nginx 扩展的,用 Lua 做二次开发 web 功能,得到了广泛的应用
如此看来,在 nginx 上做二次开发并非神秘高深莫测,我们也可以按照自己的需要去定制和扩展 nginx 的功能
作为一名 Java 程序员,自然就想到了:可以用 Java 去扩展 Nginx 的能力吗?
为什么要用 java 对 nginx 扩展?
把 java 代码写在 nginx 上,让 nginx 与业务耦合的可能性变大,经验丰富的您一定会发现这是个危险的趋势,毕竟 nginx 已经接近后台服务的最外层了,稳定是首要考虑的,正常情况下,下图这种用法才是生产环境的常见 fang 方案:将 nginx 作为反向代理,业务功能独立部署
这么看来,在 nginx 上写 java 代码是否合适呢?欣宸给不出权威答案,但是可以从大神的作品中得到启示
开涛大神的《跟我学Nginx+Lua开发》讲述了如何用 OpenResty 在 Nginx 上用 Lua 进行开发,适用于 web 应用、接入网关、Web 防火墙、缓存服务器等场景下,并且在实体书《亿级流量网站架构核心技术》也有详细说明,例如京东商品详情页,就是在 nginx 上读取缓存直接返回的
综上所述,欣宸不会因为学习了这个技术,就把业务逻辑全部在 nginx 上实现,但是在缓存、鉴权等场景,可以考虑用熟悉的 java 在 nginx 上实现
Java 程序员的尴尬
定制 Nginx,打造高性能 Web 服务,带着这个美好憧憬,我打开了有关模块开发的 Nginx 官方资料
然后,画风开始剧变,而且是朝着我不想面对的方向,如下图
模块开发用的居然是 C 语言!然而,欣宸只是个精通 CRUD 的 Java 程序员啊
这可怎么办?随手打开一个网页就让梦想破灭?
nginx-clojure,让 Java 扩展 nginx 成为现实
经过一番搜索,终于找到了 nginx-clojure 模块,如下图,是它让 java 扩展 nginx 成为现实
nginx-clojure 的作用很好理解:OpenResty 支持用 Lua 扩展 nginx,nginx-clojure 支持用 Java 扩展 nginx
关于 nginx-clojure
nginx-clojure 是个第三方 Nginx 模块,官方的介绍是 Nginx module for embedding Clojure / Java / Groovy programs, typically those Ring based handlers
nginx-clojure 模块支持嵌入式 Clojure(闭包)、Java、Groovy 等基于 Ring 的处理器(handler),那什么是 Ring 呢?
Ring 在 Clojure 中是一个构建 Web 应用的底层接口和库. 它和 Ruby 的 Rack, Python 里面的 WSGI 或者 Java Servlet 规范相似
从 java 开发者角度来看,就是开发 NginxJavaRingHandler 的实现类,然后该类可以在 nginx-clojure 模块中被运行
nginx-clojure 的最新版本是 v0.5.2,官网地址是:https://nginx-clojure.github.io
实战功能介绍
尽管 nginx-clojure 支持很多功能,但是篇幅所限,因此本篇以了解为主,还是经典的 Hello world,更多精彩内容留给后续的系列文章
今天的实战效果如下图,咱们编写 HelloHandler.java 并在 nginx 做好配置,然后用浏览器发起请求后,HelloHandler 的代码就会被执行,浏览器会收到 HelloHandler 返回的内容,这就证实了 java 代码可以在 nginx 上运行:
为了实现上述功能,接下来的操作步骤如下图:
感谢您听我唠叨了这么久,接下来,实战开始
环境信息
这里给出我的实战环境信息供您参考,这个环境可以正常运行所有实战:
操作系统:macOS Big Sur 11.5.2 (20G95)
JDK:1.8.0_281
Maven:3.8.1
下载集成了 nginx-clojure 模块的 nginx 包
咱们要做的第一件事是下载一个特别的 nginx,之所以说它特别,是因为它已集成了 nginx-clojure 模块,开箱即用
下载地址:https://sourceforge.net/projects/nginx-clojure/files/ ,如下图红框,我这里选择的是最新的 0.5.2 版本:
解压 nginx 包
下载完毕后,解压,得到名为 nginx-clojure-0.5.2 的文件夹,里面的内容如下
接下来根据您的操作系统对可执行文件做重命名,我这边是 macOS,所以把 nginx-macosx 重命名为 nginx,如果是 linux,把 nginx-linux-64 重命名为 nginx,如果是 windows,就把 nginx-win64.exe 重命名为 nginx.exe
上述重命名操作是 nginx-clojure 官方推荐的,统一可执行文件名,这样运行文档中的命令就统一了
执行命令./nginx -v,控制台响应如下,可见 nginx 版本是 1.18.0:
编码,开发 java 版 handler
接下来开始写代码,先新建一个 maven 工程(我这里名叫 simple-hello),pom.xml 中需要配置 repository 节点,以及唯一的依赖 nginx-clojure,如下所示:
然后新增文件 HelloHandler.java,如下所示,代码非常简单,实现 NginxJavaRingHandler 接口,invoke 方法返回的数组中只有三个元素:返回码、响应 header 的键值对集合、响应 body 内容:
至此,编码完成,欣宸精通 Hello World 果然并非空穴来风…
编译,生成 jar
在 pom.xml 所在目录执行编译构建的命令 mvn clean package -U,会在 target 目录下生成 jar 包,只有 3K 大小:
jar 放入 nginx 的 jars 目录
将前面生成的 simple-hello-1.0-SNAPSHOT.jar 文件放入下图红框的 jars 文件夹内
修改 nginx 的配置
打开 nginx-clojure-0.5.2/conf/nginx.conf 文件,在 server 配置中增加一个 location 配置,内容如下,指定了 handler 类型,以及对应的 java 类:
修改后,完整的 nginx.conf 内容如下,可见有很多 java 相关的配置,在本篇咱们都保持不动,留待后面的文章解锁:
启动 nginx
启动命令很简单,在 nginx-clojure-0.5.2 目录下执行./nginx
如果启动失败了,请打开 nginx-clojure-0.5.2/logs/error.log 查看问题,例如我这里遇到过端口占用导致启动失败:
验证
打开 postman 验证服务是否正常,请求地址是 http://127.0.0.1:8080/java
响应如下图所示,符合预期,返回的就是咱们定制的 HelloHandler 的内容
至此,nginx-clojure 的入门操作就完成了,虽然寥寥几行代码,但却给 java 程序员打开了一扇窗:用咱们熟悉的技术去扩展 nginx,打造更符合业务的 web 服务器,以最短链路完成 web 响应
本篇只是 nginx-clojure 之旅的开端,先对 nginx-clojure 有个清晰的认识,接下来的文章咱们会深度探索它,让它更好的服务于业务
源码下载
本篇的完整源码可在 GitHub 下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
这个 git 项目中有多个文件夹,本篇的源码在 nginx-clojure-tutorials 文件夹下,如下图红框所示:
欢迎关注 InfoQ:程序员欣宸
版权声明: 本文为 InfoQ 作者【程序员欣宸】的原创文章。
原文链接:【http://xie.infoq.cn/article/1323ee189e5a475ae140b3f7a】。文章转载请联系作者。
评论