当前位置: 首页 > news >正文

网站没备案或与实际备案不符发稿社

网站没备案或与实际备案不符,发稿社,益阳网站建设广告,房产网站程序课程学习 一致性哈希算法集群时钟同步问题分布式ID解决方案分布式任务调度问题session共享(一致性)问题 一致性哈希算法 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的#xff0c;设计目标是为了解决因特网中的热点(Hot spot)问题#xff0c…课程学习 一致性哈希算法集群时钟同步问题分布式ID解决方案分布式任务调度问题session共享(一致性)问题 一致性哈希算法 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的设计目标是为了解决因特网中的热点(Hot spot)问题初衷和CARP十分类似。一致性哈希修正了CARP使用的简单哈希算法带来的问题使得DHT可以在P2P环境中真正得到应用。 但现在一致性hash算法在分布式系统中也得到了广泛应用研究过memcached缓存数据库的人都知道memcached服务器端本身不提供分布式cache的一致性而是由客户端来提供具体在计算一致性hash时采用如下步骤 首先求出memcached服务器节点的哈希值并将其配置到0232的圆continuum上。然后采用同样的方法求出存储数据的键的哈希值并映射到相同的圆上。然后从数据映射到的位置开始顺时针查找将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器就会保存到第一台memcached服务器上。从上图的状态中添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率但Consistent Hashing中只有在园continuum上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响如下图所示 一致性Hash性质 考虑到分布式系统每个节点都有可能失效并且新的节点很可能动态的增加进来如何保证当系统的节点数目发生变化时仍然能够对外提供良好的服务这是值得考虑的尤其实在设计分布式缓存系统时如果某台服务器失效对于整个系统来说如果不采用合适的算法来保证一致性那么缓存于系统中的所有数据都可能会失效即由于系统节点数目变少客户端在请求某一对象时需要重新计算其hash值通常与系统中的节点数目有关由于hash值已经改变所以很可能找不到保存该对象的服务器节点因此一致性hash就显得至关重要良好的分布式cahce系统中的一致性hash算法应该满足以下几个方面 平衡性(Balance) 平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。 单调性(Monotonicity) 单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中又有新的缓冲区加入到系统中那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去而不会被映射到旧的缓冲集合中的其他缓冲区。简单的哈希算法往往不能满足单调性的要求如最简单的线性哈希x (ax b) mod (P)在上式中P表示全部缓冲的大小。不难看出当缓冲大小发生变化时(从P1到P2)原来所有的哈希结果均会发生变化从而不满足单调性的要求。哈希结果的变化意味着当缓冲空间发生变化时所有的映射关系需要在系统内全部更新。而在P2P系统内缓冲的变化等价于Peer加入或退出系统这一情况在P2P系统中会频繁发生因此会带来极大计算和传输负荷。单调性就是要求哈希算法能够应对这种情况。 分散性(Spread) 在分布式环境中终端有可能看不到所有的缓冲而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时由于不同终端所见的缓冲范围有可能不同从而导致哈希的结果不一致最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的因为它导致相同内容被存储到不同缓冲中去降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生也就是尽量降低分散性。 负载(Load) 负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中那么对于一个特定的缓冲区而言也可能被不同的用户映射为不同的内容。与分散性一样这种情况也是应当避免的因此好的哈希算法应能够尽量降低缓冲的负荷。 平滑性(Smoothness) 平滑性是指缓存服务器的数目平滑改变和缓存对象的平滑改变是一致的。 原理 基本概念 一致性哈希算法Consistent Hashing最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。简单来说一致性哈希将整个哈希值空间组织成一个虚拟的圆环如假设某哈希函数H的值空间为0-2^32-1即哈希值是一个32位无符号整形整个哈希空间环如下 整个空间按顺时针方向组织。0和232-1在零点中方向重合。 下一步将各个服务器使用Hash进行一个哈希具体可以选择服务器的ip或主机名作为关键字进行哈希这样每台机器就能确定其在哈希环上的位置这里假设将上文中四台服务器使用ip地址哈希后在环空间的位置如下 接下来使用如下算法定位数据访问到相应服务器将数据key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置从此位置沿环顺时针“行走”第一台遇到的服务器就是其应该定位到的服务器。 例如我们有Object A、Object B、Object C、Object D四个数据对象经过哈希计算后在环空间上的位置如下 根据一致性哈希算法数据A会被定为到Node A上B被定为到Node B上C被定为到Node C上D被定为到Node D上。 下面分析一致性哈希算法的容错性和可扩展性。现假设Node C不幸宕机可以看到此时对象A、B、D不会受到影响只有C对象被重定位到Node D。一般的在一致性哈希算法中如果一台服务器不可用则受影响的数据仅仅是此服务器到其环空间中前一台服务器即沿着逆时针方向行走遇到的第一台服务器之间数据其它不会受到影响。 下面考虑另外一种情况如果在系统中增加一台服务器Node X如下图所示 此时对象Object A、B、D不受影响只有对象C需要重定位到新的Node X 。一般的在一致性哈希算法中如果增加一台服务器则受影响的数据仅仅是新服务器到其环空间中前一台服务器即沿着逆时针方向行走遇到的第一台服务器之间数据其它数据也不会受到影响。 综上所述一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据具有较好的容错性和可扩展性。 另外一致性哈希算法在服务节点太少时容易因为节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器其环分布如下 此时必然造成大量数据集中到Node A上而只有极少量会定位到Node B上。为了解决这种数据倾斜问题一致性哈希算法引入了虚拟节点机制即对每一个服务节点计算多个哈希每个计算结果位置都放置一个此服务节点称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况可以为每台服务器计算三个虚拟节点于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值于是形成六个虚拟节点 同时数据定位算法不变只是多了一步虚拟节点到实际节点的映射例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中通常将虚拟节点数设置为32甚至更大因此即使很少的服务节点也能做到相对均匀的数据分布。 集群时钟同步问题 第一种方法 如果集群可以联网的化可以使用定时任务来使每一台机器和外界时间同步服务器保持一致 使用root用户进行配置 前提安装ntp.x86_64 如果没有安装可以使用 yum list | grep ntp 查找相关的软件 用 yum -y install 软件名 进行安装 安装顺序 先安装ntpdate 有两个文件一个使ntp.x86_64另一个是ntpdate.x86_64 用service ntpd start 开启服务 其次保证ntpd 服务运行......service ntpd start 然后: 使用root用户进行定时* */2 * * * /usr/sbin/ntpdate -u time.windows.com第一个* 是分钟的意思第二个*是小时的意思第三个*是日的意思第四个*是月的意思第五个*是周的意思/2这里是代表每两个小时 不能联网时 选择一台机器作为时间服务器其他机器和时间服务器同步时间来保证集群内的时间相同 第二种方式: 自定义时间服务器 1. 选择集群中的某一台机器master作为时间服务器 2. 保证这台服务器安装了ntp.x86_64。 3. 配置相应文件vi /etc/ntp.conf   # Hosts on local network are less restricted.#restrict 192.168.1.0 mask 255.255.255.0 nomodify notraprestrict 192.168.81.0 mask 255.255.255.0 nomodify notrap// 添加集群中的网络段位# Use public servers from the pool.ntp.org project.# Please consider joining the pool (http://www.pool.ntp.org/join.html).#server 0.centos.pool.ntp.org iburst 注释掉#server 1.centos.pool.ntp.org iburst 注释掉#server 2.centos.pool.ntp.org iburst 注释掉#server 3.centos.pool.ntp.org iburst 注释掉server 127.127.1.0 -master作为服务器4. 保证服务开启5. 其他机器要保证安装ntpdate.x86_646. 其他机器要使用root定义定时器* */2 * * * /usr/sbin/ntpdate 服务器的名字或者ip 分布式ID解决方案 1. UUID方案 优点 能够保证独立性程序可以在不同的数据库间迁移效果不受影响。 保证生成的ID不仅是表独立的而且是库独立的这点在你想切分数据库的时候尤为重要。 缺点 1. 性能为题UUID太长通常以36长度的字符串表示,对MySQL索引不利如果作为数据库主键在InnoDB引擎下UUID的无序性可能会引起数据位置频繁变动严重影响性能 2. UUID无业务含义很多需要ID能标识业务含义的地方不使用 3.不满足递增要求 2. snowflake方案 snowflake是twitter开源的分布式ID生成系统。 Twitter每秒有数十万条消息的请求每条消息都必须分配一条唯一的id这些id还需要一些大致的顺序方便客户端排序并且在分布式系统中不同机器产生的id必须不同。 snowflake的结构如下(每部分用-分开): 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 – 000000000000 第一位为未使用接下来的41位为毫秒级时间(41位的长度可以使用69年)然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点 最后12位是毫秒内的计数12位的计数顺序号支持每个节点每毫秒产生4096个ID序号 一共加起来刚好64位为一个Long型。(转换成字符串长度为18) snowflake生成的ID整体上按照时间自增排序并且整个分布式系统内不会产生ID碰撞由datacenter和workerId作区分并且效率较高。snowflake的缺点是: 强依赖时钟,如果主机时间回拨,则会造成重复ID,会产生ID虽然有序,但是不连续snowflake现在有较好的改良方案,比如美团点评开源的分布式ID框架leaf通过使用ZooKeeper解决了时钟依赖问题。 snowflake的关键源码如下 /*** Twitter_Snowflakebr* SnowFlake的结构如下(每部分用-分开):br* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 br* 1位标识由于long基本类型在Java中是带符号的最高位是符号位正数是0负数是1所以id一般是正数最高位是0br* 41位时间截(毫秒级)注意41位时间截不是存储当前时间的时间截而是存储时间截的差值当前时间截 - 开始时间截)* 得到的值这里的的开始时间截一般是我们的id生成器开始使用的时间由我们程序来指定的如下下面程序IdWorker类的startTime属性。41位的时间截可以使用69年年T (1L 41) / (1000L * 60 * 60 * 24 * 365) 69br* 10位的数据机器位可以部署在1024个节点包括5位datacenterId和5位workerIdbr* 12位序列毫秒内的计数12位的计数顺序号支持每个节点每毫秒(同一机器同一时间截)产生4096个ID序号br* 加起来刚好64位为一个Long型。br* SnowFlake的优点是整体上按照时间自增排序并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分)并且效率较高经测试SnowFlake每秒能够产生26万ID左右。*/ public class SnowflakeIdWorker {// Fields/** 开始时间截 (2015-01-01) */private final long twepoch 1420041600000L;/** 机器id所占的位数 */private final long workerIdBits 5L;/** 数据标识id所占的位数 */private final long datacenterIdBits 5L;/** 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId -1L ^ (-1L workerIdBits);/** 支持的最大数据标识id结果是31 */private final long maxDatacenterId -1L ^ (-1L datacenterIdBits);/** 序列在id中占的位数 */private final long sequenceBits 12L;/** 机器ID向左移12位 */private final long workerIdShift sequenceBits;/** 数据标识id向左移17位(125) */private final long datacenterIdShift sequenceBits workerIdBits;/** 时间截向左移22位(5512) */private final long timestampLeftShift sequenceBits workerIdBits datacenterIdBits;/** 生成序列的掩码这里为4095 (0b1111111111110xfff4095) */private final long sequenceMask -1L ^ (-1L sequenceBits);/** 工作机器ID(0~31) */private long workerId;/** 数据中心ID(0~31) */private long datacenterId;/** 毫秒内序列(0~4095) */private long sequence 0L;/** 上次生成ID的时间截 */private long lastTimestamp -1L;//Constructors/*** 构造函数* param workerId 工作ID (0~31)* param datacenterId 数据中心ID (0~31)*/public SnowflakeIdWorker(long workerId, long datacenterId) {if (workerId maxWorkerId || workerId 0) {throw new IllegalArgumentException(String.format(worker Id cant be greater than %d or less than 0, maxWorkerId));}if (datacenterId maxDatacenterId || datacenterId 0) {throw new IllegalArgumentException(String.format(datacenter Id cant be greater than %d or less than 0, maxDatacenterId));}this.workerId workerId;this.datacenterId datacenterId;}// Methods/*** 获得下一个ID (该方法是线程安全的)* return SnowflakeId*/public synchronized long nextId() {long timestamp timeGen();//如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常if (timestamp lastTimestamp) {throw new RuntimeException(String.format(Clock moved backwards. Refusing to generate id for %d milliseconds, lastTimestamp - timestamp));}//如果是同一时间生成的则进行毫秒内序列if (lastTimestamp timestamp) {sequence (sequence 1) sequenceMask;//毫秒内序列溢出if (sequence 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp tilNextMillis(lastTimestamp);}}//时间戳改变毫秒内序列重置else {sequence 0L;}//上次生成ID的时间截lastTimestamp timestamp;//移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) timestampLeftShift) //| (datacenterId datacenterIdShift) //| (workerId workerIdShift) //| sequence;}/*** 阻塞到下一个毫秒直到获得新的时间戳* param lastTimestamp 上次生成ID的时间截* return 当前时间戳*/protected long tilNextMillis(long lastTimestamp) {long timestamp timeGen();while (timestamp lastTimestamp) {timestamp timeGen();}return timestamp;}/*** 返回以毫秒为单位的当前时间* return 当前时间(毫秒)*/protected long timeGen() {return System.currentTimeMillis();}//Test/** 测试 */public static void main(String[] args) throws InterruptedException {SnowflakeIdWorker idWorker new SnowflakeIdWorker(0, 0);for (int i 0; i 100; i) {long id idWorker.nextId();//System.out.println(Long.toBinaryString(id));Thread.sleep(1);System.out.println(id);}} } 分布式调度问题 单机定式任务调度的问题 在很多应用系统中我们常常要定时执行一些任务。比如订单系统的超时状态判断、缓存数据的定时更新、定式给用户发邮件甚至是一些定期计算的报表等等。常见的处理方式有线程的while(true) 和sleep组合、使用Timer定时器触发任务又或者是使用quartz框架。貌似这些方法可以完美的解决方案为什么还需要分布式呢主要有如下两点原因 1.高可用单机版的定式任务调度只能在一台机器上运行如果程序或者系统出现异常就会导致功能不可用。虽然可以在单机程序实现的足够稳定但始终有机会遇到非程序引起的故障而这个对于一个系统的核心功能来说是不可接受的。 2.单机处理极限原本1分钟内需要处理1万个订单但是现在需要1分钟内处理10万个订单原来一个统计需要1小时现在业务方需要10分钟就统计出来。你也许会说你也可以多线程、单机多进程处理。的确多线程并行处理可以提高单位时间的处理效率但是单机能力毕竟有限主要是CPU、内存和磁盘始终会有单机处理不过来的情况。 这个时候就需要分布式的定时任务来实现了。业内常用的分布式定式任务解决方案主要有quartz、淘宝的TBSchedule和当当的elastic-job。 quartz的集群解决方案 quartz的单机版本大家应该比较熟悉它的集群方案是使用数据库来实现的。集群架构如下 上图三个节点在数据库中都拥有同一份Job定义如果某一个节点失效那么Job会在其他节点上执行。由于三个节点上的Job执行代码是一样的那么怎么保证只有在一台机器上触发呢答案是使用了数据库锁。在quartz的集群解决方案里有张表scheduler_locksquartz采用了悲观锁的方式对triggers表进行行加锁以保证任务同步的正确性。一旦某一个节点上面的线程获取了该锁那么这个Job就会在这台机器上被执行同时这个锁就会被这台机器占用。同时另外一台机器也会想要触发这个任务但是锁已经被占用了就只能等待直到这个锁被释放。之后会看trigger状态如果已经被执行了则不会执行了。 简单地说,quartz的分布式调度策略是以数据库为边界资源的一种异步策略。各个调度器都遵守一个基于数据库锁的操作规则从而保证了操作的唯一性。同时多个节点的异步运行保证了服务的可靠。但这种策略有自己的局限性集群特性对于高CPU使用率的任务效果很好但是对于大量的短任务各个节点都会抢占数据库锁这样就出现大量的线程等待资源。这种情况随着节点的增加会越来越严重。 另外quartz的分布式只是解决了高可用的问题并没有解决任务分片的问题还是会有单机处理的极限。 TBSchedule TBSchedule是一款非常优秀的高性能分布式调度框架广泛应用于阿里巴巴、淘宝、支付宝、京东、聚美、汽车之家、国美等很多互联网企业的流程调度系统。tbschedule在时间调度方面虽然没有quartz强大但是它支持分片功能。和quartz不同的是tbschedule使用ZooKeeper来实现任务调度的高可用和分片。 TBSchedule的分布式机制是通过灵活的Sharding方式实现的分片的规则由客户端决定比如可以按所有数据的ID按10取模分片、按月份分片等等。TBSchedule的宿主服务器可以进行动态扩容和资源回收这个特点主要是因为它后端依赖的ZooKeeper这里的ZooKeeper对于TBSchedule来说是一个NoSQL用于存储策略、任务、心跳信息数据它的数据结构类似文件系统的目录结构它的节点有临时节点、持久节点之分。调度引擎启动后随着业务量数据量的增多当前Cluster可能不能满足目前的处理需求那么就需要增加服务器数量一个新的服务器上线后会在ZooKeeper中创建一个代表当前服务器的一个唯一性路径临时节点并且新上线的服务器会和ZooKeeper保持长连接当通信断开后节点会自动摘除。 TBSchedule会定时扫描当前服务器的数量重新进行任务分配。TBSchedule不仅提供了服务端的高性能调度服务还提供了一个scheduleConsole的war包随着宿主应用的部署直接部署到服务器可以通过web的方式对调度的任务、策略进行监控管理以及实时更新调整。 elastic-job Elastic-Job当当开源的分布式调度解决方案由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。Elastic-Job-Lite定位为轻量级无中心化解决方案使用jar包的形式提供分布式任务的协调服务。一般我们只要使用Elastic-Job-Lite就好。 Elastic-Job-Lite并没有宿主程序而是基于部署作业框架的程序在到达相应时间点时各自触发调度。它的开发也比较简单引用Jar包实现一些方法即可最后编译成Jar包运行。Elastic-Job-Lite的分布式部署全靠ZooKeeper来同步状态和原数据。实现高可用的任务只需将分片总数设置为1并把开发的Jar包部署于多个服务器上执行任务将会以1主N从的方式执行。一旦本次执行任务的服务器崩溃其他执行任务的服务器将会在下次作业启动时选择一个替补执行。如果开启了失效转移那么功能效果更好可以保证在本次作业执行时崩溃备机之一立即启动替补执行。 Elastic-Job-Lite的任务分片也是通过ZooKeeper来实现Elastic-Job并不直接提供数据处理的功能框架只会将分片项分配至各个运行中的作业服务器开发者需要自行处理分片项与真实数据的对应关系。框架也预置了一些分片策略平均分配算法策略作业名哈希值奇偶数算法策略轮转分片策略。同时也提供了自定义分片策略的接口。 另外Elastic-Job-Lite还提供了一个任务监控和管理界面Elastic-Job-Lite-Console。它和Elastic-Job-Lite是两个完全不关联的应用程序使用ZooKeeper来交换数据管理人员可以通过这个界面查看、监控和管理Elastic-Job-Lite的任务必要的时候还能手动触发任务。 elastic-job结合了quartz非常优秀的时间调度功能并且利用ZooKeeper实现了灵活的分片策略。除此之外还加入了大量实用的监控和管理功能以及其开源社区活跃、文档齐全、代码优雅等优点是分布式任务调度框架的推荐选择。 Saturn Saturn是唯品会在github开源的一款分布式任务调度产品。它是基于当当elastic-job来开发的其上完善了一些功能和添加了一些新的feature。目前在github上开源大半年470个star。Saturn的任务可以用多种语言开发比如python、Go、Shell、Java、Php。其在唯品会内部已经发部署350个节点每天任务调度4000多万次。同时管理和统计也是它的亮点。 Session共享(一致性)问题 什么是Session ​ session 是一种服务端的会话机制。被称为域对象作为范围是一次会话的范围。 ​ 服务器为每个用户创建一个会话存储用户的相关信息以便多次请求能够定位到同一个上下文。这样当用户在应用程序的 Web 页之间跳转时存储在 Session 对象中的变量将不会丢失而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时如果该用户还没有会话则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后服务器将终止该会话。 ​ Web开发中web-server可以自动为同一个浏览器的访问用户自动创建session提供数据存储功能。最常见的会把用户的登录信息、用户信息存储在session中以保持登录状态。 那么Session为什么会不一致呢? ​ 在基于请求与响应的HTTP通讯中当第一次请求来时服务器端会接受到客户端请求会创建一个session使用响应头返回sessionid给客户端。浏览器获取到sessionid后会保存到本地cookie中。 第一次请求 ​ 当第二次请求来时客户端会读取本地的sessionid存放在请求头中服务端在请求头中获取对象的sessionid在本地session内存中查询。 第二次请求 // 默认创建一个session默认值为true如果没有找到对象的session对象就会创建该对象并且将生成的sessionid 存入到响应头中。 HttpSession session request.getSession();Overridepublic HttpSession getSession() {if (request null) {throw new IllegalStateException(sm.getString(requestFacade.nullRequest));}return getSession(true);} // 默认情况下就是true如果session不存在则创建一个存入到本地 // 假设修改为false会是什么样子的呢就会关闭session功能。但是session属于会话机制当当先会话结束时session就会被销毁并且web程序会为每一次不同的会话创建不同的session所以在分布式场景下即使是调用同一个方法执行同样的代码但是他们的服务器不同自然web程序不同整个上下文对象也不同理所当然session也是不同的。 分布式Session的诞生 ​ 单服务器web应用中session信息只需存在该服务器中这是我们前几年最常接触的方式但是近几年随着分布式系统的流行单系统已经不能满足日益增长的百万级用户的需求集群方式部署服务器已在很多公司运用起来当高并发量的请求到达服务端的时候通过负载均衡的方式分发到集群中的某个服务器这样就有可能导致同一个用户的多次请求被分发到集群的不同服务器上就会出现取不到session数据的情况于是session的共享就成了一个问题。 session一致性问题的产生 如上图假设用户包含登录信息的session都记录在第一台web-server上反向代理如果将请求路由到另一台web-server上可能就找不到相关信息而导致用户需要重新登录。 Session一致性解决方案 1.session复制同步Tomcat自带该功能 session复制 思路多个web-server 之间相互同步session这样每个web-server之间都包含全部的session 优点web-server 支持的功能应用程序不需要修改代码 不足 session 的同步需要数据传输占内网带宽有时延所有web-server 都包含所有session数据数据量受内存限制无法水平扩展有更多web-server 时要歇菜 2.客户端存储法 思路服务端存储所有用户的session内存占用较大可以将session存储到浏览器cookie中每个端只要存储一个用户的数据了 优点服务端不需要存储 缺点 每次http请求都携带session占外网带宽数据存储在端上并在网络传输存在泄漏、篡改、窃取等安全隐患session存储的数据大小受cookie限制 这种方式虽然不是很常用但也可行。 3.反向代理hash一致性 思路web-server为了保证高可用有多台冗余反向代理层能不能做一些事情让同一个用户的请求保证落在一台web-server 上呢 使用Nginx的负载均衡算法其中的hash_ip算法将ip固定到某一台服务器上这样就不会出现session共享问题因为同一个ip访问下永远是同一个服务器。 缺点失去了Nginx负载均衡的初心。 优点 只需要改nginx配置不需要修改应用代码负载均衡只要hash 属性是均匀的多台web-server的负载是均衡的可以支持web-server水平扩展session 同步法是不行的受内存限制 不足 如果web-server重启一部分session会丢失产生业务影响例如部分用户重新登录如果web-server水平扩展rehash后session重新分布也会有一部分用户路由不到正确的session。 4.后端统一集中存储 将Session存储到数据库或者Redis中 思路将session存储在web-server后端的存储层数据库或者缓存 优点 没有安全隐患可以水平扩展数据库/缓存水平切分即可web-server重启或者扩容都不会有session丢失 不足增加了一次网络调用并且需要修改应用代码 对于db存储还是cache个人推荐后者session读取的频率会很高数据库压力会比较大。如果有session高可用需求cache可以做高可用但大部分情况下session可以丢失一般也不需要考虑高可用。 方案使用Spring Session框架相当于将Session之缓存到Redis中。 问在项目发布的时候Session如何控制不会失效的? 答使用缓存框架缓存Session的值这里可以使用Redis加上EhCache实现一级和危机缓存 5.使用Token的方式代替Session功能 ​ 在移动端是没有Session这个概念的都是使用Token的方式来实现的。 token最终会存放到Redis中redis-cluster分片集群中是默认支持分布式共享的。完美的解决的共享问题。 推荐使用 4、5方式。 使用Spring Session实现Session一致性 ​ Spring Session 可以零侵入的解决Session一致性的问题。 Spring-Session实现Session共享实现原理以及源码解析 实现原理这里简单说明描述 就是当Web服务器接收到http请求后当请求进入对应的Filter进行过滤将原本需要由web服务器创建会话的过程转交给Spring-Session进行创建本来创建的会话保存在Web服务器内存中通过Spring-Session创建的会话信息可以保存第三方的服务中如redis,mysql等。Web服务器之间通过连接第三方服务来共享数据实现Session共享 /*** 配置redis服务器连接** author by Assume* date 2019/3/30 20:19*/ EnableRedisHttpSession(maxInactiveIntervalInSeconds 1800)//单位秒 public class SessionConfig {Value(${redis.hostname})private String hostName;Value(${redis.port})private int port;Value(${redis.password})private String password;Beanpublic JedisConnectionFactory connectionFactory() {JedisConnectionFactory connectionFactory new JedisConnectionFactory();connectionFactory.setPort(port);connectionFactory.setHostName(hostName);connectionFactory.setPassword(password);return connectionFactory;} }/*** 初始化Session配置** author by Assume* date 2019/3/30 20:30*/ public class SessionInitializer extends AbstractHttpSessionApplicationInitializer {public SessionInitializer() {super(SessionConfig.class);} }最靠谱的分布式Session解决方案 基于令牌Token方式实现Session解决方案因为Session本身就是分布式共享连接。 将生成的Token 存入到Redis中。 引用博客地址 https://www.jianshu.com/p/b889f9a49fec https://blog.csdn.net/m0_37041378/article/details/78125747# https://blog.csdn.net/e3hhhh/article/details/100186554 https://www.cnblogs.com/lpfuture/p/5796398.html
http://www.zqtcl.cn/news/319256/

相关文章:

  • 网站上的中英文切换是怎么做的大连网站制作优选ls15227
  • 网站开发工作安排广告设计公司有哪些
  • 无人机公司网站建设用什么软件做网站最简单
  • 企业微信app下载安装电脑版淄博网站优化价格
  • 做一个电影网站需要多少钱在线代理服务器网站
  • 怎样制作微信网站办网络宽带多少钱
  • ios开发者账号有什么用嘉兴网站关键词优化
  • 怎样在外贸网站做业务简付后wordpress
  • html网页制作源代码成品长沙 网站优化
  • 长沙做网站哪里好百度招聘 网站开发
  • 创建网站服务器银川建设厅网站
  • 海口建设局网站代运营网站建设
  • 网站建设环境搭建心得体会微信开发者模式
  • 网站点击率多少正常落地页网站
  • 做淘宝店铺有哪些好的网站东莞网站制作建设收费
  • Wordpress 实名认证太原网站搜索优化
  • 大良网站建设dwxw网站可以自己做
  • 自己怎么建网站佛山哪家网站建设比较好
  • 长沙短视频制作公司广州网站优化注意事项
  • 北京西城网站建设公司蓬莱做网站价格
  • 网站镜像做排名网站托管工作室
  • 江苏省建设协会网站wordpress小说采集
  • 网站运行费用预算计算机学了出来干嘛
  • 什么网站上公司的评价最客观青州网站优化
  • 网站开发下载那个kk网龙岩
  • 网站页面统计代码是什么意思国外网站模板欣赏
  • 徐州社交网站传奇做网站空间
  • 网站服务器租赁怎样用ps做网站的效果图
  • 温州网站建设制作苏州做网站费用
  • 山东网站建设和游戏开发的公司排名网站开发工程师待遇淄博