日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Cluster模式潜在问题及解决方案、Web服务综合解决方案

發(fā)布時(shí)間:2024/4/19 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cluster模式潜在问题及解决方案、Web服务综合解决方案 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

會(huì)不斷更新!沖沖沖!跳轉(zhuǎn)連接

https://blog.csdn.net/qq_35349982/category_10317485.html

Cluster模式潛在問(wèn)題及解決方案、Web服務(wù)綜合解決方案

1.一致性的哈希算法

1.1分布式與集群

分布式和集群是不?樣的,分布式?定是集群,但是集群不?定是分布式

1.2Hash算法

1.1 順序查找法

list:List[1,5,7,6,3,4,8] // 通過(guò)循環(huán)判斷來(lái)實(shí)現(xiàn) for(int element: list) { if(element == n) { 如果相等,說(shuō)明n存在于數(shù)據(jù)集中 }}

1.2?分查找法

1.3 直接尋址法

定義?個(gè)數(shù)組,數(shù)組?度?于等于數(shù)據(jù)集?度,此處?度為9,數(shù)據(jù)1就存儲(chǔ)在下標(biāo)為1的位置3就存儲(chǔ)在下標(biāo)為3的元素位置,,,依次類推。

這個(gè)時(shí)候,我想看下5存在與否,只需要判斷l(xiāng)ist.get(5) array[5] 是否為空,如果為空,代表5不存在于數(shù)據(jù)集,如果不為空代表5在數(shù)據(jù)集當(dāng)中,通過(guò)?次查找就達(dá)到了?的,時(shí)間復(fù)雜度為O(1)。這種?式叫做“直接尋址法”:

1.4 開(kāi)放尋址法 | 拉鏈法

1.3?致性Hash算法

?先有?條直線,直線開(kāi)頭和結(jié)尾分別定為為1和2的32次?減1,這相當(dāng)于?個(gè)地址,對(duì)于這樣?條線,彎過(guò)來(lái)構(gòu)成?個(gè)圓環(huán)形成閉環(huán),這樣的?個(gè)圓環(huán)稱為hash環(huán)。

紅節(jié)點(diǎn) —服務(wù)器節(jié)點(diǎn)

綠人像 —請(qǐng)求訪問(wèn)

每?臺(tái)服務(wù)器負(fù)責(zé)?段,?致性哈希算法對(duì)于節(jié)點(diǎn)的增減都只需重定位環(huán)空間中的??部分?jǐn)?shù)據(jù),具有較好的容錯(cuò)性和可擴(kuò)展性。

但是,?致性哈希算法在服務(wù)節(jié)點(diǎn)太少時(shí),容易因?yàn)楣?jié)點(diǎn)分部不均勻?造成數(shù)據(jù)傾斜問(wèn)題。

例如系統(tǒng)中只有兩臺(tái)服務(wù)器,其環(huán)分布如下,節(jié)點(diǎn)2只能負(fù)責(zé)?常?的?段,?量的客戶端請(qǐng)求落在了節(jié)點(diǎn)1上,這就是數(shù)據(jù)(請(qǐng)求)傾斜問(wèn)題

解決方案:?致性哈希算法引?了虛擬節(jié)點(diǎn)機(jī)制,即對(duì)每?個(gè)服務(wù)節(jié)點(diǎn)計(jì)算多個(gè)哈希,每個(gè)計(jì)算結(jié)果位置都放置?個(gè)此服務(wù)節(jié)點(diǎn),稱為虛擬節(jié)點(diǎn)。

1.4手寫(xiě)Hash算法

1.流程口述

  • 聲明服務(wù)器的節(jié)點(diǎn),計(jì)算hashCode然后存到SortedMap(上圈)中,(為解決數(shù)據(jù)傾斜問(wèn)題,增加虛擬節(jié)點(diǎn))
  • 聲明客戶端的節(jié)點(diǎn)
  • 請(qǐng)求到來(lái)時(shí):那客戶端的ip的hashCode值去服務(wù)器節(jié)點(diǎn)中訪問(wèn),有則取,沒(méi)有則取第一個(gè)
  • SortedMap<Integer, String> integerStringSortedMap = hashServerMap.tailMap(clientHash);

    2.代碼

    import java.util.SortedMap; import java.util.TreeMap; import java.util.UUID;public class ConsistentHashWithVirtual {public static void main(String[] args) {//step1 初始化:把服務(wù)器節(jié)點(diǎn)IP的哈希值對(duì)應(yīng)到哈希環(huán)上// 定義服務(wù)器ipString[] tomcatServers = new String[]{"123.111.0.0","123.101.3.1","111.20.35.2","123.98.26.3"};SortedMap<Integer,String> hashServerMap = new TreeMap<>();// 定義針對(duì)每個(gè)真實(shí)服務(wù)器虛擬出來(lái)幾個(gè)節(jié)點(diǎn)int virtaulCount = 3;for(String tomcatServer: tomcatServers) {// 求出每一個(gè)ip的hash值,對(duì)應(yīng)到hash環(huán)上,存儲(chǔ)hash值與ip的對(duì)應(yīng)關(guān)系int serverHash = Math.abs(tomcatServer.hashCode());// 存儲(chǔ)hash值與ip的對(duì)應(yīng)關(guān)系hashServerMap.put(serverHash,tomcatServer);// 處理虛擬節(jié)點(diǎn)for(int i = 0; i < virtaulCount; i++) {int virtualHash = Math.abs((tomcatServer + "#" + i).hashCode());hashServerMap.put(virtualHash,"----由虛擬節(jié)點(diǎn)"+ i + "映射過(guò)來(lái)的請(qǐng)求:"+ tomcatServer);}}//step2 針對(duì)客戶端IP求出hash值// 定義客戶端IPString[] clients = new String[]{"10.78.12.3","113.25.63.1","126.12.3.8"};for(String client : clients) {int clientHash = Math.abs(client.hashCode());//step3 針對(duì)客戶端,找到能夠處理當(dāng)前客戶端請(qǐng)求的服務(wù)器(哈希環(huán)上順時(shí)針最近)// 根據(jù)客戶端ip的哈希值去找出哪一個(gè)服務(wù)器節(jié)點(diǎn)能夠處理()SortedMap<Integer, String> integerStringSortedMap = hashServerMap.tailMap(clientHash);if(integerStringSortedMap.isEmpty()) {// 取哈希環(huán)上的順時(shí)針第一臺(tái)服務(wù)器Integer firstKey = hashServerMap.firstKey();System.out.println("==========>>>>客戶端:" + client + " 被路由到服務(wù)器:" + hashServerMap.get(firstKey));}else{Integer firstKey = integerStringSortedMap.firstKey();System.out.println("==========>>>>客戶端:" + client + " 被路由到服務(wù)器:" + hashServerMap.get(firstKey));}}}}

    1.5nginx的負(fù)載均衡

    1.ip_hash的問(wèn)題

    Nginx的IP_hash策略可以在客戶端ip不變的情況下,將其發(fā)出的請(qǐng)求始終路由到同?個(gè)?標(biāo)服務(wù)器上,實(shí)現(xiàn)會(huì)話粘滯,避免處理session共享問(wèn)題

    如果沒(méi)有IP_hash策略,那么如何實(shí)現(xiàn)會(huì)話粘滯?

    可以維護(hù)?張映射表,存儲(chǔ)客戶端IP或者sessionid與具體?標(biāo)服務(wù)器的映射關(guān)系

    <ip,tomcat1>

    缺點(diǎn)

    1)那么,在客戶端很多的情況下,映射表?常?,浪費(fèi)內(nèi)存空間

    2)客戶端上下線,?標(biāo)服務(wù)器上下線,都會(huì)導(dǎo)致重新維護(hù)映射表,映射表維護(hù)成本很?

    2.ngx_http_upstream_consistent_hash模塊

    ngx_http_upstream_consistent_hash 模塊是?個(gè)負(fù)載均衡器,使??個(gè)內(nèi)部?致性hash算法來(lái)選擇合適的后端節(jié)點(diǎn)。

    下載地址: https://github.com/replay/ngx_http_consistent_hash

    配置策略

    consistent_hash $remote_addr:可以根據(jù)客戶端ip映射 consistent_hash $request_uri:根據(jù)客戶端請(qǐng)求的uri映射 consistent_hash $args:根據(jù)客戶端攜帶的參數(shù)進(jìn)?映

    安裝模塊

    ./configure —add-module=/root/ngx_http_consistent_hash-master make make install #負(fù)載均衡策略 upstream myServer{ #每個(gè)請(qǐng)求按照ip的hash結(jié)果分配,每?個(gè)客戶端的請(qǐng)求會(huì)固定分配到同?個(gè)?標(biāo)服務(wù)器處理,可以解決session問(wèn)題consistent_hash $request_uri;#weight代表權(quán)重,默認(rèn)每?個(gè)負(fù)載的服務(wù)器都為1,權(quán)重越?那么被分配的請(qǐng)求越多(?于服務(wù)器性能不均衡的場(chǎng)景)server 47.95.1.96:8080 weight=1;server 47.95.1.96:8081 weight=2; }proxy_pass http://myServer/;

    2.時(shí)鐘同步問(wèn)題

    1.場(chǎng)景

    一個(gè)電商系統(tǒng),三個(gè)服務(wù)器,三個(gè)訂單,因?yàn)闀r(shí)鐘不同步,造成三個(gè)系統(tǒng)的`訂單時(shí)間`不一致

    2.方案

    2.1訪問(wèn)授時(shí)中心

    #使? ntpdate ?絡(luò)時(shí)間同步命令ntpdate -u ntp.api.bz #從?個(gè)時(shí)間服務(wù)器同步時(shí)間

    2.2一個(gè)節(jié)點(diǎn)訪問(wèn),其他節(jié)點(diǎn)同步

    ?個(gè)服務(wù)器節(jié)點(diǎn)可以訪問(wèn)互聯(lián)?或者所有節(jié)點(diǎn)都不能夠訪問(wèn)互聯(lián)?

    一個(gè)節(jié)點(diǎn)訪問(wèn),其他節(jié)點(diǎn)同步

    ##修改/etc/ntp.conf?件

    #1.先讓一個(gè)節(jié)點(diǎn)同步授時(shí)中心 ntpdate -u ntp.api.bz #1、如果有 restrict default ignore,注釋掉它 #2、添加如下??內(nèi)容restrict 172.17.0.0 mask 255.255.255.0 nomodify notrap # 放開(kāi)局域?同步功能,172.17.0.0是你的局域??段server 127.127.1.0 # local clockfudge 127.127.1.0 stratum 10 #選擇一個(gè)主節(jié)點(diǎn) #3、重啟?效并配置ntpd服務(wù)開(kāi)機(jī)?啟動(dòng)service ntpd restartchkconfig ntpd on##其他節(jié)點(diǎn)同步ntpdate 172.17.0.17

    3.分布式ID解決?案

    3.1 UUID

    UUID 是指Universally Unique Identififier,翻譯為中?是通?唯?識(shí)別碼

    public class MyTest {public static void main(String[] args) {System.out.println(java.util.UUID.randomUUID().toString());} }

    3.2 獨(dú)?數(shù)據(jù)庫(kù)的?增ID

    場(chǎng)景:分表后兩張表公用一個(gè)獨(dú)立表的ID

    創(chuàng)建一張表

    -- ---------------------------- -- Table structure for DISTRIBUTE_ID -- ---------------------------- DROP TABLE IF EXISTS `DISTRIBUTE_ID`; CREATE TABLE `DISTRIBUTE_ID` (`id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '主鍵',`createtime` datetime DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into DISTRIBUTE_ID(createtime) values(NOW()); select LAST_INSERT_ID()

    缺點(diǎn):

  • 需要代碼連接到數(shù)據(jù)庫(kù)才能獲取到id,性能?法保障,

  • mysql數(shù)據(jù)庫(kù)實(shí)例掛掉了,那么就?法獲取分布式id了。

  • 3.3 SnowFlake 雪花算法

    3.4 借助Redis的Incr命令獲取全局唯?ID

    安裝redis后

  • 修改配置文件 redis.conf
  • 啟動(dòng)
  • #bind 1270.0.1注釋掉 protected-mode no #設(shè)置為no <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version> </dependency> Jedis jedis = new Jedis("127.0.0.1",6379); try {long id = jedis.incr("id");//定義的KEY 是IDSystem.out.println("從redis中獲取的分布式id為:" + id); } finally {if (null != jedis) {jedis.close();} }

    源碼:

    public Long incr(String key) {this.checkIsInMultiOrPipeline();//獲取鏈接this.client.incr(key); //獲取keyreturn this.client.getIntegerReply();} //======================================= //讀取 public long readLongCrLf() {byte[] buf = this.buf;this.ensureFill();boolean isNeg = buf[this.count] == 45;if (isNeg) {++this.count;}long value = 0L;while(true) {this.ensureFill();int b = buf[this.count++];if (b == 13) {this.ensureFill();if (buf[this.count++] != 10) {throw new JedisConnectionException("Unexpected character!");} else {return isNeg ? -value : value;}}value = value * 10L + (long)b - 48L;}}

    4.分布式任務(wù)調(diào)度

    4.1定時(shí)任務(wù)場(chǎng)景

    • 訂單審核,出庫(kù)
    • 訂單支付退款
    • 禮券同步
    • 物流信息推送
    • 短信推送
    • 日志監(jiān)控

    4.2什么是分布式任務(wù)調(diào)度

  • 在分布式集群環(huán)境下的調(diào)度任務(wù)(同一個(gè)定時(shí)任務(wù)部署多分,只執(zhí)行一個(gè)定時(shí)任務(wù))
  • 分布式調(diào)度->定時(shí)任務(wù)的分布式->定時(shí)任務(wù)拆分(把一個(gè)大任務(wù)拆分成切分,同時(shí)執(zhí)行)
  • 4.3定時(shí)任務(wù)與消息隊(duì)列的區(qū)別

    • 共同點(diǎn)

    • 異步處理

      比如 注冊(cè),下單時(shí)間

    • 應(yīng)用解耦

      不管定時(shí)任務(wù)作業(yè)還是MQ 都可以實(shí)現(xiàn)應(yīng)用解耦

    • 流量削峰

      任何作業(yè)和MQ都可以用來(lái)抗流量

    • 不同點(diǎn)

    • 定時(shí)任務(wù)作業(yè)時(shí)時(shí)間驅(qū)動(dòng),MQ是時(shí)間驅(qū)動(dòng)
    • 時(shí)間驅(qū)動(dòng)是不可替代的,比如說(shuō)金融系統(tǒng)是每日的利息結(jié)算,不是來(lái)一條做一條,還是批量時(shí)間去處理
    • 定時(shí)任務(wù)作業(yè)更傾向于批處理,MQ傾向于逐條處理

    4.4 Quartz定時(shí)

    <!--任務(wù)調(diào)度框架quartz--><!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version></dependency> public class QuartzMan {// 1、創(chuàng)建任務(wù)調(diào)度器(好比公交調(diào)度站)public static Scheduler createScheduler() throws SchedulerException {SchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();return scheduler;}// 2、創(chuàng)建一個(gè)任務(wù)(好比某一個(gè)公交車(chē)的出行)public static JobDetail createJob() {JobBuilder jobBuilder = JobBuilder.newJob(DemoJob.class); // TODO 自定義任務(wù)類jobBuilder.withIdentity("jobName","myJob");JobDetail jobDetail = jobBuilder.build();return jobDetail;}/*** 3、創(chuàng)建作業(yè)任務(wù)時(shí)間觸發(fā)器(類似于公交車(chē)出車(chē)時(shí)間表)* cron表達(dá)式由七個(gè)位置組成,空格分隔* 1、Seconds(秒) 0~59* 2、Minutes(分) 0~59* 3、Hours(小時(shí)) 0~23* 4、Day of Month(天)1~31,注意有的月份不足31天* 5、Month(月) 0~11,或者 JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC* 6、Day of Week(周) 1~7,1=SUN或者 SUN,MON,TUE,WEB,THU,FRI,SAT* 7、Year(年)1970~2099 可選項(xiàng)*示例:* 0 0 11 * * ? 每天的11點(diǎn)觸發(fā)執(zhí)行一次* 0 30 10 1 * ? 每月1號(hào)上午10點(diǎn)半觸發(fā)執(zhí)行一次*/public static Trigger createTrigger() {// 創(chuàng)建時(shí)間觸發(fā)器CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("triggerName","myTrigger").startNow().withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?")).build();return cronTrigger;}/*** main函數(shù)中開(kāi)啟定時(shí)任務(wù)* @param args*/public static void main(String[] args) throws SchedulerException {// 1、創(chuàng)建任務(wù)調(diào)度器(好比公交調(diào)度站)Scheduler scheduler = QuartzMan.createScheduler();// 2、創(chuàng)建一個(gè)任務(wù)(好比某一個(gè)公交車(chē)的出行)JobDetail job = QuartzMan.createJob();// 3、創(chuàng)建任務(wù)的時(shí)間觸發(fā)器(好比這個(gè)公交車(chē)的出行時(shí)間表)Trigger trigger = QuartzMan.createTrigger();// 4、使用任務(wù)調(diào)度器根據(jù)時(shí)間觸發(fā)器執(zhí)行我們的任務(wù)scheduler.scheduleJob(job,trigger);scheduler.start();} }

    4.5 Elastic-job

    github地址:https://github.com/elasticjob

    1.主要功能

    • 分布式環(huán)境下,能夠避免同一個(gè)任務(wù)多實(shí)例重復(fù)執(zhí)行
    • 彈性擴(kuò)容縮容,當(dāng)集群中增加某一個(gè)實(shí)例,它能被選舉且執(zhí)行任務(wù),減少一個(gè)實(shí)例,任務(wù)自動(dòng)分配給其他實(shí)例
    • 任務(wù)失敗時(shí),轉(zhuǎn)移給其他實(shí)例
    • 自動(dòng)記錄錯(cuò)過(guò)執(zhí)行的作業(yè)
    • 支持并行調(diào)度,支持任務(wù)分片
    • 作業(yè)分片后,能后保證同一分片在分布式環(huán)境中僅執(zhí)行一個(gè)

    2.代碼執(zhí)行實(shí)例

    • 分片 ====>shardingItemParameters(“0=bachelor,1=master,2=doctor”)
    • 把一個(gè)任務(wù)分成多個(gè)task,每一個(gè)task交給一個(gè)具體的一個(gè)機(jī)器實(shí)例去處理
    • Strategy策略定義這些分片項(xiàng)怎么去分配到機(jī)器,默認(rèn)是平均分,分片和作業(yè)是通過(guò)一個(gè)注冊(cè)中心協(xié)調(diào)的
    • 擴(kuò)容
  • 分?項(xiàng)也是?個(gè)JOB配置,修改配置,重新分?,在下?次定時(shí)運(yùn)?之前會(huì)重新調(diào)?分?算法,那么這個(gè)分?算法的結(jié)果就是:哪臺(tái)機(jī)器運(yùn)?哪?個(gè)??,這個(gè)結(jié)果存儲(chǔ)到zk中的,主節(jié)點(diǎn)會(huì)把分?給分好放到注冊(cè)中?去,然后執(zhí)?節(jié)點(diǎn)從注冊(cè)中?獲取信息(執(zhí)?節(jié)點(diǎn)在定時(shí)任務(wù)開(kāi)啟的時(shí)候獲取相應(yīng)的分?)
  • 高可用,其他節(jié)點(diǎn)全部掛點(diǎn)了,剩下一個(gè)節(jié)點(diǎn),則所有的節(jié)點(diǎn)都指向這個(gè)節(jié)點(diǎn)
  • <!-- https://mvnrepository.com/artifact/com.dangdang/elastic-job-lite-core --><!--elastic-job-lite核心包--><dependency><groupId>com.dangdang</groupId><artifactId>elastic-job-lite-core</artifactId><version>2.1.5</version></dependency> //任務(wù)調(diào)度類 public static void main(String[] args) {// 配置分布式協(xié)調(diào)服務(wù)(注冊(cè)中心)ZookeeperZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("localhost:2181","data-archive-job");CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);//初始化coordinatorRegistryCenter.init();// 配置任務(wù)(時(shí)間事件、定時(shí)任務(wù)業(yè)務(wù)邏輯、調(diào)度器)JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration.newBuilder("archive-job", "*/2 * * * * ?", 3).shardingItemParameters("0=bachelor,1=master,2=doctor").build();SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,ArchivieJob.class.getName());//任務(wù)初始化//1.配置任分布式協(xié)調(diào)中心//2.配置任務(wù),執(zhí)行的任務(wù)類,定時(shí)時(shí)間JobScheduler jobScheduler = new JobScheduler(coordinatorRegistryCenter, LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build());jobScheduler.init();} /*** ElasticJobLite定時(shí)任務(wù)業(yè)務(wù)邏輯處理類*/ public class ArchivieJob implements SimpleJob {/*** 需求:resume表中未歸檔的數(shù)據(jù)歸檔到resume_bak表中,每次歸檔1條記錄* execute方法中寫(xiě)我們的業(yè)務(wù)邏輯(execute方法每次定時(shí)任務(wù)執(zhí)行都會(huì)執(zhí)行一次)* @param shardingContext*/@Overridepublic void execute(ShardingContext shardingContext) {int shardingItem = shardingContext.getShardingItem();System.out.println("=====>>>>當(dāng)前分片:" + shardingItem);// 獲取分片參數(shù)String shardingParameter = shardingContext.getShardingParameter(); // 0=bachelor,1=master,2=doctor// 1 從resume表中查詢出1條記錄(未歸檔)String selectSql = "select * from resume where state='未歸檔' and education='"+ shardingParameter +"' limit 1";List<Map<String, Object>> list = JdbcUtil.executeQuery(selectSql);if(list == null || list.size() ==0 ) {System.out.println("數(shù)據(jù)已經(jīng)處理完畢!!!!!!");return;}// 2 "未歸檔"更改為"已歸檔"Map<String, Object> stringObjectMap = list.get(0);long id = (long) stringObjectMap.get("id");String name = (String) stringObjectMap.get("name");String education = (String) stringObjectMap.get("education");System.out.println("=======>>>>id:" + id + " name:" + name + " education:" + education);String updateSql = "update resume set state='已歸檔' where id=?";JdbcUtil.executeUpdate(updateSql,id);// 3 歸檔這條記錄,把這條記錄插入到resume_bak表String insertSql = "insert into resume_bak select * from resume where id=?";JdbcUtil.executeUpdate(insertSql,id);} }

    分布式的理解

    5.Session的共享

    5.1 Session問(wèn)題原因分析

    Http是無(wú)狀態(tài)協(xié)議

    兩種用于保持Http狀態(tài)的技術(shù),那就是Cookie和Session

    JSESSIONID是一個(gè)Cookie,Servlet容器(tomcat,jetty)用來(lái)記錄用戶session

    5.2 Session一致性的解決方案

  • nginx的ip_hash策略
  • 同?個(gè)客戶端IP的請(qǐng)求都會(huì)被路由到同?個(gè)?標(biāo)服務(wù)器,也叫做會(huì)話粘滯

    • 優(yōu)點(diǎn):

    配置簡(jiǎn)單,不?侵應(yīng)?,不需要額外修改代碼

    • 缺點(diǎn):

    服務(wù)器重啟Session丟失

    存在單點(diǎn)負(fù)載?的?險(xiǎn)

    單點(diǎn)故障問(wèn)題

  • Session復(fù)制(不推薦)多個(gè)tomcat之間通過(guò)修改配置?件,達(dá)到Session之間的復(fù)制

  • Session共享(交代redis)

  • 優(yōu)點(diǎn):

    • 能適應(yīng)各種負(fù)載均衡策略
    • 服務(wù)器重啟或者當(dāng)即不會(huì)造成Session丟失
    • 擴(kuò)展能力強(qiáng)
    • 適合大集群數(shù)量使用

    缺點(diǎn)

    • 對(duì)應(yīng)用有侵入性

    5.3代碼實(shí)現(xiàn)(Session共享)

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency> spring.redis.database=0 spring.redis.host=127.0.0.1 spring.redis.port=6379 @SpringBootApplication @EnableCaching @EnableRedisHttpSession //加這個(gè)注解 public class LoginApplication extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(LoginApplication.class);}public static void main(String[] args) {SpringApplication.run(LoginApplication.class, args);}}

    5.4源碼刨析

  • 引入了RedisHttpSessionConfiguration類
  • 繼承了SpringHttpSessionConfiguration類
  • SessionRepositoryFilter類
  • //1.引入了RedisHttpSessionConfiguration類 @Import({RedisHttpSessionConfiguration.class}) public @interface EnableRedisHttpSession { } //=========================== //2.繼承了SpringHttpSessionConfiguration類 public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration {} //=========================== //3.SessionRepositoryFilter類 public class SpringHttpSessionConfiguration{@Beanpublic <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter(sessionRepository);sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);return sessionRepositoryFilter;} } //protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryFilter.SessionRepositoryRequestWrapper(request, response);SessionRepositoryFilter.SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryFilter.SessionRepositoryResponseWrapper(wrappedRequest, response);try {filterChain.doFilter(wrappedRequest, wrappedResponse);} finally {wrappedRequest.commitSession();//redis提交}} //redis提交private void commitSession() {SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper.HttpSessionWrapper wrappedSession = this.getCurrentSession();if (wrappedSession == null) {if (this.isInvalidateClientSession()) {SessionRepositoryFilter.this.httpSessionIdResolver.expireSession(this, this.response);}} else {S session = wrappedSession.getSession();this.clearRequestedSessionCache();SessionRepositoryFilter.this.sessionRepository.save(session);String sessionId = session.getId();if (!this.isRequestedSessionIdValid() || !sessionId.equals(this.getRequestedSessionId())) {SessionRepositoryFilter.this.httpSessionIdResolver.setSessionId(this, this.response, sessionId);}}}

    附錄

    1.wrapper的概念

    實(shí)現(xiàn)Wrapper的類需要:

  • 實(shí)現(xiàn)某個(gè)接口
  • 依賴該接口的子類, 并通過(guò)接口方法訪問(wèn)子類對(duì)象的方法
  • public class MyArrays {public List<Point> asList(Point[] points) {List<Point> list = new ArrayList<Point>();for (int i = 0; i < points.length; i++) {list.add(points[i]);}return new ArrayListWrapper(list);} }class ArrayListWrapper implements List<Point> {private List<Point> list;ArrayListWrapper(List<Point> list) {this.list = list;}@Overridepublic int size() {return list.size();}@Overridepublic boolean add(Point e) {throw new UnsupportedOperationException("...");}@Overridepublic boolean remove(Object o) {throw new UnsupportedOperationException("...");} …………………………}

    單詞

    Cluster 群,集群

    strict 嚴(yán)格

    stratum 層

    ensure 保證
    Coordinator協(xié)調(diào),班主任

    elastic 彈性的

    總結(jié)

    以上是生活随笔為你收集整理的Cluster模式潜在问题及解决方案、Web服务综合解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。