希望长大对我而言,是可以做更多想做的事,而不是被迫做更多不想做的事...... 首页 双层nginx之应用层 丁D 学无止境 2019-06-06 09:07 2785已阅读 nginx 应用层 nginx本地缓存 摘要上一篇我们讲解了双层nginx提高nginx本地缓存的命中率,和分发层的开发,本文我们将接着讲nginx第二层应用层。 上一篇我们已经将同一个请求(参数一致)分发到相同的应用层了, 应用层接收到请求,应该中本地缓存中查到数据,如果有数据就直接 根据html模板渲染成html页面返回。 假设nginx本地缓存不存在(第一次请求/LRU清理)就应该中redis中获取 然后返回用户,如果redis也没有就中ehcache中获取,如果ehcache中也没有就去数据库中获取(这时候可能出现缓存重建并发冲突)。。 **实现思路** ```js 1、应用nginx的lua脚本接收到请求 2、获取请求参数中的商品id,以及商品店铺id 3、根据商品id和商品店铺id,在nginx本地缓存中尝试获取数据 4、如果在nginx本地缓存中没有获取到数据,那么就到redis分布式缓存中获取数据,如果获取到了数据,还要设置到nginx本地缓存中 但是这里有个问题,建议不要用nginx+lua直接去获取redis数据 因为openresty没有太好的redis cluster的支持包,所以建议是发送http请求到缓存数据生产服务,由该服务提供一个http接口 缓存数生产服务可以基于redis cluster api从redis中直接获取数据,并返回给nginx 5、如果缓存数据生产服务没有在redis分布式缓存中没有获取到数据,那么就在自己本地ehcache中获取数据,返回数据给nginx,也要设置到nginx本地缓存中 6、如果ehcache本地缓存都没有数据,那么就需要去原始的服务中拉去数据,该服务会从mysql中查询,拉去到数据之后,返回给nginx,并重新设置到ehcache和redis中 这里先不考虑,后面要专门讲解一套分布式缓存重建并发冲突的问题和解决方案 7、nginx最终利用获取到的数据,动态渲染网页模板 ``` 商品详情模板 ```js vi product.html product id: {* productId *} product name: {* productName *} product picture list: {* productPictureList *} product specification: {* productSpecification *} product service: {* productService *} product color: {* productColor *} product size: {* productSize *} shop id: {* shopId *} shop name: {* shopName *} shop level: {* shopLevel *} shop good cooment rate: {* shopGoodCommentRate *} ``` 要配置 lua_shared_dict my_cache 128m; ```js lua脚本中: local uri_args = ngx.req.get_uri_args() local productId = uri_args["productId"] local shopId = uri_args["shopId"] local cache_ngx = ngx.shared.my_cache local productCacheKey = "product_info_"..productId local shopCacheKey = "shop_info_"..shopId local productCache = cache_ngx:get(productCacheKey) local shopCache = cache_ngx:get(shopCacheKey) if productCache == "" or productCache == nil then local http = require("resty.http") local httpc = http.new() local resp, err = httpc:request_uri("http://192.168.31.179:8080",{ method = "GET", path = "/getProductInfo?productId="..productId }) productCache = resp.body cache_ngx:set(productCacheKey, productCache, 10 * 60) end if shopCache == "" or shopCache == nil then local http = require("resty.http") local httpc = http.new() local resp, err = httpc:request_uri("http://192.168.31.179:8080",{ method = "GET", path = "/getShopInfo?shopId="..shopId }) shopCache = resp.body cache_ngx:set(shopCacheKey, shopCache, 10 * 60) end local cjson = require("cjson") local productCacheJSON = cjson.decode(productCache) local shopCacheJSON = cjson.decode(shopCache) local context = { productId = productCacheJSON.id, productName = productCacheJSON.name, productPrice = productCacheJSON.price, productPictureList = productCacheJSON.pictureList, productSpecification = productCacheJSON.specification, productService = productCacheJSON.service, productColor = productCacheJSON.color, productSize = productCacheJSON.size, shopId = shopCacheJSON.id, shopName = shopCacheJSON.name, shopLevel = shopCacheJSON.level, shopGoodCommentRate = shopCacheJSON.goodCommentRate } local template = require("resty.template") template.render("product.html", context) ``` **分布式缓存并发重建** 假设目前nginx本地没有对应的缓存,redis也咩有,ehcache也没有。只能去数据拉取,并设置到redis中。 那这个时候有两个请求过来,并且cache服务负载均衡有多台(2台) 一个请求被分到第一台。一个请求在第二台 这个时候两个请求都要去数据库查询,,第一次请求查询查询到的是12:00:00时间的数据 并且准备设置到redis中但是还没设置 第二个请求查询到的是12:00:01时间的数据数据,并优先设置到redis中,,这个时间第1个请求设置到redis中将第二个请求设置的新数据覆盖了 。。。 **处理方案 ** 在nginx应用层分发请求到cache服务的时候。。 将同一个请求分到同一cache服务上,,这个时候可以利用java的锁sync同步。。来控制只能一个线程执行,并判断时间,,, **消费消息队列中的消息** 很赞哦! (0) 上一篇:双层nginx提高本地缓存的命中率 下一篇:使用静态内部类来创建单例 目录 点击排行 Elasticsearch6.3.2之x-pack redis哨兵 2019-07-09 22:05 Redis+Twemproxy+HAProxy+Keepalived 2019-07-12 17:20 GC优化策略和相关实践案例 2019-10-10 10:54 JVM垃圾回收器 2019-10-10 10:23 标签云 Java Spring MVC Mybatis Ansible Elasticsearch Redis Hive Docker Kubernetes RocketMQ Jenkins Nginx 友情链接 郑晓博客 佛布朗斯基 凉风有信 MarkHoo's Blog 冰洛博客 南实博客 Rui | 丁D Java研发工程师 生活可以用「没办法」三个字概括。但别人的没办法是「腿长,没办法」、「长得好看,没办法」、「有才华,没办法」。而你的没办法,是真的没办法。 请作者喝咖啡