随笔:Cookie与Session的今世前缘
本周尝试着写第一篇随笔,希望小伙伴儿们能够喜欢呀!文中不足之处,欢迎各位指正!
之前在学习JavaWeb的时候,学习过Cookie与Session的内容,当时也进行了相关的记录,写了一篇学习笔记,具体的学习笔记小伙伴儿们可以自行点击查看(第47次文章:cookie&session)。
当初第一遍学习的时候,感觉是一知半解就跳过了,上面那篇学习笔记也仅仅是记录一下学习的内容而已,没有什么深刻的体会。本周在学习过程中,再次遇到了cookie与session,感觉就像是一个“最熟悉的陌生人”。心中明明知道学过这个内容,然而却一点都不记得他们具体的内容了!哈哈!
不过这次的学习,真的让我对cookie和session的理解又上升到了一个新的高度。cookie与session简直是用自己的行为,诠释了什么叫“金风玉露一相逢,便胜却人间无数!”
我们的浏览器主要的功能是用来浏览文档的,可以简单的看做现在的PDF阅读软件。那个时候,我们的浏览器也不存在什么保存记忆的功能。当时的数据量也很小,没有什么负担,大家都很开开心的阅读文件就完事了。
随着时间的发展,进入了信息时代,单纯的阅读行为已经无法满足我们的要求了,需要浏览器具有一定的记忆功能。
在网络世界中,大家都遵守Http协议,用户给服务器发送请求,服务器给出响应。然而Http协议是一个无状态协议,如下图所示:
Http协议
那么什么叫无状态的呢?简单的来说,每次请求之间都是相互独立的,不会有任何的联系。我们来做一个简单的想象:
我们在电商平台进行购物,到了双十一,我们会提前在电商平台上选择很多件商品加入到购物车中。在零点时分,统一付款,一次结清。可是http协议是一个无状态的协议,每一次请求之间不会有任何的联系。这样的话,我们每次选择的商品之间,不会有任何的联系,那么也就无法统一存放到购物车中,统一付款了。
为了完成这个功能,我们需要服务器能够识别出每次选择商品的操作都是同一个用户。这样,我们选择选择商品时,每次选择操作之间都是有联系的。之间的关联就在于,这些都是同一个用户发出的请求。
那么如何才能让服务器端识别识别每次发送的请求来自于同一个客户端呢?有些大佬们就想到了一个解决方案:
客户端每次操作之后,从服务器端将操作之后的数据返还给客户端,也就是Cookie。 客户端收到Cokkie之后,将Cookie存放在本地缓存中,当下一次客户端向同一个服务器发送请求时,客户端顺带的带上这个cookie。
这样,服务器就可以直接识别出来当前的发送的请求是否与之前的请求是否有关了。cookie在客户端每次发送请求的时候,传递给服务器供服务器端识别。而服务器端同样需要将cookie响应给客户端。于是cookie就像一个皮球一样,被客户端和服务器端来回踢,如下图所示:
cookie
貌似,这样解决了我们购物的问题,现实也的确是的。然而,由于cookie需要每次都被携带此用户的所有信息,那么cookie将会像一个雪球一样,越来越大。当面对一个巨大的“雪球”的时候,客户端和服务器也发愁了。这么大,完全踢不动啊!带着这么大的数据,在每次请求传送过程中将会对传输效率造成极大的影响。
于是工程师们想到了一个另一个解决方法:
每次将客户端操作之后的数据不再传输给客户端,而是直接存储在服务器端,这些数据就是session。 然后对每个session加一个唯一编号JSESSIONID,将这个编号传输存储到cookie中,服务器将cookie传输给客户端。 客户端在每次访问服务器的时候,携带上这个cookie。服务器在响应的时候,将cookie发送给客户端进行存储。
由于cookie中仅仅存贮一个识别码JSESSIONID
而已,占用的内存非常少,在传输过程中不会占用太多资源,这样我们的效率就被提高起来了。
于是乎,我们所熟知的cookie和session就这样被创立了。通过cookie和session的诞生,可以发现,session在被创建的那一刻,就会指定一个特定的cookie与之进行匹配。
经过上面的故事我们可以重新再回过头来理解一下cookie和session的区别:
Cookie:
Session:
通过上面的分析可以发现,cookie和session是完美的一对啊!session就像一位伟大的丈夫,即便心中有千言万语,身上装有万贯家产,然而也只将能够打开自己的这把钥匙送给cookie,不让任何人进入自己的心中,守护着自己和cookie纯洁的感情,不允许有第三者的侵入。
当cookie在客户端被清除掉的时候,session将会面临着被服务器清空的命运。然而,此时的session没有后悔来这世上走一遭,只会默默的等待着那一刻的到来,与cookie一起消失在茫茫宇宙中。
每个session和cookie从出生的那一刻便只认准彼此。你不离不弃,我生死相依。每一次的分别,只是为了下一次的重逢!当你消失时,我也会孤独等待死亡的降临。正验证了白居易的那首诗“思悠悠,恨悠悠,恨到归时方始休”,多么凄美的故事啊!
凄美的故事就这样结束了么?并没有!
再往后,我们慢慢进入了大数据的时代。每位客户操作产生的数据会越来越多,而服务器的处理却是有限的,我们需要部署多台服务器来完成对用户功能的支持。
于是就产生了服务器分布式,部署多台服务器。如下所示:
当服务器集群之后,服务器端的抗压能力越来越强了。但是就对cookie和session这对恋人不利了。例如:
当我们第一次请求访问的是服务器1时,那么产生的session将会被服务器1创建,并且也会存储在服务器1中。可是当客户端发送第二次请求带着cookie来寻找session时。假如服务器1处于忙碌状态,而服务器集群具有负载均衡机制,服务器2被分配给了客户端的请求。此时,尽管客户端已经携带cookie来到了服务器端,但是却无法找到与之配对的session了。
这是多么糟糕的一件事啊,cookie为session踏遍千山万水,来到了session的基地,然而却把cookie分配到了这座城市的不同区域,无法探寻到与cookie匹配的session!这就是咫尺天涯吧!
为了解决这个问题,有几种解决方法:
方法1: 方案:将每一次客户端的请求与对应的服务器进行绑定。当遇到相同的客户端请求的时候,我们要求直接将其分配到固定的服务器进行处理访问。 问题:我们的服务器集成就失去了意义。本来我们想要完成负载均衡,然而当我们把客户端和服务器端完成绑定之后,我们就无法根据服务器的状态来动态的分配客户端的请求了。
面对无法负载均衡的问题,我们就想到了方法2:
方法2: 方案:我们将服务器每次产生的session数据为每个服务器都复制一份。那么客户端后面的每一次请求,无论分配给哪一个服务器来处理,都可以完成cookie与session的配对啦! 问题:此时我们的每个服务器之间的耦合度会很高,相互依赖,并且会给服务器造成极大的数据容量压力。我们服务器的空间余量也将大幅缩水。
面对每个服务器空间压力较大的问题,我们想出了方法3:
方法3: 方案:我们单独部署一个服务器,此服务器主要就用来存储session数据。服务器每次产生的session数据统一存放这个服务器中。当客户端发送请求的时候,我们统一到这个服务器中取出对应的session数据。 问题:此时解决了上面的所有问题,但是数据的备份就很成问题了。一旦这个服务器挂掉了,那么所有的服务器都会受到影响。这显然有很大的隐患。所以,依旧难以满足实际的部署需求。
面对上面的问题,我们就再次提出了一种解决方案:
方法4: 方案:我们放弃session,但是依旧使用cookie与session的思想,直接将所有的数据存储在数据库中,如下所示:
因为我们目前的数据库集成技术还是非常成熟的,所以这是一种非常可取的方式。但是数据库中的数据存储在硬盘上,所以获取的速度会明显小于之前在服务器内存中存储session数据。
不过,没关系,现在的技术发展,更加倾向于在数据库的前方,再用非关系型数据库Redis布置一个缓存区,这样就可以大大提升我们的存取速度啦!
发展到现在,session不建议被频繁使用,更加推荐使用数据库来存储。
当客户端拿着cookie来寻找session时,虽然此时的session已经面目全非,当年的英姿飒爽已然不再(被存储到了数据库中)。但是两者还是能够相互匹配,此时的cookie和session,已经不在乎彼此的模样,成为了精神匹配。
一生只为你,为爱而生,为爱而死!所爱隔山海,山海皆可平!