shiro之redis频繁访问问题

目前安全框架shiro使用较为广泛,其功能也比较强大。为了分布式session共享,通常的做法是将session存储在redis中,实现多个节点获取同一个session。此实现可以实现session共享,但session的特点是内存存储,就是为了高速频繁访问,每个请求都必须验证session是否存在是否过期,也从session中获取数据。这样导致一个页面刷新过程中的数十个请求会同时访问redis,在几毫秒内同时操作session的获取,修改,更新,保存,删除等操作,从而造成redis的并发量飙升,刷新一个页面操作redis几十到几百次。

为了解决由于session共享造成的redis高并发问题,很明显需要在redis之前做一次短暂的session缓存,如果该缓存存在就不用从redis中获取,从而减少同时访问redis的次数。如果做session缓存,主要有两种种方案,其实原理都相同:

  1>重写sessionManager的retrieveSession方法。首先从request中获取session,如果request中不存在再走原来的从redis中获取。这样可以让一个请求的多次访问redis问题得到解决,因为request的生命周期为浏览器发送一个请求到接收服务器的一次响应完成,因此,在一次请求中,request中的session是一直存在的,并且不用担心session超时过期等的问题。这样就可以达到有多少次请求就几乎有多少次访问redis,大大减少单次请求,频繁访问redis的问题。大大减少redis的并发数量。此实现方法最为简单。

 1 package cn.uce.web.login.filter;
 2
 3 import java.io.Serializable;
 4
 5 import javax.servlet.ServletRequest;
 6
 7 import org.apache.shiro.session.Session;
 8 import org.apache.shiro.session.UnknownSessionException;
 9 import org.apache.shiro.session.mgt.SessionKey;
10 import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
11 import org.apache.shiro.web.session.mgt.WebSessionKey;
12
13 public class ShiroSessionManager extends DefaultWebSessionManager {
14      /**
15      * 获取session
16      * 优化单次请求需要多次访问redis的问题
17      * @param sessionKey
18      * @return
19      * @throws UnknownSessionException
20      */
21     @Override
22     protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
23         Serializable sessionId = getSessionId(sessionKey);
24
25         ServletRequest request = null;
26         if (sessionKey instanceof WebSessionKey) {
27             request = ((WebSessionKey) sessionKey).getServletRequest();
28         }
29
30         if (request != null && null != sessionId) {
31             Object sessionObj = request.getAttribute(sessionId.toString());
32             if (sessionObj != null) {
33                 return (Session) sessionObj;
34             }
35         }
36
37         Session session = super.retrieveSession(sessionKey);
38         if (request != null && null != sessionId) {
39             request.setAttribute(sessionId.toString(), session);
40         }
41         return session;
42     }
43 }
 <!-- session管理器 -->
    <bean id="sessionManager" class="cn.uce.web.login.filter.ShiroSessionManager">
      <!-- 超时时间 -->
      <property name="globalSessionTimeout" value="${session.global.timeout}" />
      <!-- session存储的实现 -->
      <property name="sessionDAO" ref="redisSessionDAO" />
      <!-- <property name="deleteInvalidSessions" value="true"/> -->
      <!-- 定时检查失效的session -->
      <!-- <property name="sessionValidationSchedulerEnabled" value="true" /> -->
      <!-- <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
      <property name="sessionIdCookieEnabled" value="true"/> -->
      <property name="sessionIdCookie" ref="sessionIdCookie" />
    </bean>

  2>session缓存于本地内存中。自定义cacheRedisSessionDao,该sessionDao中一方面注入cacheManager用于session缓存,另一方面注入redisManager用于session存储,当createSession和updateSession直接使用redisManager操作redis.保存session.当readSession先用cacheManager从cache中读取,如果不存在再用redisManager从redis中读取。注意:该方法最大的特点是session缓存的存活时间必须小于redis中session的存活时间,就是当redus的session死亡,cahe中的session一定死亡,为了保证这一特点,cache中的session的存活时间应该设置为s级,设置为1s比较合适,并且存活时间固定不能刷新,不能随着访问而延长存活。

/**
 *
 */
package com.uc56.web.omg.authentication;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.crazycake.shiro.SerializeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uc56.web.omg.shiroredis.CustomRedisManager;

/**
 * 将从redis读取的session进行本地缓存,本地缓存失效时重新从redis读取并更新最后访问时间,解决shiro频繁读取redis问题
 */
public class CachingShiroSessionDao extends CachingSessionDAO {

    private static final Logger logger = LoggerFactory.getLogger(CachingShiroSessionDao.class);

    /** 保存到Redis中key的前缀 */
    private String keyPrefix = "";

    /**
     * jedis  操作redis的封装
     */
    private CustomRedisManager redisManager;

    /**
     * 如DefaultSessionManager在创建完session后会调用该方法;
     * 如保存到关系数据库/文件系统/NoSQL数据库;即可以实现会话的持久化;
     * 返回会话ID;主要此处返回的ID.equals(session.getId());
     */
    @Override
    protected Serializable doCreate(Session session) {
        // 创建一个Id并设置给Session
        Serializable sessionId = this.generateSessionId(session);
        assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    /**
     * 重写CachingSessionDAO中readSession方法,如果Session中没有登陆信息就调用doReadSession方法从Redis中重读
     */
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
        Session session = getCachedSession(sessionId);
        if (session == null
                || session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) {
            session = this.doReadSession(sessionId);
            if (session == null) {
                throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
            } else {
                // 缓存
                cache(session, session.getId());
            }
        }
        return session;
    }

    /**
     * 根据会话ID获取会话
     *
     * @param sessionId 会话ID
     * @return
     */
    @Override
    protected Session doReadSession(Serializable sessionId) {
        ShiroSession shiroSession = null;
        try {
            shiroSession = (ShiroSession)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
            if (shiroSession != null
                    && shiroSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) != null) {
                //检查session是否过期
                shiroSession.validate();
                // 重置Redis中Session的最后访问时间
                shiroSession.setLastAccessTime(new Date());
                this.saveSession(shiroSession);
                logger.info("sessionId {} name {} 被读取并更新访问时间", sessionId, shiroSession.getClass().getName());
            }
        } catch (Exception e) {
            if (!(e instanceof ExpiredSessionException)) {
                logger.warn("读取Session失败", e);
            }else {
                logger.warn("session已失效:{}", e.getMessage());
            }
        }

        return shiroSession;
    }

    //扩展更新缓存机制,每次请求不重新更新session,更新session会延长session的失效时间
    @Override
    public void update(Session session) throws UnknownSessionException {
        doUpdate(session);
        if (session instanceof ValidatingSession) {
            if (((ValidatingSession) session).isValid()) {
                //不更新ehcach中的session,使它在设定的时间内过期
                //cache(session, session.getId());
            } else {
                uncache(session);
            }
        } else {
            cache(session, session.getId());
        }
    }

    /**
     * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
     */
    @Override
    protected void doUpdate(Session session) {
        //如果会话过期/停止 没必要再更新了
        try {
            if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
                return;
            }
        } catch (Exception e) {
            logger.error("ValidatingSession error");
        }

        try {
            if (session instanceof ShiroSession) {
                // 如果没有主要字段(除lastAccessTime以外其他字段)发生改变
                ShiroSession shiroSession = (ShiroSession) session;
                if (!shiroSession.isChanged()) {
                    return;
                }
                shiroSession.setChanged(false);
                this.saveSession(session);
                logger.info("sessionId {} name {} 被更新", session.getId(), session.getClass().getName());

            } else if (session instanceof Serializable) {
                this.saveSession(session);
                logger.info("sessionId {} name {} 作为非ShiroSession对象被更新, ", session.getId(), session.getClass().getName());
            } else {
                logger.warn("sessionId {} name {} 不能被序列化 更新失败", session.getId(), session.getClass().getName());
            }
        } catch (Exception e) {
            logger.warn("更新Session失败", e);
        }
    }

    /**
     * 删除会话;当会话过期/会话停止(如用户退出时)会调用
     */
    @Override
    protected void doDelete(Session session) {
        try {
            redisManager.del(this.getByteKey(session.getId()));
            logger.debug("Session {} 被删除", session.getId());
        } catch (Exception e) {
            logger.warn("修改Session失败", e);
        }
    }

    /**
     * 删除cache中缓存的Session
     */
    public void uncache(Serializable sessionId) {
        Session session = this.readSession(sessionId);
        super.uncache(session);
        logger.info("取消session {} 的缓存", sessionId);
    }

    /**
     *
     *  统计当前活动的session
     */
    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();

        Set<byte[]> keys = redisManager.keys(this.keyPrefix + "*");
        if(keys != null && keys.size()>0){
            for(byte[] key:keys){
                Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
                sessions.add(s);
            }
        }

        return sessions;
    }

    /**
     * save session
     * @param session
     * @throws UnknownSessionException
     */
    private void saveSession(Session session) throws UnknownSessionException{
        if(session == null || session.getId() == null){
            logger.error("session or session id is null");
            return;
        }

        byte[] key = getByteKey(session.getId());
        byte[] value = SerializeUtils.serialize(session);
        session.setTimeout(redisManager.getExpire() * 1L);
        this.redisManager.set(key, value, redisManager.getExpire());
    }

    /**
     * 将key转换为byte[]
     * @param key
     * @return
     */
    private byte[] getByteKey(Serializable sessionId){
        String preKey = this.keyPrefix + sessionId;
        return preKey.getBytes();
    }

    public CustomRedisManager getRedisManager() {
        return redisManager;
    }

    public void setRedisManager(CustomRedisManager redisManager) {
        this.redisManager = redisManager;

        /**
         * 初使化RedisManager
         */
        this.redisManager.init();
    }

    /**
     * 获取 保存到Redis中key的前缀
     * @return keyPrefix
     */
    public String getKeyPrefix() {
        return keyPrefix;
    }

    /**
     * 设置 保存到Redis中key的前缀
     * @param keyPrefix 保存到Redis中key的前缀
     */
    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }

}
/**
 *
 */
package com.uc56.web.omg.authentication;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;

import org.apache.shiro.session.mgt.SimpleSession;

/**
 * 由于SimpleSession lastAccessTime更改后也会调用SessionDao update方法,
 * 增加标识位,如果只是更新lastAccessTime SessionDao update方法直接返回
 */
public class ShiroSession extends SimpleSession implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    // 除lastAccessTime以外其他字段发生改变时为true
    private boolean isChanged;

    public ShiroSession() {
        super();
        this.setChanged(true);
    }

    public ShiroSession(String host) {
        super(host);
        this.setChanged(true);
    }

    @Override
    public void setId(Serializable id) {
        super.setId(id);
        this.setChanged(true);
    }

    @Override
    public void setStopTimestamp(Date stopTimestamp) {
        super.setStopTimestamp(stopTimestamp);
        this.setChanged(true);
    }

    @Override
    public void setExpired(boolean expired) {
        super.setExpired(expired);
        this.setChanged(true);
    }

    @Override
    public void setTimeout(long timeout) {
        super.setTimeout(timeout);
        this.setChanged(true);
    }

    @Override
    public void setHost(String host) {
        super.setHost(host);
        this.setChanged(true);
    }

    @Override
    public void setAttributes(Map<Object, Object> attributes) {
        super.setAttributes(attributes);
        this.setChanged(true);
    }

    @Override
    public void setAttribute(Object key, Object value) {
        super.setAttribute(key, value);
        this.setChanged(true);
    }

    @Override
    public Object removeAttribute(Object key) {
        this.setChanged(true);
        return super.removeAttribute(key);
    }

    //更新最后访问时间不更新redis
    @Override
    public void touch() {
        this.setChanged(false);
        super.touch();
    }

    /**
     * 停止
     */
    @Override
    public void stop() {
        super.stop();
        this.setChanged(true);
    }

    /**
     * 设置过期
     */
    @Override
    protected void expire() {
        this.stop();
        this.setExpired(true);
    }

    public boolean isChanged() {
        return isChanged;
    }

    public void setChanged(boolean isChanged) {
        this.isChanged = isChanged;
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    protected boolean onEquals(SimpleSession ss) {
        return super.onEquals(ss);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public String toString() {
        return super.toString();
    }
}
/**
 *
 */
package com.uc56.web.omg.authentication;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.SessionFactory;

public class ShiroSessionFactory implements SessionFactory {

    @Override
    public Session createSession(SessionContext initData) {
        ShiroSession session = new ShiroSession();
        return session;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">  

    <!-- 自定义权限定义 -->
    <bean id="permissionsRealm" class="com.uc56.web.omg.realm.PermissionsRealm">
        <!-- 缓存管理器 -->
        <property name="cacheManager" ref="shiroRedisCacheManager" />
    </bean>
    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!-- 缓存管理器 -->
        <property name="cacheManager" ref="shiroEhcacheManager" />
        <!-- session 管理器 -->
          <property name="sessionManager" ref="sessionManager" />
          <property name="realm" ref="permissionsRealm"/>
    </bean>
    <!-- redis 缓存管理器 -->
    <bean id="shiroRedisCacheManager" class="com.uc56.web.omg.shiroredis.CustomRedisCacheManager">
        <property name="redisManager" ref="shiroRedisManager" />
    </bean>
    <bean id="shiroRedisManager" class="com.uc56.web.omg.shiroredis.CustomRedisManager">
        <property name="host" value="${redis.host}" />
        <property name="port" value="${redis.port}" />
        <property name="password" value="${redis.password}" />
        <property name="expire" value="${session.maxInactiveInterval}" />
        <property name="timeout" value="${redis.timeout}" />
    </bean>
    <!-- 提供单独的redis Dao -->
    <!-- <bean id="redisSessionDAO" class="com.uc56.web.omg.shiroredis.CustomRedisSessionDAO">
      <property name="redisManager" ref="shiroRedisManager" />
      <property name="keyPrefix" value="${session.redis.namespace}"></property>
    </bean> -->
    <bean id="sessionDao" class="com.uc56.web.omg.authentication.CachingShiroSessionDao">
        <property name="keyPrefix" value="${session.redis.namespace}"/>
        <property name="redisManager" ref="shiroRedisManager" />
    </bean>
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login/loginAuthc.do"></property>
        <property name="successUrl" value="login/loginIndex.do"></property>
        <property name="unauthorizedUrl" value="login/forbidden.do" />
        <property name="filters">
            <map>
               <entry key="authc" value-ref="formAuthenticationFilter"/>
               <entry key="LoginFailureCheck" value-ref="LoginFailureCheckFilter"/>
            </map>
        </property>
        <property name="filterChainDefinitions">
            <value>
               /login/login.do=anon
               /login/loginAuthc.do=anon
               /login/authCheck.do=anon
               /login/forbidden.do=anon
               /login/validateUser.do=anon
               /city/**=anon
               /easyui-themes/**=anon
               /images/**=anon
               /jquery-easyui-1.5.1/**=anon
               /scripts/**=anon
               /users/**=anon
               /**=LoginFailureCheck,authc,user
            </value>
        </property>
    </bean>
    <!-- 用户授权信息Cache, 采用EhCache,本地缓存最长时间应比中央缓存时间短一些,以确保Session中doReadSession方法调用时更新中央缓存过期时间 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:springShiro/spring-shiro-ehcache.xml"/>
    </bean>

    <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/>
    <bean id="LoginFailureCheckFilter" class="com.uc56.web.omg.filter.LoginFailureCheckFilter">
        <property name="casService" ref="casService"></property>
        <property name="loginUserService" ref="loginUserService"></property>
    </bean>
    <bean id="loginUserService" class="com.uc56.web.omg.control.LoginUserService"/>
    <bean id="passwordEncoder" class="com.uc56.core.security.MD5PasswordEncoder"/>

     <!-- session管理器 -->
   <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
      <!-- 超时时间 -->
      <property name="globalSessionTimeout" value="${session.global.timeout}" />
      <property name="sessionFactory" ref="sessionFactory"/>
      <!-- session存储的实现 -->
      <property name="sessionDAO" ref="sessionDao" />
      <!-- 定时检查失效的session -->
      <property name="sessionValidationSchedulerEnabled" value="true" />
      <!-- <property name="sessionValidationInterval" value="180000"/> -->
      <property name="sessionIdCookie" ref="sharesession" />
      <property name="sessionListeners">
            <list>
                <bean class="com.uc56.web.omg.authentication.listener.ShiroSessionListener"/>
            </list>
      </property>
   </bean>

   <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
    <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
        <!-- cookie的name,对应的默认是JSESSIONID -->
        <constructor-arg name="name" value="redisManager.sessionname" />
        <!-- jsessionId的path为/用于多个系统共享jsessionId -->
        <property name="path" value="/" />
         <property name="httpOnly" value="false"/>
    </bean>    

    <!-- 自定义Session工厂方法 返回会标识是否修改主要字段的自定义Session-->
    <bean id="sessionFactory" class="com.uc56.web.omg.authentication.ShiroSessionFactory"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false"  name="shirocache">
    <!-- <diskStore path="java.io.tmpdir"/>
    登录记录缓存 锁定10分钟
    <cache name="passwordRetryCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="authenticationCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro-activeSessionCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="3600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
    <cache name="shiro_cache"
           maxElementsInMemory="2000"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           maxElementsOnDisk="0"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="FIFO"
           statistics="true">
    </cache> -->
    <!-- <defaultCache
        在内存中最大的对象数量
        maxElementsInMemory="10000"
        设置元素是否永久的
        eternal="false"
        设置元素过期前的空闲时间
        timeToIdleSeconds="60"
        缓存数据的生存时间(TTL)
        timeToLiveSeconds="60"
        是否当memory中的数量达到限制后,保存到Disk
        overflowToDisk="false"
        diskPersistent="false"
        磁盘失效线程运行时间间隔,默认是120秒
        diskExpiryThreadIntervalSeconds="10"
        缓存满了之后的淘汰算法: LRU(最近最少使用)、FIFO(先进先出)、LFU(较少使用)
        memoryStoreEvictionPolicy="LRU"
     /> -->
     <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToLiveSeconds="60"
        overflowToDisk="false"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="10"
     />
</ehcache>

此设计中最重要的一点就是:

  1.cache中的session只存储不更新,也就是说每次访问不会刷新缓存中的session,cache中的session一定会在设定的时间中过期
  2.cache中设置的session的时间一定要短于redis中存储的session,保证redis中session过期是,cache中的session一定过期

  3.redis中的session更新会清楚cache中的session保证session一直性

  

  

原文地址:https://www.cnblogs.com/xj-blog/p/8289429.html

时间: 2024-10-09 03:10:07

shiro之redis频繁访问问题的相关文章

SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统

1.前言本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管理系统实例. 使用技术:SpringBoot.mybatis.shiro.thymeleaf.pagehelper.Mapper插件.druid.dataTables.ztree.jQuery 开发工具:intellij idea 数据库:mysql.redis 2.表结构还是是用标准的5张表来展现权限.如下图:image 分别为用户表,角色表,资源表,用户角色表,角色资源表.在这个demo中使用了mybat

SpringMVC集成shiro和redis

记录用maven集成shiro和redis. 先是代码结构: 然后是web.xml 1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://xmlns.jcp.org/xml/ns/javaee" 4 xsi:schemaL

PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码

<?php /* *通过禁止IP频繁访问防止网站被防攻击代码*design by www.scutephp.com*/header('Content-type: text/html; charset=utf-8');$ip=$_SERVER['REMOTE_ADDR'];//获取当前访问者的ip$logFilePath='./log/';//日志记录文件保存目录$fileht='.htaccess2';//被禁止的ip记录文件$allowtime=60;//防刷新时间$allownum=5;//

PHP代码,拒绝频繁访问

一个网站性能有限,如果有人恶意去频繁对页面进行刷新,其实对服务器影响是很大的,导致资源使用非常高,直接影响到其他用户的体验. 那么对于这样的一些频繁访问,我们该如何去拒绝它呢? 我总结了两种方法:第一种方式通过Web服务器检查拒绝,第二种方式通过代码进行拦截过滤. 通过Web服务器检查拒绝 第一种方式大致原理和思路是这样的,比如我们的Web服务器采用Nginx,那个Nginx可以记录用户访问记录,并通过查询分析这个日志可以得出频繁访问用户IP列表. 我们需要做的事情: 做一个定时任务,定时去分析

C基础 redis缓存访问

引言 先说redis安装, 这里采用的环境是. Linux version 4.4.0-22-generic ([email protected]41) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2) ) #40-Ubuntu SMP Thu May 12 22:03:46 UTC 2016 对于 ubuntu 安装 redis是非常简单的. 这里采用源码安装. 安装代码如下 wget http://download.redis.io/r

Shiro使用Redis作存储之后更新Session失败的问题

问题 因为想在多个应用之间共享用户的登录态,因此实现了自己的SessionDAO,使用Kryo把SimpleSession序列化然后放到redis之中去,同时也使用了shiro.userNativeSessionManager: true来使用shiro自己的存储.然而之后一直出现丢失更新的问题,例如 Session session = SecurityUtils.getSubject().getSession(); User user = (User) session.getAttribute

分布式 dubbo zookeeper springmvc mybatis shiro restful redis fastdfs activemq

摘要: 摘要: SSH ++shiro+restful+bootstrap java架构 java企业架构 spring mvc +mybatis + KafKa+Flume+Zookeeper j2ee分布式架构 dubbo + springmvc + mybatis + ehcache + redis 分布式架构 分布式消息中间件:spring mvc +mybatis + KafKa+Flume+Zookeeper 分布式缓存:Redis spring mvc +mybatis + 分布式

一个 redis 异常访问引发 oom 的案例分析

本文来自本人独立博客,为获得更佳阅读体验,请点击 这里 ---------------------------------------------------------------------------------------------------- 「推断的前提是以事实为依据.」 这两天碰到一个线上系统的偶尔出现突然堆内存暴涨,这倒不是个什么疑难杂症, 只是过程中有些思路觉得可以借鉴参考,故总结下并写下来. 现象 内存情况可以看看下面这张监控图. 一天偶尔出现几次,持续时间一般几分钟不等

Redis 外部访问设置

1.错误原因 Redis搭建好后一般都是使用编程语言进行连接调用,默认Redis的设置是不允许外界访问的,连接Redis只能通过本地(127.0.0.1)来连接,而不能使用网络IP(192.168.1.x)来连接,如果需要请修改配置文件redis.conf 2.解决方案 进入Redis目录打开Redis.conf配置文件 1>注释掉bind #bind 127.0.0.1 2>默认不是守护进程方式运行,这里可以修改 daemonize no 3>禁用保护模式 protected-mode