谁说Session只能存储在服务器端?

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 今天使用Koa遇到了一个诡异的问题,然后仔细研究了Koa-Session的实现原理,刷新了我的认知。好我们从头讲起。 先看看Session的原理是什么?

Session是什么


session机制采用的是一种在服务器端保持状态的解决方案。由于采用服务器端能保持状态。也需要客户端保存一个标识。所以session机制可能需要借助于cookie机制来达到保存标识的目的。


网络异常,图片无法展示
|


  1. 服务器在接受客户端首次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在响应头中种下这个唯一标识字符串。


  1. 签名。这一步通过秘钥对sid进行签名处理,避免客户端修改sid。(非必需步骤)


  1. 浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息,


  1. 服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服务器端保存的该客户端的session,然后判断该请求是否合法。


如果按照经典实现的方式,session数据是保存在服务器端的,那么假设session不使用外部存储设备,session也就是存储在内存中的。那么如果一旦服务器重新启动所有session就会消失。


诡异的Koa-session


好那么我们看看Koa-Session是不是可以复现这个问题。


const koa = require('koa')
const app = new koa()
const session = require('koa-session')
// 签名key keys作用 用来对cookie进行签名
app.keys = ['some secret'];
// 配置项
const SESS_CONFIG = {
  key: 'kkb:sess', // cookie键名
  maxAge: 86400000, // 有效期,默认一天
  httpOnly: true, // 仅服务器修改
  signed: true, // 签名cookie
};
// 注册
app.use(session(SESS_CONFIG, app));
// 测试
app.use(ctx => {
  if (ctx.path === '/favicon.ico') return;
  // 获取
  let n = ctx.session.count || 0;
  // 设置
  ctx.session.count = ++n;
  ctx.body = '第' + n + '次访问';
});
app.listen(3000)


网络异常,图片无法展示
|


按照程序功能变量count每次都会累加,如果重新启动服务。count应该归零。但是结果确不是这样。


网络异常,图片无法展示
|


网络异常,图片无法展示
|


原因分析


这时候我们细致的分析一下。首先我么发现在这里存储sid的cookie字段的值是eyXXXXX这样的一个值。说明很可能是base64编码的json。不是我们通常认为的uuid。


网络异常,图片无法展示
|


通过在线的base64解码我们确认了这个结果。


网络异常,图片无法展示
|


这样问题就很清晰了。原来Koa-session默认确实是通过将session序列化后存储在客户端的。 我们从以下的npm文档中也可以证实了这个说法。


www.npmjs.com/package/koa…


网络异常,图片无法展示
|


文档里明确声明koa默认存储是放在客户端的非加密数据。


客户端存储的优缺点分析


优点


首先先说优点。客户端存储的优点大概有两个。


  • 低成本的实现了session的持久化问题


  • 低成本的实现了多实例共享session问题


通常情况下我们如果实现session的持久化和全局共享都需要使用第三方存储比如redis或者mongodb。client端序列化方式就很好的解决了这个问题。但是使用客户端存储就很好的解决了这个问题。


缺点


缺点也有两条


  • 存储容量有限制(Cookie 大小一般是4k)


  • 安全性问题由于存储在客户端而且是非加密数据所以不能存储敏感数据。


如何指定存储方式


在Koa-Session中如果希望变更存储方式可以通过实现store接口的方式实现。


内存实现


首先我们先写一个基础的内存实现。其实就是为了熟悉一下这个接口。


class Memory {
    constructor () {
        this.sotry = {}
    }
    get(key) {
        console.log('get:',key)
        return this.sotry[key]
    }
    set(key,sess) {
        console.log('set:',key,sess)
        this.sotry[key] = sess
    }
    destroy (key) {
        console.log('destroy:',key)
        this.sotry = {}
    }
}
const SESS_CONFIG = {
    key: 'kkb:sess', 
    store: new Memory() // 指定实现
}
app.use(session(SESS_CONFIG, app))


可以看到指定了存储后,koa-session会调用存储接口中的getter和setter方法。


网络异常,图片无法展示
|


浏览器中也不会存储序列化数据而是只存储sid也就是uuid。


网络异常,图片无法展示
|


完整代码


github.com/su37josephx…


Redis实现


另外我们再看看生产环境中常用的Redis存储方式。


const redisStore = require('koa-redis')
const redis = require('redis')
const redisClient = redis.createClient(6379, 'localhost')
const wrapper = require('co-redis')
const client = wrapper(redisClient)
app.keys = ['some secret']
const SESS_CONFIG = {
    key: 'kkb:sess', // 名
    store: redisStore({ client })
}
app.use(session(SESS_CONFIG, app))


总结


Koa的默认存储方式选择的是客户端序列化方式,刷新了我们对Session常规的印象。这种方式其实借鉴了JWT Token的实现方法。非常适合小型应用。可以很低成本的解决持久化和横向扩展问题。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
存储 数据挖掘 Windows
服务器数据恢复—V7000存储raid5故障导致LUN无法访问的数据恢复案例
服务器数据恢复环境: 三台V7000存储,共有64块SAS硬盘(其中有三块热备盘,其中一块已启用)组建了数组raid5阵列。分配若干LUN,上层安装Windows server操作系统,数据分区格式化为NTFS文件系统。 服务器故障: V7000存储中有多块硬盘出现故障离线,阵列失效,LUN无法访问。需要恢复卷中所有数据(主要为dcm文件)。
|
3月前
|
存储
服务器数据恢复—EMC存储RAID5阵列崩溃的数据恢复案例
服务器数据恢复环境: 一台EMC某型号存储设备,该存储中有一组由12块(包括2块热备盘)STAT硬盘组建的raid5阵列。 服务器故障: 该存储在运行过程中突然崩溃,raid瘫痪。数据恢复工程师到达现场对故障存储设备进行初检,发现raid中有两块硬盘掉线但只有一块热备盘成功激活,所以导致阵列瘫痪,上层lun无法使用。
|
1天前
|
存储 算法 数据挖掘
服务器数据恢复—nas中raid6阵列失效,存储无法访问的数据恢复案例
一台nas上共有14块硬盘组建了一组raid6磁盘阵列。 该nas在工作过程中,raid6阵列中硬盘出现故障离线,导致raid6阵列失效,nas无法正常访问。
|
8天前
|
存储 数据挖掘 数据库
服务器数据恢复—OceanStor存储数据恢复案例
华为OceanStor T系列某型号存储中有一组由24块机械硬盘组建的一组RAID5阵列。 运行过程中该存储设备RAID5阵列上多块硬盘出现故障离线,阵列失效,存储中数据无法访问。
|
19天前
|
存储 数据挖掘
服务器数据恢复—V7000存储上多块Mdisk成员盘出现故障的数据恢复案例
服务器存储数据恢复环境: 一台V7000存储上共12块SAS机械硬盘(其中1块是热备盘),组建了2组Mdisk,创建了一个pool。挂载在小型机上作为逻辑盘使用,小型机上安装的AIX+Sybase。 服务器存储故障: V7000存储中磁盘出现故障,管理员发现问题后立即更换磁盘。新更换的硬盘在上线同步数据的时候,存储上另一块磁盘也出现问题,导致逻辑盘无法挂接在小型机上,业务暂时中断。V7000存储的管理界面上显示两块硬盘故障脱机。 pool无法加载,其中三个通用卷均无法挂载。
|
2月前
|
存储 Oracle 关系型数据库
服务器数据恢复—EVA存储硬盘读写性能不稳定掉线的数据恢复案例
服务器存储数据恢复环境: 一台EVA某型号控制器+EVA扩展柜+FC磁盘。 服务器存储故障&检测: 磁盘故障导致该EVA存储中LUN不可用,导致上层应用无法正常使用。
104 47
|
1月前
|
存储 运维 数据挖掘
服务器数据恢复—EVA存储中多块硬盘离线导致存储崩溃的数据恢复案例
一台HP EVA存储中有23块硬盘,挂接到一台windows server操作系统的服务器。 EVA存储上有三个硬盘指示灯亮黄灯,此刻存储还能正常使用。管理员在更换硬盘的过程中,又出现一块硬盘对应的指示灯亮黄灯,存储崩溃,无法使用了。
|
2月前
|
存储 缓存 弹性计算
Codota的服务器存储架构
Codota的服务器存储架构
31 5
|
2月前
|
存储 Oracle 关系型数据库
服务器数据恢复—DS5300存储raid5阵列数据恢复案例
服务器存储数据恢复环境: 某单位一台某品牌型号为DS5300的服务器存储,1个机头+4个扩展柜,底层是2组分别由数十块硬盘组建的RAID5阵列。存储系统上层一共分了11个卷。 服务器存储故障&分析: 存储设备上一组raid5阵列上的2块磁盘出现故障,对应的硬盘指示灯亮黄灯,阵列崩溃,存储不可用。该组故障阵列上层存放的是Oracle数据库文件。
|
2月前
|
存储 运维 数据挖掘
服务器数据恢复—华为OceanStor存储数据恢复案例
服务器存储数据恢复环境: 华为品牌型号为OceanStor S2600T的存储设备,存储上有一组由24块4T容量的机械硬盘组建的RAID5阵列,作为存储池使用。 图1 服务器存储故障&检测: 存储设备中raid5阵列上多块硬盘出现故障离线,raid5阵列失效,数据无法正常访问。 关机后将存储中所有硬盘标记&取出,硬件工程师对所有硬盘进行硬件故障检测。经过检测,没有发现存在物理故障的磁盘,都可以正常读取。