模擬京東使用Openresty+Redis做讀服務
使用Vagrant + Ansible來搭建(不要問我為什么不使用Docker)。這樣,所有的人只要兩條命令就可以搭建好了,而不需要手工一條命令一條命令打。
所謂使用Openresty來做讀服務,是指Openresty直接從數據源讀數據,然后渲染輸出,而不經過應用服務器,比如Tomcat服務器。 Openresty 是一個基于Nginx和LuaJIT的動態Web開發平臺。我不知道京東是否是直接使用Openresty還是自己編譯Nginx + Lua。反正,我直接使用Openresty。
本次文章就是根據開濤的教程,實現使用 lua-resty-template 做模塊引擎,使用Redis做數據源。我把Openresty和Redis都安裝在同一臺機器上,以方便做實驗,當然,如果你想裝在不同的服務器,只需要修改下配置就好了。以下是架構:
搭建的步驟:
-
安裝Openresty及其相關的Openresty module: lua-resty-template、lua-resty-redis
-
安裝Redis,啟動Redis
-
配置Openresty,啟動Openresty
-
寫頁面邏輯代碼
整個步驟我都寫成了Ansible自動化配置腳本。所以,你已經不需要自己搭建。
啟動方法
啟動前,你必須安裝Vagrant 和 Ansible 2.0+。
git clone https://git.oschina.net/zacker330/openresty-lab.git
cd openresty-lab
vagrant up
ansible-playbook ./ansible/playbook.yml -i ./ansible/inventory -u vagrant -k
>> 輸入ssh密碼 `vagrant`
PS. ansible-playbook需要通過ssh登錄上目標機器來執行我們的任務。
接下來,我們解釋下代碼。
Openresty的配置如下:
## 省去了一些不重要的nginx配置
http {
default_type application/octet-stream;
## 省去了一些不重要的nginx配置
## 初始化所需要對象
init_by_lua '
require "resty.core"
redis = require "resty.redis"
template = require "resty.template"
template.caching(false); -- you may remove this on production
';
server{
listen 80;
server_name 192.168.8.10;
charset utf-8;
## 指定 模塊路徑
set $template_root "/usr/local/openresty/nginx/html/templates";
location ~ \.lsp$ {
default_type text/html;
content_by_lua 'template.render(ngx.var.uri)'; ## 訪問index.lsp,將使用index.lsp模板
}
}
}
頁面邏輯代碼 index.lsp:
{%
layout = "layouts/default.lsp" -- 模板
local blogid= ngx.var.arg_blogId
local title = "博客標題"
local author = {name = "fooname", gender = "female", level= 3}
local description = "<script>alert(1);</script>"
local content = "java8的流式處理極大了簡化我們對于集合、數組等結構的操作,讓我們可以以函數式的思想去操作,<br/>本篇文章將探討java8的流式數據處理的基本使用。"
local tags = {"life", "lua", "openresty"}
local radar = {lua = 90, openresty = 80, nginx = 70}
-- 使用nginx的內置變量
local a = ngx.var.arg_a
local b = ngx.var.arg_b
local ip = ngx.var.remote_addr
-- 使用redis讀數據源
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local ok, err = red:lpush("list", a, b)
local member, err = red:llen("list")
%}
<div>
member: {{ member }}<br/>
remote ip: {{ ip }}
blogId: {{blogid}}<br/>
作者: {{author.name}} {{author.gender}} level: {{author.level}}<br/>
description: {{description}} <br/>
tags: {% for i = 1, #tags do %}
{% if i > 1 then %},{% end %}
{* tags[i] *}
{% end %}<br/>
</div>
最終訪問效果:http://192.168.8.10/index.lsp?a=12&b=asdfasdf&blogId=111
小結
-
這種不經過應用服務器的方式,讀的速度似乎更快,畢竟省去了中間的Tomcat服務。但是,誰來填充數據給Redis和什么時機填充數據,又是另一回事了。
-
開發過程似乎有些麻煩,因為修改nginx配置后,不能像普通的頁面開發那樣立馬看到效果,還要nginx -s reload一下。這個,我想到的解決方案是使用Ruby的guard gem來監控文件變動,然后reload nginx配置,最后使用瀏覽器的livereload來自刷新頁面。https://github.com/guard/guard-livereload 目前還沒有時間實現,希望有熱心朋友實現提pr。或者開濤能分享下他們的實踐。希望他本人能看到這篇博客。:P
參考:
來自:https://my.oschina.net/zjzhai/blog/759719