项目背景: 使用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;
}
}
}
复制代码
所有评论(0)