新年快乐~~~

上一篇文章讲到使用多级缓存来减少数据库的访问来加快网页的速度,只是,仍旧没有“嗖”一下就加载出来的感觉,想再优化一下,优化代码什么的已经到了极限。上周无意中看到了openresty,能够直接在nginx层直接对请求处理,而不需要每次都访问tomcat,特别是对于自己的首页http://www.wenzhihuai.com来说,由于首页内容广泛,需要涉及的方法太多,每次打开首页都得耗费大量的时间。

一、整体架构

目前本人总共有三个服务器:

A:119.23.46.71(深圳,Nginx环境,本地Redis,tomcat服务器)

B:119.29.188.224(广州,tomcat服务器)

C:47.95.10.139(北京,tomact服务器)

为了减少后端的相应时间,之前使用的是在应用里集成ehcache作为一级缓存,redis作为二级缓存。这种架构存在一种特殊的情况:当Nginx将首页的请求分发给北京节点的时候,响应将变得极其缓慢,用户的请求需要从深圳到北京,再从北京回到深圳,光是延时就要耗费40ms(最好的情况),由于网速是1M/s,最坏的情况下,响应用户的请求也得耗费几秒。所以,为了减少这种极端情况,设计了这款架构(个人项目随便整整而已,怎么来都行啦)。

由于是博客类的项目,对于一致性要求并不高,所以干脆直接将首页缓存到Redis即可。

![](http://image.wenzhihuai.com/images/20180214105827.png)

步骤:
1.请求到达nginx后,openresty通过lua读取本地缓存,如果不命中,则回源到tomcat集群。
2.tomcat集群首先从自己的服务器中读取一级缓存Ehcache,如果没有命中,则继续回源到二级缓存。
3.读取二级缓存Redis,如果依旧没有命中,则回源到MySQL服务器。

二、配置过程

2.1 Openresty

安装过程可以直接参考官方文档:http://openresty.org/cn/download.html,安装前还需安装以下开发库:

yum install pcre-devel openssl-devel gcc curl

然后进行编译安装:

tar -xzvf openresty-VERSION.tar.gz
cd openresty-VERSION/
./configure
make
sudo make install

2.2 Nginx相关配置

Openresty自带了Nginx。所以,只要安装好了Openresty,即可直接使用nginx来配置。

以下只是部分,需要全部的请查看mynginxconfig

http {
include mime.types;
default_type application/octet-stream;
# 需要添加lua的相关库
lua_package_path "/opt/openresty/lualib/?.lua;;";
lua_package_cpath "/opt/openresty/lualib/?.so;;";
... access_log logs/access.log main;
sendfile on;
keepalive_timeout 65; upstream backend {
#consistent_hash was not configured
hash $uri;
server 47.95.10.139:8080;
server 119.23.46.71:8080;
server 119.29.188.224:8080;
}
server {
listen 80;
server_name www.wenzhihuai.com;
# 精确匹配,打开首页的时候进入
location = / {
default_type text/html;
root html;
index index.html index.htm;
...
# 关闭缓存lua脚本,调试的时候专用
lua_code_cache off;
content_by_lua_file /opt/lua/hello.lua;
# 此处不要proxy_pass了,否则lua脚本没用
# proxy_pass http://backend; }
# 如果上面的不符合,则匹配下面的
location / {
default_type text/html;
root html;
index index.html index.htm;
# 对请求进行反向代理
proxy_pass http://backend;
}
}
...
}

2.3 lua脚本

脚本记得放在/opt/lua/hello.lua目录下,对应nginx的配置,同时需要引入redis模块。

local redis = require "resty.redis"
local red = redis:new() local request_uri = ngx.var.request_uri if (request_uri == "/" or request_uri == "/index.html") then
red:set_timeout(1000) -- 1 sec
red:connect("119.23.46.71", 6340)
local ok, err = red:auth("root")
if not ok then
ngx.say("failed to connect: ", err)
return
end
--缓存的首页放在key为index里
local resp, errr = red:get("index")
if not resp then
return
end
if resp == ngx.null then
resp = "<h1>hello world</h1>"
end
--如果找到,则输出内容
ngx.print(resp)
red:close()
return
end
local pagenum = ngx.req.get_uri_args()["pagenum"]
--因为在nginx中设置了proxy_pass_request_headers off,即不讲请求头部传到lua,所以头部需要重新设置
ngx.req.set_header("Accept", "text/html,application/xhtml+xml,application/xml;")
--这里回源到tomcat的时候,Accept-Encoding默认为gzip,即返回来数据已经是gzip压缩过了的,返回到用户的时候又被压缩了一次,会造成一堆乱码。所以将Accept-Encoding设置为空。
ngx.req.set_header("Accept-Encoding", "")
local respp = ngx.location.capture("/index.do", { method = ngx.HTTP_GET, args = { pagenum = pagenum } })
--打印
ngx.print(respp.body)
return

2.4 更新首页到redis

每隔20秒直接访问后端进行首页的抓取,然后存储到redis里面,简单粗暴。

@Controller
@SuppressWarnings("unchecked")
public class TimeController {
//logger
private static final Logger logger = LoggerFactory.getLogger(TimeController.class);
@Scheduled(cron = "0/20 * * * * ?")
public void refreshIndex() throws Exception {
String ip = IPUtils.getServerIp().replaceAll("\n", "");
if (REGULARIP.equals(ip)) {
String content = HttpHelper.getInstance().get("http://119.29.188.224:8080");
JedisUtil.getInstance().set("index", content);
}
}
}

碰到的问题

capture报错

2018/02/10 18:53:51 [error] 2833#0: *3942 lua subrequests cycle while processing "/index.html", client: 113.108.186.130, server: www.wenzhihuai.com, request: "GET /index.html?pagenum=23 HTTP/1.1", subrequest: "/index.html", host: "www.wenzhihuai.com"
2018/02/10 18:53:51 [error] 2833#0: *3942 lua entry thread aborted: runtime error: /opt/lua/hello.lua:25: failed to issue subrequest: -1
stack traceback:
coroutine 0:
[C]: in function 'capture'
/opt/lua/hello.lua:25: in function </opt/lua/hello.lua:1>, client: 113.108.186.130, server: www.wenzhihuai.com, request: "GET /index.html?pagenum=23 HTTP/1.1", subrequest: "/index.html", host: "www.wenzhihuai.com"

打开网页乱码,用curl正常显示

查了好久,才发现Openresty如果使用nginx.location.capture是重新请求一次的,如果带有请求头并且开启了gzip压缩,那么数据就相当于被再次压缩。

![](http://image.wenzhihuai.com/images/20180210073318.png)

解决办法:去掉请求头部

ngx.req.set_header("Accept-Encoding", "");

使用Openresty加快网页速度的更多相关文章

  1. Web 性能优化:21 种优化 CSS 和加快网站速度的方法

    这是 Web 性能优化的第 4 篇,上一篇在下面看点击查看: Web 性能优化:使用 Webpack 分离数据的正确方法 Web 性能优化:图片优化让网站大小减少 62% Web 性能优化:缓存 Re ...

  2. 简单几步优化你的windows,加快开机速度(重装windows之后要做的几件事)

    每个人都想要让自己的系统运行得快一些,开机快一些,我就来说说我自己的经验,我使用的系统是windows8.1,当然这有些方法也适用于其他的系统,我每次重装完系统之后第一件事就是下面几步,当然重装系统之 ...

  3. 慢腾腾的Quartus prime16.0加快编译速度

    前言 当一个工程反复修改的时候,可能有时候源代码没有更改,为了加快编译速度可以配置quartus一些选项.当然,初次编译的速度是否会提升,未验证.更高级的设计分区以及逻辑锁区提升速度,以后阐述. 流程 ...

  4. 在VisualGDB中配置预编译头加快编译速度

    今天是中秋佳节,但是写完已经是第二天凌晨了,还是祝大家中秋快乐! VS对C++的支持相较GCC太弱了,连续几个VS版本对C++的改进都很小.很少.对Cpper也许是一种痛,我们也许希望能使用VS的强大 ...

  5. Android开发之制作圆形头像自定义View,直接引用工具类,加快开发速度。带有源代码学习

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...

  6. Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子。加快开发速度

    Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子.加快开发速度 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 在使用 A ...

  7. 简单修改hosts文件加快打开网页速度

    这个电脑小技巧的帖子菲菲博客分享如何通过简单一招利用修改系统的hosts文件来实现有效加快浏览器打开网页的速度.尤其是网络繁忙时DNS服务器负担加重的时候效果特别明显,有兴趣就和菲菲一起来学习一下吧, ...

  8. IntelliJ下使用Code/Live Template加快编码速度:程序员的工作不是写程序,而是写程序解决问题

    程序员的工作不是写程序,而是写程序解决问题. --- 某不知名程序员 我们每天都在写代码,有些代码有结构性的相似,但不是所有的代码都可以被抽成方法.在这种情况下,我们应该考虑使用template的方式 ...

  9. 优化SQLServer数据库加快查询速度

    查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 ...

随机推荐

  1. 【Zigbee技术入门教程-号外】基于Z-Stack协议栈的抢答系统

    [Zigbee技术入门教程-号外]基于Z-Stack协议栈的抢答系统 广东职业技术学院  欧浩源 一.引言    2017年全国职业院校技能大赛"物联网技术应用"赛项中任务三题2的 ...

  2. 使用 Gacutil.exe 将.Net程序集添加到GAC的方法

    使用gacutil.exe工具安装:gacutil -i "要注册的dll文件全路径" "gacutil.exe”工具为.NET自带工具 ,需要注意的是:这个工具在.NE ...

  3. seaJS 模块加载过程分析

    先看一个seajs的官方example,  以下以seajs.use('main')为例, 解析加载mod main的过程 //app.html seajs.use("main") ...

  4. gettype

    取得变量的类型. 语法: string gettype(mixed var); 返回值: 字符串 函数种类: PHP 系统功能 内容说明 本函数用来取得变量的类型.返回的类型字符串可能为下列字符串其中 ...

  5. “此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”的问题的解决

    虚拟机使用的是VMware Workstation,并且首次在虚拟机体验64 位系统.在新建好虚拟机,运行时候就出现了VMware Workstation 的提醒:此主机支持 Intel VT-x,但 ...

  6. 04 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之高并发优化

    Github:https://github.com/nnngu 项目源代码:https://github.com/nnngu/nguSeckill 关于并发 并发性上不去是因为当多个线程同时访问一行数 ...

  7. 疑难杂症——关于EntityFramework的SqlQuery方法的执行效率差异的探讨

    前言:最近项目上面遇到一个问题,在Code First模式里面使用EntityFramework的SqlQuery()方法查询非常慢,一条数据查询出来需要10秒以上的时间,可是将sql语句放在plsq ...

  8. (2-3)Eureka详解

    基础架构 服务注册中心 服务提供者 服务消费者 服务治理 服务提供者 服务注册.在服务注册时,需要确认一下eureka.client.registerwith-eurek=ture参数是否正确,默认是 ...

  9. Servlet--ServletInputStream类,ServletOutputStream类

    ServletInputStream类 定义 public abstract class ServletInputStream extends InputStream 这个类定义了一个用来读取客户端的 ...

  10. Linux常用命令(二)--文件目录命令

    1. 列表目录命令: 格式: ls [参数] 用于显示文件或目录信息 选项: -l 每行显示一个文件和目录信息(长格式),简写:ll等同于ls -l 注意:当参数是文件时,显示此文件全部信息 当参数是 ...