项目背景: 使用springboot做微服务,后端一共10个工程左右,在同一台服务器部署(16g,8核),工程之间的调用十分频繁,没有使用rpc框架,使用http调用。shiro使用redis作session管理。
产生问题: 服务器cpu非常高。
问题排查: 使用top查看哪个服务占用cpu高。 用 ps -mp TID THREAD,pid,time查看那个线程占用服务器高, printf "%x\n" pid 将线程专程16进制, jstack TID|grep pid -A 60 看耗时线程卡在哪里(多跑几遍这里命令,看最多是卡在哪里),结果发现大多数线程卡在jedis.getConnection();

问题原因: 有一个定时任务从电商平台同步订单。每同步一个订单,工程之间调用发生30次左右。每次调用,shiro从redis去4,5次数据。每天同步200万订单。redis maxConnection 开50个,导致大量线程卡在获取redis connection上面。 问题解决:接口在内部调用的时候不经过shiroFilter。首先定义不经过shiro的uri和访问ip(本文代码为本地调用),符合条件的话不走shiro,否则走shiro

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException;

import com.google.common.base.Splitter;

public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean{
	private static final Logger logger = LoggerFactory.getLogger(MyShiroFilterFactoryBean.class);
	private List<String> noShiroIps = new ArrayList<String>();
	private List<String> noShiroUrls = new ArrayList<String>();
	
   public MyShiroFilterFactoryBean(String hosts) {
       super();
       if(StringUtils.isNotEmpty(hosts)) {
    	   noShiroIps = Splitter.on(",").splitToList(hosts);
       }
       noShiroUrls = NoShiroPostProcessor.getInstance();
   }

   @Override
   protected AbstractShiroFilter createInstance() throws Exception {
       SecurityManager securityManager = getSecurityManager();
       if (securityManager == null) {
           String msg = "SecurityManager property must be set.";
           throw new BeanInitializationException(msg);
       }

       if (!(securityManager instanceof WebSecurityManager)) {
           String msg = "The security manager does not implement the WebSecurityManager interface.";
           throw new BeanInitializationException(msg);
       }

       FilterChainManager manager = createFilterChainManager();

       PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
       chainResolver.setFilterChainManager(manager);

       return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
   }

   private final class MySpringShiroFilter extends AbstractShiroFilter {
       protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
           super();
           if (webSecurityManager == null) {
               throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
           }
           setSecurityManager(webSecurityManager);
           if (resolver != null) {
               setFilterChainResolver(resolver);
           }
       }

       @Override
       protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
               FilterChain chain) throws ServletException, IOException {
           HttpServletRequest request = (HttpServletRequest)servletRequest;
           String uri = request.getRequestURI().toLowerCase();
           boolean flag = true;
           if(noShiroIps.contains(getIpAddr(request)) && noShiroUrls.contains(uri)){
        	   flag = false;
           }
           if(flag){
        	   logger.info("shirouri=" + uri);
               super.doFilterInternal(servletRequest, servletResponse, chain);
           }else{
        	   logger.info("shironouri=" + uri);
               chain.doFilter(servletRequest, servletResponse);
           }
       }
       
       private String getIpAddr(HttpServletRequest request) {  
	   	    String ip = request.getHeader("x-forwarded-for");//先从nginx自定义配置获取  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("X-real-ip");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("Proxy-Client-IP");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("WL-Proxy-Client-IP");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getRemoteAddr();  
	   	    }  
	   	    return ip;  
	   	}

   }
}
复制代码
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐