当前位置:首页 » 硬盘大全 » shiro开启redis缓存
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

shiro开启redis缓存

发布时间: 2022-09-27 21:10:16

❶ java里shiro的用法

好在配置简单,以前做一个权限模块要写好多代码。现在spring security好像是集成了shiro的功能,实现了代码量更少,高速开发的目的。

❷ 怎么实现redis的数据库缓存

大致为两种措施:

一、脚本同步:
1、自己写脚本将数据库数据写入到redis/memcached。
2、这就涉及到实时数据变更的问题(mysql row binlog的实时分析),binlog增量订阅Alibaba 的canal ,以及缓存层数据 丢失/失效 后的数据同步恢复问题。

二、业务层实现:
1、先读取nosql缓存层,没有数据再读取mysql层,并写入数据到nosql。
2、nosql层做好多节点分布式(一致性hash),以及节点失效后替代方案(多层hash寻找相邻替代节点),和数据震荡恢复了。

❸ org.apache.shiro.util.bytesource 什么类型

java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource是由于 SimpleByteSource 没有实现序列化接口导致。在集成redis缓存, 开启缓存认证时候报错我的解决方案 写一个新类去继承SimpleByteSource,并实现序列化接口 public class MySimpleByteSource extends SimpleByteSource implements Serializable {public MySimpleByteSource(byte[] bytes) {super(bytes);// TODO Auto-generated constructor stub}} 在处理认证中 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { return new SimpleAuthenticationInfo(model, user.getPassword(), new MySimpleByteSource(salt), getName()); }org.apache.shiro.util.bytesource 什么类型

❹ org.apache.shiro.util.bytesource 什么类型

java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource

是由于 SimpleByteSource 没有实现序列化接口导致。
在集成redis缓存, 开启缓存认证时候报错
<!-- 启用认证缓存,当用户登录一次后将不在查询数据库来获取用户信息,直接在从缓存获取 -->
<property name="authenticationCachingEnabled" value="true" />

我的解决方案 写一个新类去继承SimpleByteSource,并实现序列化接口
public class MySimpleByteSource extends SimpleByteSource implements Serializable {

public MySimpleByteSource(byte[] bytes) {
super(bytes);
// TODO Auto-generated constructor stub
}

}
在处理认证中
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
return new SimpleAuthenticationInfo(model, user.getPassword(), new MySimpleByteSource(salt), getName());
}

❺ 如何查询redis的缓存文件路径

1、首先找到redis的安装目录,如下图测试环境目录,进入到/opt/install/redis-2.8.19/src,如下图所示。

❻ 我配置了redis注解缓存,为什么不起作用

作为缓存服务器,如果不加以限制内存的话,就很有可能出现将整台服务器内存都耗光的情况,可以在redis的配置文件里面设置:
example:
#
限定最多使用1.5GB内存
maxmemory
1536mb
如果内存到达了指定的上限,还要往redis里面添加更多的缓存内容,需要设置清理内容的策略:
默认为0,没有指定最大缓存,如果有新的数据添加,超过最大内存,则会使redis崩溃,所以一点要设置。
设置maxmemory之后,配合的要设置缓存数据回收策略。

❼ shiro+redis中redis在什么地方调用

什么是Redis Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API ---维基网络 1.与其他用户状态保存方案比较 一般开发中用户状态使用session或者cookie,两种方式各种利弊

❽ web服务器怎么使用redis分步式缓存

Redis复制流程概述
Redis的复制功能是完全建立在之前我们讨论过的基于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生,那么首先要注意你的系统内存容量规划,原因可以参考我上一篇文章中提到的Redis磁盘IO问题。
Redis复制流程在Slave和Master端各自是一套状态机流转,涉及的状态信息是:
Slave 端:
REDIS_REPL_NONEREDIS_REPL_CONNECTREDIS_REPL_CONNECTED
Master端:
REDIS_REPL_WAIT_BGSAVE_STARTREDIS_REPL_WAIT_BGSAVE_ENDREDIS_REPL_SEND_BULKREDIS_REPL_ONLINE
整个状态机流程过程如下:
Slave端在配置文件中添加了slave of指令,于是Slave启动时读取配置文件,初始状态为REDIS_REPL_CONNECT。
Slave端在定时任务serverCron(Redis内部的定时器触发事件)中连接Master,发送sync命令,然后阻塞等待master发送回其内存快照文件(最新版的Redis已经不需要让Slave阻塞)。
Master端收到sync命令简单判断是否有正在进行的内存快照子进程,没有则立即开始内存快照,有则等待其结束,当快照完成后会将该文件发送给Slave端。
Slave端接收Master发来的内存快照文件,保存到本地,待接收完成后,清空内存表,重新读取Master发来的内存快照文件,重建整个内存表数据结构,并最终状态置位为 REDIS_REPL_CONNECTED状态,Slave状态机流转完成。
Master端在发送快照文件过程中,接收的任何会改变数据集的命令都会暂时先保存在Slave网络连接的发送缓存队列里(list数据结构),待快照完成后,依次发给Slave,之后收到的命令相同处理,并将状态置位为 REDIS_REPL_ONLINE。

整个复制过程完成,流程如下图所示:

Redis复制机制的缺陷
从上面的流程可以看出,Slave从库在连接Master主库时,Master会进行内存快照,然后把整个快照文件发给Slave,也就是没有象MySQL那样有复制位置的概念,即无增量复制,这会给整个集群搭建带来非常多的问题。
比如一台线上正在运行的Master主库配置了一台从库进行简单读写分离,这时Slave由于网络或者其它原因与Master断开了连接,那么当Slave进行重新连接时,需要重新获取整个Master的内存快照,Slave所有数据跟着全部清除,然后重新建立整个内存表,一方面Slave恢复的时间会非常慢,另一方面也会给主库带来压力。
所以基于上述原因,如果你的Redis集群需要主从复制,那么最好事先配置好所有的从库,避免中途再去增加从库。
Cache还是Storage
在我们分析过了Redis的复制与持久化功能后,我们不难得出一个结论,实际上Redis目前发布的版本还都是一个单机版的思路,主要的问题集中在,持久化方式不够成熟,复制机制存在比较大的缺陷,这时我们又开始重新思考Redis的定位:Cache还是Storage?
如果作为Cache的话,似乎除了有些非常特殊的业务场景,必须要使用Redis的某种数据结构之外,我们使用Memcached可能更合适,毕竟Memcached无论客户端包和服务器本身更久经考验。
如果是作为存储Storage的话,我们面临的最大的问题是无论是持久化还是复制都没有办法解决Redis单点问题,即一台Redis挂掉了,没有太好的办法能够快速的恢复,通常几十G的持久化数据,Redis重启加载需要几个小时的时间,而复制又有缺陷,如何解决呢?
Redis可扩展集群搭建1. 主动复制避开Redis复制缺陷。
既然Redis的复制功能有缺陷,那么我们不妨放弃Redis本身提供的复制功能,我们可以采用主动复制的方式来搭建我们的集群环境。
所谓主动复制是指由业务端或者通过代理中间件对Redis存储的数据进行双写或多写,通过数据的多份存储来达到与复制相同的目的,主动复制不仅限于用在Redis集群上,目前很多公司采用主动复制的技术来解决MySQL主从之间复制的延迟问题,比如Twitter还专门开发了用于复制和分区的中间件gizzard(https://github.com/twitter/gizzard) 。
主动复制虽然解决了被动复制的延迟问题,但也带来了新的问题,就是数据的一致性问题,数据写2次或多次,如何保证多份数据的一致性呢?如果你的应用对数据一致性要求不高,允许最终一致性的话,那么通常简单的解决方案是可以通过时间戳或者vector clock等方式,让客户端同时取到多份数据并进行校验,如果你的应用对数据一致性要求非常高,那么就需要引入一些复杂的一致性算法比如Paxos来保证数据的一致性,但是写入性能也会相应下降很多。
通过主动复制,数据多份存储我们也就不再担心Redis单点故障的问题了,如果一组Redis集群挂掉,我们可以让业务快速切换到另一组Redis上,降低业务风险。
2. 通过presharding进行Redis在线扩容。
通过主动复制我们解决了Redis单点故障问题,那么还有一个重要的问题需要解决:容量规划与在线扩容问题。
我们前面分析过Redis的适用场景是全部数据存储在内存中,而内存容量有限,那么首先需要根据业务数据量进行初步的容量规划,比如你的业务数据需要100G存储空间,假设服务器内存是48G,那么根据上一篇我们讨论的Redis磁盘IO的问题,我们大约需要3~4台服务器来存储。这个实际是对现有业务情况所做的一个容量规划,假如业务增长很快,很快就会发现当前的容量已经不够了,Redis里面存储的数据很快就会超过物理内存大小,那么如何进行Redis的在线扩容呢?
Redis的作者提出了一种叫做presharding的方案来解决动态扩容和数据分区的问题,实际就是在同一台机器上部署多个Redis实例的方式,当容量不够时将多个实例拆分到不同的机器上,这样实际就达到了扩容的效果。
拆分过程如下:
在新机器上启动好对应端口的Redis实例。
配置新端口为待迁移端口的从库。
待复制完成,与主库完成同步后,切换所有客户端配置到新的从库的端口。
配置从库为新的主库。
移除老的端口实例。
重复上述过程迁移好所有的端口到指定服务器上。

以上拆分流程是Redis作者提出的一个平滑迁移的过程,不过该拆分方法还是很依赖Redis本身的复制功能的,如果主库快照数据文件过大,这个复制的过程也会很久,同时会给主库带来压力。所以做这个拆分的过程最好选择为业务访问低峰时段进行。
Redis复制的改进思路
我们线上的系统使用了我们自己改进版的Redis,主要解决了Redis没有增量复制的缺陷,能够完成类似Mysql Binlog那样可以通过从库请求日志位置进行增量复制。
我们的持久化方案是首先写Redis的AOF文件,并对这个AOF文件按文件大小进行自动分割滚动,同时关闭Redis的Rewrite命令,然后会在业务低峰时间进行内存快照存储,并把当前的AOF文件位置一起写入到快照文件中,这样我们可以使快照文件与AOF文件的位置保持一致性,这样我们得到了系统某一时刻的内存快照,并且同时也能知道这一时刻对应的AOF文件的位置,那么当从库发送同步命令时,我们首先会把快照文件发送给从库,然后从库会取出该快照文件中存储的AOF文件位置,并将该位置发给主库,主库会随后发送该位置之后的所有命令,以后的复制就都是这个位置之后的增量信息了。

Redis与MySQL的结合
目前大部分互联网公司使用MySQL作为数据的主要持久化存储,那么如何让Redis与MySQL很好的结合在一起呢?我们主要使用了一种基于MySQL作为主库,Redis作为高速数据查询从库的异构读写分离的方案。
为此我们专门开发了自己的MySQL复制工具,可以方便的实时同步MySQL中的数据到Redis上。

(MySQL-Redis 异构读写分离)
总结:
Redis的复制功能没有增量复制,每次重连都会把主库整个内存快照发给从库,所以需要避免向在线服务的压力较大的主库上增加从库。
Redis的复制由于会使用快照持久化方式,所以如果你的Redis持久化方式选择的是日志追加方式(aof),那么系统有可能在同一时刻既做aof日志文件的同步刷写磁盘,又做快照写磁盘操作,这个时候Redis的响应能力会受到影响。所以如果选用aof持久化,则加从库需要更加谨慎。
可以使用主动复制和presharding方法进行Redis集群搭建与在线扩容。

❾ 怎么去操作shiro跟redis集成的session

第一步:配置WEB.XML
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第二步:SHIRO整合SPRING配置
applicationContext-shiro.xml 伪代码:

<!--Session集群配置-->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="3600000"/>
<property name="sessionDAO" ref="zkShiroSessionDAO"/>
<property name="sessionValidationScheler" ref="sessionValidationScheler"/>
<property name="" value="true"/>
<property name="sessionIdCookie" ref="wapsession"/>
</bean>

<!--
指定本系统SESSIONID, 默认为: JSESSIONID
问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失!
-->
<bean id="wapsession" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg name="name" value="WAPSESSIONID"/>
</bean>

<!--
定时清理僵尸session,Shiro会启用一个后台守护线程定时执行清理操作
用户直接关闭浏览器造成的孤立会话
-->
<bean id="sessionValidationScheler"
class="org.apache.shiro.session.mgt.">
<property name="interval" value="3600000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>

<!--由zk做session存储容器-->
<bean id="zkShiroSessionDAO" class="b2gonline.incometaxexamine._systembase.shiro.ZKShiroSessionDAO">
<!--使用内存缓存登录用户信息,一次获取用户登录信息后缓存到内存减少Shiro大量的读取操作,用户退出或超时后自动清除-->
<constructor-arg name="useMemCache" value="true"/>
<property name="zookeeperTemplate" ref="zookeeperTemplate"/>
<property name="shiroSessionZKPath" value="/SHIROSESSIONS"/>
<property name="sessionPrefix" value="session-"/>
</bean>

<!-- SHIRO安全接口 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
...
<property name="sessionManager" ref="sessionManager"/>
</bean>
第三步:Zookeeper对Shiro-SessionDao实现类
ZKShiroSessionDAO.JAVA伪代码:

import bgonline.foundation.hadoop.zk.IZookeeperTemplate;
import bgonline.foundation.hadoop.zk.ZNode;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.MapCache;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* ZOOKEEPER实现SHIRO集群SESSION存储
*
* @author aliencode
* @date 13-7-10
*/
public class ZKShiroSessionDAO extends CachingSessionDAO {

public ZKShiroSessionDAO() {
}

private boolean useMemCache = false;

/**
* SESSION ZK DAO 实例
* 如果开户缓存
* 用户登录时自动缓存, 用户登录超时自动删除
* 由于shiro的cacheManager是全局的, 所以这里使用setActiveSessionsCache直接设置Cache来本地缓存, 而不使用全局zk缓存.
* 由于同一用户可能会被路由到不同服务器,所以在doReadSession方法里也做了缓存增加.
*
* @param useMemCache 是否使用内存缓存登录信息
*/
public ZKShiroSessionDAO(boolean useMemCache) {
this.useMemCache = useMemCache;
if (useMemCache) {
setActiveSessionsCache(
new MapCache<>(this.ACTIVE_SESSION_CACHE_NAME, new ConcurrentHashMap<Serializable, Session>())
);
}
}

Logger logger = LoggerFactory.getLogger(this.getClass());

/**
* ZK操作类
*/
private IZookeeperTemplate zookeeperTemplate;

/**
* 缓存根路径, 结尾不加/
*/
private String shiroSessionZKPath = "/SHIROSESSIONS";

/**
* 缓存项前缀
*/
private String sessionPrefix = "session-";

/**
* 设置Shiro Session 前缀 默认 session-
*
* @param sessionPrefix
*/
public void setSessionPrefix(String sessionPrefix) {
this.sessionPrefix = sessionPrefix;
}

public void setZookeeperTemplate(IZookeeperTemplate zookeeperTemplate) {
this.zookeeperTemplate = zookeeperTemplate;
}

/**
* 设置Shiro在ZK服务器存放根路径
*
* @param shiroSessionZKPath 默认值:/SHIROSESSIONS/
*/
public void setShiroSessionZKPath(String shiroSessionZKPath) {
this.shiroSessionZKPath = shiroSessionZKPath;
}

/**
* session更新
*
* @param session
* @throws UnknownSessionException
*/
@Override
public void update(Session session) throws UnknownSessionException {
if (session == null || session.getId() == null) {
logger.error("session argument cannot be null.");
}
saveSession(session, "update");
}

@Override
protected void doUpdate(Session session) {
}

/**
* session删除
*
* @param session
*/
@Override
public void delete(Session session) {
if (session == null || session.getId() == null) {
logger.error("session argument cannot be null.");
}
logger.debug("delete session for id: {}", session.getId());
zookeeperTemplate.deleteNode(getPath(session.getId()));
if (useMemCache) {
this.uncache(session);
}
}

@Override
protected void doDelete(Session session) {
}

/**
* 获取当前活跃的session, 当前在线数量
*
* @return
*/
@Override
public Collection<Session> getActiveSessions() {
ZNode zNode = new ZNode();
zNode.setPath(shiroSessionZKPath);
Set<Session> sessions = new HashSet<Session>();
//读取所有SessionID , 返回形如: session-9e3b5707-fa80-4d32-a6c9-f1c3685263a5
List<String> ss = zookeeperTemplate.getChildren(zNode);
for (String id : ss) {
if (id.startsWith(sessionPrefix)) {
String noPrefixId = id.replace(sessionPrefix, "");
Session session = doReadSession(noPrefixId);
if (session != null) sessions.add(session);
}
}
logger.debug("shiro getActiveSessions. size: {}", sessions.size());
return sessions;
}

/**
* 创建session, 用户登录
*
* @param session
* @return
*/
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
saveSession(session, "create");
return sessionId;
}

/**
* session读取
*
* @param id
* @return
*/
@Override
protected Session doReadSession(Serializable id) {
if (id == null) {
logger.error("id is null!");
return null;
}
logger.debug("doReadSession for path: {}", getPath(id));

Session session;
byte[] byteData = zookeeperTemplate.getData(getPath(id)).getByteData();
if (byteData != null && byteData.length > 0) {
session = (Session) SerializationUtils.deserialize(byteData);
if (useMemCache) {
this.cache(session, id);
logger.debug("doReadSession for path: {}, add cached !", getPath(id));
}
return session;
} else {
return null;
}
}

/**
* 生成全路径
*
* @param sessID
* @return
*/
private String getPath(Serializable sessID) {
return shiroSessionZKPath + '/' + sessionPrefix + sessID.toString();
}

/**
* session读取或更新
*
* @param session
* @param act update/save
*/
private void saveSession(Session session, String act) {
Serializable sessionId = session.getId();
ZNode sessionNode = new ZNode();
sessionNode.setByteData(SerializationUtils.serialize(session));
sessionNode.setPath(getPath(sessionId));
logger.debug("save session for id: {}, act: {}", sessionId, act);
if (act == "update")
zookeeperTemplate.setData(sessionNode);
else
zookeeperTemplate.createNode(sessionNode);
}

}