JAVA几种缓存技术介绍说明
1、OSCache
OSCache是个一个广泛采用的高性能的J2EE缓存框架,OSCache能用于任何java应用程序的普通的缓存解决方案。
OSCache有以下特点:
(1)缓存任何对象,你可以不受限制的缓存部分jsp页面或HTTP请求,任何java对象都可以缓存。
永久缓存--缓存能随意的写入硬盘,因此答应昂贵的创建(eXPensive-to-create)数据来保持缓存,甚至能让应用重启。
(2)支持集群--集群缓存数据能被单个的进行参数配置,不需要修改代码。
缓存记录的过期--你可以有最大限度的控制缓存对象的过期,包括可插入式的刷新策略(假如默认性能不需要时)。
2、Java Caching System
JSC(Java Caching System)是一个用分布式的缓存系统,是基于服务器的java应用程序。它是通过提供治理各种动态缓存数据来加速动态web应用。
JCS和其他缓存系统一样,也是一个用于高速读取,低速写入的应用程序。
动态内容和报表系统能够获得更好的性能。
假如一个网站,有重复的网站结构,使用间歇性更新方式的数据库(而不是连续不断的更新数据库),被重复搜索出相同结果的,就能够通过执行缓存方式改进其性能和伸缩性。
3、EHCache
EHCache 是一个纯java的在进程中的缓存,它具有以下特性:快速,简单,为Hibernate21充当可插入的缓存,最小的依靠性,全面的文档和测试。
4、JCache
JCache是个开源程序,正在努力成为JSR-107开源规范,JSR-107规范已经很多年没改变了。这个版本仍然是构建在最初的功能定义上。
5、ShiftOne
ShiftOne Java Object Cache是一个执行一系列严格的对象缓存策略的Java lib,就像一个轻量级的配置缓存工作状态的框架。
6、SwarmCache
SwarmCache是一个简单且有效的分布式缓存,它使用ip multicast与同一个局域网的其他主机进
行通讯,是非凡为集群和数据驱动web应用程序而设计的。
SwarmCache能够让典型的读操作大大超过写操作的这类应用提供更好的性能支持。
SwarmCache使用JavaGroups来治理从属关系和分布式缓存的通讯。
扩展资料
Java中缓存存在的原因:
一 般情况下,一个网站,或者一个应用,它的一般形式是,浏览器请求应用服务器,应用服务器做一堆计算后再请求数据库,数据库收到请求后再作一堆计算后把数据 返回给应用服务器。
应用服务器再作一堆计算后把数据返回给浏览器,这个是一个标准流程。但是随着互连网的普及,上网的人越来越多,网上的信息量也越来越多。
数据库每秒中接受请求的次数也是有限的,如果利用有限的资源来提供尽可能大的吞吐量呢。一个办法:减少计算量,缩短请求流程(减少网络io或者硬盘io),这时候缓存就可以大展手脚了。
缓存的基本原理就是打破上图中所描绘的标准流程,在这个标准流程中,任何 一个环节都可以被切断请求可以从缓存里取到数据直接返回。
Redis集群一般有5种:
1,主从复制
2,哨兵模式
3,Redis官方提供的Cluster集群模式(服务端)
4,Jedis sharding集群(客户端sharding)
5,利用中间件代理,比如豌豆荚的codis等
介绍完他们的模式,现在来分析一下他们的原理:
主从复制(Master-Slave Replication):
实现主从复制(Master-Slave Replication)的工作原理:Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC命令。Master服务主节点收到同步命令后将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave从节点服务在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。
主从复制配置
修改从节点的配置文件:slaveof masterip masterport
如果设置了密码,就要设置:masterauth master-password
哨兵模式:
该模式是从Redis的26版本开始提供的,但是当时这个版本的模式是不稳定的,直到Redis的28版本以后,这个哨兵模式才稳定下来,无论是主从模式,还是哨兵模式,这两个模式都有一个问题,不能水平扩容,并且这两个模式的高可用特性都会受到Master主节点内存的限制。
Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用。
Sentinel(哨兵)进程的作用
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用现在的Master替换失效Master。Master和Slave服务器切换后,Master的redisconf、Slave的redisconf和sentinelconf的配置文件的内容都会发生相应的改变,即,Master主服务器的redisconf配置文件中会多一行slaveof的配置,sentinelconf的监控目标会随之调换。
Sentinel(哨兵)进程的工作方式
每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
Redis官方 Cluster集群模式
Redis Cluster是一种服务器Sharding技术,30版本开始正式提供。
在这个图中,每一个蓝色的圈都代表着一个redis的服务器节点。它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。
Redis集群数据分片
在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量这个变量的取值范围是:0-16383。还有一个就是cluster我个人把这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
Jedis sharding集群
Redis Sharding可以说是在Redis cluster出来之前业界普遍的采用方式,其主要思想是采用hash算法将存储数据的key进行hash散列,这样特定的key会被定为到特定的节点上。
庆幸的是,Java Redis客户端驱动Jedis已支持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool
Jedis的Redis Sharding实现具有如下特点:
采用一致性哈希算法,将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。
为了避免一致性哈希只影响相邻节点造成节点分配压力,ShardedJedis会对每个Redis节点根据名字(没有,Jedis会赋予缺省名字)会虚拟化出160个虚拟节点进行散列。根据权重weight,也可虚拟化出160倍数的虚拟节点。用虚拟节点做映射匹配,可以在增加或减少Redis节点时,key在各Redis节点移动再分配更均匀,而不是只有相邻节点受影响。
ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,这样通过合理命名key,可以将一组相关联的key放入同一个Redis节点,这在避免跨节点访问相关数据时很重要。
利用中间件代理
中间件的作用是将我们需要存入redis中的数据的key通过一套算法计算得出一个值。然后根据这个值找到对应的redis节点,将这些数据存在这个redis的节点中。
常用的中间件有这几种
Twemproxy
Codis
nginx
java目前常用的缓存:
Generic
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, etc)
EhCache 2x
Hazelcast
Infinispan
Couchbase
Redis
Caffeine
Guava (deprecated)
Simple
建议使用spring boot集成方式,可插拔,简单。
集中式缓存适用场景:
1、服务器集群部署。
2、数据高一致性(任何数据变化都能及时的被查询到)
分布式缓存适用场景:
系统需要缓存的数据量大
对数据的可用性较高的情况
需要横向扩展,从而达到缓存的容量无限的要求
整个网站架构一般可以分为应用层、服务层、数据层。实践中大的分层结构还可以继续分层,比如应用层还可以继续分为视图层和业务逻辑层,服务层也可以继续细分为数据接口层、逻辑处理层等。通过分层,把一个庞大的系统切分为不同的部分,便于分工开发和维护;各层之间相互有一定的独立性,在网站的开发中可以根据不同的需求进行相应的调整。逻辑上分层之后,在物理部署上也可以根据需求制定不同的策略。
分层架构不仅仅是为了规划软件的逻辑结构,其对网站的高并发分布式架构来说尤为重要。进行分层以后,可以从纵向进行业务分割,根据不同的业务模块一个项目划分成不同的模块交给单独的团队去开发部署,完成后分别部署在不同的服务器上,通过链接进行互联。再根据不同情况来对不同的节点进行冗余来保证网站的高可用性,接下来进行缓存、CDN、反向代理等等的优化。
对于一个高访问量、大数据量的网站我们需要考虑什么呢
11性能
首先就是性能了,性能是一个网站的的重要指标,除非是没得选择,就这一个网站,不然用户是绝对不会忍受一个超级慢的网站。正因为性能问题无处不在,解决性能问题的方式也各种各样,从用户请求一个url开始,进行的每一个环节都可以进行优化;根据上面的分层,可以大致从三个方面进行优化,应用层优化,服务层优化,数据层优化。
涉及到的知识就是web前端的优化,应用服务器端的优化和数据的存储,索引,缓存等,这些在后面的内容里会分别展开细说,但性能只是一个网站的必要条件,除此之外,因为无法预知网站可能会面临的压力或是攻击,还要保证网站在各种情境下(高并发,高负载,持续压力不均匀等)保持稳定的性能。包括以下各个方面:性能测试指标、性能测试方法、性能优化策略。
性能测试指标
主要的性能测试指标有响应时间、并发数、吞吐量、性能计数器等。
响应时间
指的是从发出这个请求开始到接收到数据的时间,一般情况下这个时间都非常非常的小甚至小于测试的误差值,所以我们可以采用重复请求的方式来获取具体的响应时间,比如请求十万次,记录总时间,然后计算出单次请求的时间
并发数
指能够同时处理的请求数目,对于网站而言,即并发用户数
吞吐量
是单位时间能能够处理的请求数,体现的系统的整体处理能力>衡量指标有很多,可以是请求数/秒页面数/秒访问人数/天处理业务数/小时等>常用的量化指标有TPS(每秒事务数)HPS(每秒HTTP请求数)QPS(每秒查询数)等
性能计数器
描述服务器或操作系统的一些性能指标,包括系统负载(SystemLoad),线程数,内存使用,磁盘和网络I/O等,当这些值超过警告值(安全临界值)时,就会向开发人员报警,及时处理异常。
性能测试方法
性能测试是一个统称,具体可以分为性能测试、负载测试、压力测试、稳定性测试。性能测试以初期设计的指标为预期目标,不断对系统施压,看系统在预期的范围内,能否达到预期的性能。负载测试对系统不断增加并发请求以增加系统压力,直到系统某项或多项指标达到安全临界值,这时继续对系统施加压力,系统的处理能力会有所下降。压力测试是在超过安全负载的情况下,继续施压,直到系统崩溃或不再能够处理任何请求,以此来计算系统的最大压力承受能力。
稳定性测试在一定的压力(不均匀施压)下,系统能够稳定的运行较长时间。
性能优化策略
要定位问题产生原因,排查不同环节的日志,分析哪个环节的响应时间与预期不相符,然后分析影响性能的原因,是代码问题还是架构设计不合理,或者系统资源不足,然后根据实际问题进行解决。
12可用性
对于大型网站而言,出现宕机的情况是可怕的,因为可能有上千万的用户量,短短几分钟的宕机都有可能导致网站声誉扫地,如果是电商类的网站,更可能会导致用户的财产损失,甚至会摊上官司,那时候损失的就不仅是金钱和用户了,因此要保证能够提供每天24小时的可用,但实际中服务器并不能保证每天24小时都能平稳的运行,可能出现硬件问题,也可能出现软件问题,总之问题总是会有的。
所以我们高可用设计的目标就是在某些服务器宕机的情况下,也能够保证服务或应用正常运行,网站高可用的主要手段是冗余,应用部署在多台服务器上同时提供访问,数据存储在多台数据服务器之间互相进行热备份,这样任何一台服务器宕机都不会影响服务或应用的整体,也不会产生数据丢失。
对于应用服务器而言,多台应用服务器通过一个负载均衡设备组成一个集群同时对外提供服务,当一台服务器宕机后,服务切换到其他服务器上继续执行,这样就可以保证了网站的高可用性,前提是应用服务器不允许存储用户会话信息,否则将会丢失,这样即使用户请求转接到其他服务器上面也无法继续执行。
对于数据存储服务器,要提供服务器之间的实时备份,这样当一台服务器宕机的时候,将数据访问切换到其他服务器上,并进行数据恢复和备份,衡量一个系统架构设计是否满足高可用的目标,就是假设其中一台或多台服务器宕机以及出现各种不可预期的问题时,系统整体是否依然可用。
13伸缩性
面对着大量用户的高并发访问和海量的数据存储,不可能只用一台服务器就能够满足全部需求,存储全部数据。通过集群的方式将多台服务器组成一个整体共同提供服务,所谓伸缩性就是指通过不断向集群中加入服务器的手段来应对不断上升的用户并发访问压力和不断增长的数据存储需求,对于应用服务器集群,只要服务器上不存储数据,所有的服务器都是对等的,通过使用合适的负载均衡设备就可以向集群中不断加入新的服务器。
对于缓存服务器而言,加入新的服务器可能会导致缓存路由失效,从而导致大部分的缓存数据都无法访问,需要改进缓存路由算法来保证缓存数据可访问,关系数据库虽然支持数据复制,主从热备份等机制,但是很难实现大规模集群的可伸缩性。
14可扩展性
网站的扩展性直接关系到网站功能模块的开发,网站快速发展,功能也不断的增加,网站架构的可扩展性的主要目的是使其能够快速的应对需求变化,是为了能够在增加新业务时,尽量实现对现有产品无影响,不需要改动或是改动很少现有业务就能够上线新产品;不同的产品业务之间的耦合度很小,一个产品或业务的改动不会对其他造成影响。
15安全性
最后就是安全性了。互联网是一个开放的平台,任何人在任何地方都可以访问网站。安全架构就是保护网站不受恶意的访问和攻击,保护数据不被窃取。
网站众所周知,web server是无状态的,也就是说服务器不知道用户在最后一次请求中做了什么,请求之间是相互独立的。客户信息仅来自每个请求携带的或由服务器本身保存的公共信息,并且可以被所有请求使用。因此,为了跟踪用户请求的状态信息,比如网购的购物车历史,Cookie应运而生。
当服务器响应客户端的请求时,它会向客户端推送一个Cookie。这个Cookie记录了服务器上的一些信息。客户端在后续请求中携带这个Cookie,服务器可以根据这个Cookie判断请求的上下文。
Cookie的出现是从无国籍状态过渡到有国家状态的一种手段。
以登录为例,用户输入帐户名和密码,向服务器发送请求。服务器生成一个Cookie并发送给浏览器。浏览器将Cookie以k-v的形式保存在某个目录下的文本文件中,下次请求同一个网站时会将Cookie发送给服务器。服务器验证接收到的Cookie是否与服务器的Cookie一致;否则,验证失败。这是最初的想法。
img src=' https://P6 toutiaoimgcom/large/PGC-image/48e 7b 24 ea 95 f 4 E0 CB 8d 940 DC 05 feb 1 EC '/
存储在浏览器中的Cookie的位置如下图所示。
img src=' https://p26 toutiaoimgcom/large/PGC-image/b 35 b 701d 7 b 454 ada 95 a 49 a 36d 0026 a F9 '/
Cookie的原理决定了他具有以下特征:
在存储客户端,可以随意篡改,不安全。
它的内容会和http交互传输,会影响性能,所以Cookie能存储的数据不能太大,最多4kb。
一个浏览器只能为一个网站存储不超过20个cookie,而浏览器一般只允许300个cookie。
移动对Cookie支持不友好。
一般来说,存储的是纯文本,对象在存储之前需要序列化,解析需要反序列化。
还是以登录Cookie为例。例如,现在有两个二级域名,http://axxxcom(域名A)和3358bxxxcom(域名B)。那么域名A的登录Cookie可以在域名B下使用吗?
默认情况下,域名A的服务主机中生成的Cookie只能由域名A的服务器获取,其他域名无法获取这个Cookie,只能是主机Cookie。
但是,服务器可以显式声明Cookie的域来定义它的域。比如域名A的登录Cookie的域设置为http://xxxcom(他们共同的顶级域名),path设置为'/',Set-Cookie:name=value;domain=xxxcomPath='/',那么域名B就可以读了。
在新规范rfc6265中,domain的值将忽略任何前导点,即子域中可以使用xxxcom和 XXXcom 。SSO(单点登录)也是根据这个原理实现的。
例如,现在有两个域名,abefcomcn(域名1)和cdefcomcn(域名2)。域名2想读取域名1的Cookie。域名1可以声明哪些域?答案是effcomcn或者 fcomcn,浏览器不能接受以domian为comcn的cookie,因为如果cookie域名可以设置为后缀的话,那就是峡谷大战了。
如果域名1设置了Set-Coo
kie:mykey=myvalue1;domain=efcomcn;path=’/’
域名 2 设置Set-Cookie:mykey=myvalue2;domain=efcomcn;path=’/’
那该域下 mykey 的值会被覆盖为 myvalue2,很好理解,同一个域下,Cookie 的 mykey 是唯一的。通常,我们要通过设置正确的 domain 和 path,减少不必要的数据传输,节省带宽。
随着交互式 Web 使用的兴起,Cookie 大小的限制以及浏览器对存储 Cookie 的数量限制,我们一定需要更强大的空间来储存大量的用户信息,比如我们这个网站是谁登录了,谁的购物车里加入了商品等等,服务器要保存千万甚至更多的用户的信息,Cookie 显然是不行的。那怎么办呢?
那将用户信息存储在哪呢?能否直接存在服务器中?
如果存在服务器中,1、这对服务器说是一个巨大的开销,严重的限制了服务器的扩展能力。2、假设 web 服务器做了负载均衡,用户 user1 通过机器 A 登入该系统,那么下一个请求如果被转发到另一台机器 B 上,机器 B 上是没有存该用户信息的,所以也找不到 sessionId,因此 sessionId 不应该存储在服务器上。这个时候redis/Memcached便出来解决该问题了,可以简单的理解它们为一个缓存数据库。
当我们把 sessionId 集中存储到一个独立的缓存服务器上,所有的机器根据 sessionId 到这个缓存系统里去获取用户信息和认证。那么问题就迎刃而解了。
根据其工作原理,你有没有发现这个方式会存在一个什么样的问题?那就是增加了单点登录失败的可能性,如果负责 session 的机器挂了, 那整个登录也就挂了。但是一般在项目里,负责 session 的机器也是有多台机器的集群进行负载均衡,增加可靠性。
思考:
假如服务器重启的话,用户信息会丢失吗?
Redis 等缓存服务器也是有个集群的,假设某一台服务重启了,会从其他运行的服务器中查找用户信息,那假设真的某一次所有服务器全都崩溃了,怎么办呢?大概的应对策略就是,存储在内存中的用户信息会定期刷到主机硬盘中以持久化数据,即便丢失,也只会丢失重启的那几分钟内的用户数据。
Cookie-session 局限性
依赖 Cookie,用户可以在浏览器端禁用 Cookie
不支持跨端兼容 app 等
业务系统不停的请求缓存服务器查找用户信息,使得内存开销增加,服务器压力过大
服务器是有状态的,如果是没有缓存服务器的方式,扩容就非常困难,需要在多台服务器中疯狂复制 sessionId
存在单点登录失败的可能性
单点登录(Single Sign On),简称为 SSO。随着企业的发展,一个大型系统里可能包含 n 多子系统,用户在操作不同的系统时,需要多次登录,很麻烦,单点登录就是用来解决这个问题的,在多个使用系统中,只需要登录一次,就可以访问其他相互信任的使用系统。
之前我们说过,单点登录是基于 cookie 同顶域共享的,那按照不同的情况可分为以下 3 种类型。
同一个站点下;
系统在相同的顶级域名下;
各子系统属于不同的顶级域名
一般情况下一个企业有一个顶级域名,前面讲过了,同一个站点和相同顶级域下的单点登录是利用了 Cookie 顶域共享的特性,相信大家已经明白这个流程,不再赘述。但如果是不同域呢?不同域之间 Cookie 是不共享的,怎么办?
这里我们就要说一说 CAS(中央认证服务 )流程了,这个流程是单点登录的标准流程。它借助一个单独的系统专门做认证用,以下成为SSO系统。
它的流程其实跟 Cookie-session 模式是一样的,单点登录等于说是每个子系统都拥有一套完整的 Cookie-session 模式,再加上一套 Cookie-session 模式的 SSO 系统。
用户访问系统 a,需登录的时候跳到 SSO 系统,在 SSO 系统里通过账号密码认证之后,SSO 的服务器端保存 session,,并生成一个 sessionId 返回给 SSO 的浏览器端,浏览器端写入 SSO 域下的 Cookie,并生成一个生成一个 ST,携带该 ST 传入系统 a,系统 a 用这个 ST 请求 SSO 系统做校验,校验成功后,系统 a 的服务器端将登录状态写入 session 并种下系统 a 域下的 Cookie。之后系统 a 再做登录验证的时候,就是同域下的认证了。
这时,用户访问系统 b,当跳到 SSO 里准备登录的时候发现 SSO 已经登录了,那 SSO 生成一个 ST,携带该 ST 传入系统 b,系统 b 用这个 ST 请求 SSO 系统做校验,校验成功后,系统 b 的服务器端将登录状态写入 session 并设置系统 b 域下的 Cookie。可以看得出,在这个流程里系统 b 就不需要再走登录了。
关于“跳到 SSO 里准备登录的时候发现 SSO 已经登录了”,这个是怎么做的呢,这就涉及 Oauth2 授权机制了,在这里就不展开讲,简单提个思路,就是在系统 b 向 SSO 系统跳转的时候让它从系统 a 跳转,携带系统 a 的会话信息跳到 SSO,再通过重定向回系统 b。
关于 Oauth2,可移步阮一峰 的《OAuth 20 的四种方式》。
我们已经分析过 Cookie-session 的局限性了,还有没有更彻底的解决办法呢?既然 SSO 认证系统的存在会增加单点失败的可能性,那我们是不是索性不要它?这就是去中心化的思路,即省去用来存储和校验用户信息的缓存服务器,以另外的方式在各自系统中进行校验。实现方式简单来说,就是把 session 的信息全部加密到 Cookie 里,发送给浏览器端,用 cpu 的计算能力来换取空间。
服务端不保存 sessionId,用户登录系统后,服务器给他下发一个令牌(token),下一次用户再次通过 Http 请求访问服务器的时候, 把这个 token 通过 Http header 或者 url 带过来进行校验。为了防止别人伪造,我们可以把数据加上一个只有自己才知道的密钥,做一个签名,把数据和这个签名一起作为 token 发送过去。这样我们就不用保存 token 了,因为发送给用户的令牌里,已经包含了用户信息。当用户再次请求过来的时候我用同样的算法和密钥对这个 token 中的数据进行加密,如果加密后的结果和 token 中的签名一致,那我们就可以进行鉴权,并且也能从中取得用户信息。
对于服务端来说,这样只负责生成 token , 然后验证 token ,不再需要额外的缓存服务器存储大量的 session,当面对访问量增加的情况,我们只需要针对访问需求大的服务器进行扩容就好了,比扩充整个用户中心的服务器更节省。
假如有人篡改了用户信息,但是由于密钥是不知道的,所以 token 中的签名和被篡改后客户端计算出来的签名肯定是不一致的,也会认证失败,所以不必担心安全问题。
关于 token 的时效性,是这样做的,首次登陆根据账号密码生成一个 token,之后的每次请求,服务端更新时间戳发送一个新的 token,客户端替换掉原来的 token。
jwt 模式的退出登录实际上是假的登录失效,因为只是浏览器端清除 token 形成的假象,假如用之前的 token 只要没过期仍然能够登陆成功
安全性依赖密钥,一旦密钥暴露完蛋
加密生成的数据比较长,相对来说占用了更大的流量
不依赖 Cookie,可跨端跨程序使用,支持移动设备
相对于没有单点登录的 cookie-session 模式来说非常好扩展
服务器保持了无状态特性,不需要将用户信息存在服务器或 Session 中
对于单点登录需要不停的向 SSO 站点发送验证请求的模式节省了大量请求
相关问答:
0条评论