龙空技术网

亿级流量场景下,大型缓存架构设计实现,你入坑了吗?

秃头敲代码 250

前言:

眼前我们对“httptenginxorg”大概比较注意,看官们都想要分析一些“httptenginxorg”的相关知识。那么小编同时在网络上汇集了一些关于“httptenginxorg””的相关文章,希望姐妹们能喜欢,大家快快来学习一下吧!

1、 分发层+应用层 的双层nginx架构,提升缓存命中率

缓存架构图:

架构图介绍:

1、缓存命中率低

缓存数据生产服务那一层已经搞定了,相当于三层缓存架构中的本地堆缓存+redis分布式缓存都搞定了

就要来做三级缓存中的nginx那一层的缓存了

如果一般来说,你默认会部署多个nginx,在里面都会放一些缓存,就默认情况下,此时缓存命中率是比较低的

2、如何提升缓存命中率

分发层+应用层,双层nginx

分发层nginx,负责流量分发的逻辑和策略,这个里面它可以根据你自己定义的一些规则,比如根据productId去进行hash,然后对后端的nginx数量取模

将某一个商品的访问的请求,就固定路由到一个nginx后端服务器上去,保证说只会从redis中获取一次缓存数据,后面全都是走nginx本地缓存了

后端的nginx服务器,就称之为应用服务器; 最前端的nginx服务器,被称之为分发服务器

看似很简单,其实很有用,在实际的生产环境中,可以大幅度提升你的nginx本地缓存这一层的命中率,大幅度减少redis后端的压力,提升性能

openresty的设计【源码示例】:

local uri_args = ngx.req.get_uri_args()local productId = uri_args["productId"]local hosts = {"192.168.31.187", "192.168.31.19"}local hash = ngx.crc32_long(productId)local index = (hash % 2) + 1backend = ";..hosts[index]local requestPath = uri_args["requestPath"]requestPath = "/"..requestPath.."?productId="..productIdlocal http = require("resty.http")local httpc = http.new()local resp, err = httpc:request_uri(backend,{  method = "GET",  path = requestPath})if not resp then  ngx.say("request error: ", err)  returnendngx.say(resp.body)httpc:close()
2、热点问题:超级热数据导致系统崩溃的场景:3、热点问题:超级热数据导致系统崩溃的场景 ——解决方案:

openresty中热数据处理切换处理:

storm中的逻辑处理:

    private class HotProductFindThread implements Runnable {        public void run() {            List<Map.Entry<Long, Long>> productCountList = new ArrayList<Map.Entry<Long, Long>>();            List<Long> hotProductIdList = new ArrayList<Long>();                        while(true) {                // 1、将LRUMap中的数据按照访问次数,进行全局的排序                // 2、计算95%的商品的访问次数的平均值                // 3、遍历排序后的商品访问次数,从最大的开始                // 4、如果某个商品比如它的访问量是平均值的10倍,就认为是缓存的热点                try {                    productCountList.clear();                    hotProductIdList.clear();                                        if(productCountMap.size() == 0) {                        Utils.sleep(100);                        continue;                    }                                        LOGGER.info("【HotProductFindThread打印productCountMap的长度】size=" + productCountMap.size());                                        // 1、先做全局的排序                                        for(Map.Entry<Long, Long> productCountEntry : productCountMap.entrySet()) {                        if(productCountList.size() == 0) {                            productCountList.add(productCountEntry);                        } else {                            boolean bigger = false;                                                        for(int i = 0; i < productCountList.size(); i++){                                Map.Entry<Long, Long> topnProductCountEntry = productCountList.get(i);                                                                if(productCountEntry.getValue() > topnProductCountEntry.getValue()) {                                    int lastIndex = productCountList.size() < productCountMap.size() ? productCountList.size() - 1 : productCountMap.size() - 2;                                    for(int j = lastIndex; j >= i; j--) {                                        if(j + 1 == productCountList.size()) {                                            productCountList.add(null);                                        }                                        productCountList.set(j + 1, productCountList.get(j));                                      }                                    productCountList.set(i, productCountEntry);                                    bigger = true;                                    break;                                }                            }                                                        if(!bigger) {                                if(productCountList.size() < productCountMap.size()) {                                    productCountList.add(productCountEntry);                                }                            }                        }                    }                                        // 2、计算出95%的商品的访问次数的平均值                    int calculateCount = (int)Math.floor(productCountList.size() * 0.95);                                        Long totalCount = 0L;                    for(int i = productCountList.size() - 1; i >= productCountList.size() - calculateCount; i--) {                        totalCount += productCountList.get(i).getValue();                    }                                        Long avgCount = totalCount / calculateCount;                                        // 3、从第一个元素开始遍历,判断是否是平均值得10倍                    for(Map.Entry<Long, Long> productCountEntry : productCountList) {                        if(productCountEntry.getValue() > 10 * avgCount) {                            hotProductIdList.add(productCountEntry.getKey());                                                        // 将缓存热点反向推送到流量分发的nginx中                            String distributeNginxURL = "; + productCountEntry.getKey();                            HttpClientUtils.sendGetRequest(distributeNginxURL);                                                        // 将缓存热点,那个商品对应的完整的缓存数据,发送请求到缓存服务去获取,反向推送到所有的后端应用nginx服务器上去                            String cacheServiceURL = "; + productCountEntry.getKey();                            String response = HttpClientUtils.sendGetRequest(cacheServiceURL);                                                    String[] appNginxURLs = new String[]{                                    "; + productCountEntry.getKey() + "&productInfo=" + response,                                    "; + productCountEntry.getKey() + "&productInfo=" + response                            };                                                        for(String appNginxURL : appNginxURLs) {                                HttpClientUtils.sendGetRequest(appNginxURL);                            }                        }                    }                                        Utils.sleep(5000);                 } catch (Exception e) {                    e.printStackTrace();                }            }        }            }

使用的http工具类

package com.roncoo.eshop.storm.http; import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Map.Entry; import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.HttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils; /** * HttpClient工具类 * @author lixuerui * */@SuppressWarnings("deprecation")public class HttpClientUtils {         /**     * 发送GET请求     * @param url 请求URL     * @return 响应结果     */    @SuppressWarnings("resource")    public static String sendGetRequest(String url) {        String httpResponse = null;                 HttpClient httpclient = null;        InputStream is = null;        BufferedReader br = null;                 try {            // 发送GET请求            httpclient = new DefaultHttpClient();            HttpGet httpget = new HttpGet(url);             HttpResponse response = httpclient.execute(httpget);                         // 处理响应            HttpEntity entity = response.getEntity();            if (entity != null) {                is = entity.getContent();                br = new BufferedReader(new InputStreamReader(is));                                      StringBuffer buffer = new StringBuffer("");                      String line = null;                                   while ((line = br.readLine()) != null) {                         buffer.append(line + "\n");                     }                          httpResponse = buffer.toString();                 }        } catch (Exception e) {             e.printStackTrace();         } finally {            try {                if(br != null) {                    br.close();                }                if(is != null) {                    is.close();                }            } catch (Exception e2) {                e2.printStackTrace();             }        }                   return httpResponse;    }         /**     * 发送post请求     * @param url URL     * @param map 参数Map     * @return     */    @SuppressWarnings({ "rawtypes", "unchecked", "resource" })    public static String sendPostRequest(String url, Map<String,String> map){         HttpClient httpClient = null;         HttpPost httpPost = null;         String result = null;                  try{             httpClient = new DefaultHttpClient();             httpPost = new HttpPost(url);                          //设置参数             List<NameValuePair> list = new ArrayList<NameValuePair>();             Iterator iterator = map.entrySet().iterator();             while(iterator.hasNext()){                 Entry<String,String> elem = (Entry<String, String>) iterator.next();                 list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));             }             if(list.size() > 0){                 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "utf-8");                   httpPost.setEntity(entity);             }                          HttpResponse response = httpClient.execute(httpPost);             if(response != null){                 HttpEntity resEntity = response.getEntity();                 if(resEntity != null){                     result = EntityUtils.toString(resEntity, "utf-8");                   }             }         } catch(Exception ex){             ex.printStackTrace();         } finally {                     }                 return result;     }      }

标签: #httptenginxorg