普通的Web開發(fā),常用的模式就是用戶登錄之后,登錄狀態(tài)信息保存在Session中,用戶一些常用的熱數(shù)據(jù)保存在文件緩存中,用戶上傳的附件信息保存在Web服務(wù)器的某個(gè)目錄上。這種方式對(duì)于一般的Web應(yīng)用,使用很方便,完全能夠勝任。但是對(duì)于高并發(fā)的企業(yè)級(jí)網(wǎng)站,就應(yīng)付不了了。需要采用Web集群實(shí)現(xiàn)負(fù)載均衡。
創(chuàng)新互聯(lián)自2013年創(chuàng)立以來,先為蜀山等服務(wù)建站,蜀山等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為蜀山企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
使用Web集群方式部署之后,首要調(diào)整的就是用戶狀態(tài)信息與附件信息。用戶狀態(tài)不能再保存到Session中,緩存也不能用本地Web服務(wù)器的文件緩存,以及附件,也不能保存在Web服務(wù)器上了。因?yàn)橐WC集群里面的各個(gè)Web服務(wù)器,狀態(tài)完全一致。因此,需要將用戶狀態(tài)、緩存等保存到專用的緩存服務(wù)器,比如Memcache。附件需要保存到云存儲(chǔ)中。
Web負(fù)載均衡
Web負(fù)載均衡(Load Balancing),簡(jiǎn)單地說就是給我們的服務(wù)器集群分配“工作任務(wù)”,而采用恰當(dāng)?shù)姆峙浞绞剑瑢?duì)于保護(hù)處于后端的Web服務(wù)器來說,非常重要。
負(fù)載均衡的策略有很多,我們從簡(jiǎn)單的講起。?
1. HTTP重定向?
當(dāng)用戶發(fā)來請(qǐng)求的時(shí)候,Web服務(wù)器通過修改HTTP響應(yīng)頭中的Location標(biāo)記來返回一個(gè)新的url,然后瀏覽器再繼續(xù)請(qǐng)求這個(gè)新url,實(shí)際上就是頁面重定向。通過重定向,來達(dá)到“負(fù)載均衡”的目標(biāo)。
2. 反向代理負(fù)載均衡?
反向代理服務(wù)的核心工作主要是轉(zhuǎn)發(fā)HTTP請(qǐng)求,扮演了瀏覽器端和后臺(tái)Web服務(wù)器中轉(zhuǎn)的角色。因?yàn)樗ぷ髟贖TTP層(應(yīng)用層),也就是網(wǎng)絡(luò)七層結(jié)構(gòu)中的第七層,因此也被稱為“七層負(fù)載均衡”。可以做反向代理的軟件很多,比較常見的一種是Nginx。
Nginx是一種非常靈活的反向代理軟件,可以自由定制化轉(zhuǎn)發(fā)策略,分配服務(wù)器流量的權(quán)重等。反向代理中,常見的一個(gè)問題,就是Web服務(wù)器存儲(chǔ)的session數(shù)據(jù)。
3. IP負(fù)載均衡
IP負(fù)載均衡服務(wù)是工作在網(wǎng)絡(luò)層(修改IP)和傳輸層(修改端口,第四層),比起工作在應(yīng)用層(第七層)性能要高出非常多。原理是,他是對(duì)IP層的數(shù)據(jù)包的IP地址和端口信息進(jìn)行修改,達(dá)到負(fù)載均衡的目的。這種方式,也被稱為“四層負(fù)載均衡”。常見的負(fù)載均衡方式,是LVS(Linux Virtual Server,Linux虛擬服務(wù)),通過IPVS(IP Virtual Server,IP虛擬服務(wù))來實(shí)現(xiàn)。
當(dāng)前做分布式的廠商有幾家,我知道比較出名的有“華為云分布式數(shù)據(jù)庫DDM”和“阿里云分布式數(shù)據(jù)庫”,感興趣可以自行搜素了解下。
分布式數(shù)據(jù)庫的幾點(diǎn)概念可以了解一下。
數(shù)據(jù)分庫:
以表為單位,把原有數(shù)據(jù)庫切分成多個(gè)數(shù)據(jù)庫。切分后不同的表存儲(chǔ)在不同的數(shù)據(jù)庫上。
以表中的數(shù)據(jù)行記錄為單位,把原有邏輯數(shù)據(jù)庫切分成多個(gè)物理數(shù)據(jù)庫分片,表數(shù)據(jù)記錄分布存儲(chǔ)在各個(gè)分片上。
路由分發(fā):
在分布式數(shù)據(jù)庫中,路由的作用即將SQL語句進(jìn)行解析,并轉(zhuǎn)發(fā)到正確的分片上,保證SQL執(zhí)行后得到正確的結(jié)果,并且節(jié)約QPS資源。
讀寫分離:
數(shù)據(jù)庫中對(duì)計(jì)算和緩存資源消耗較多的往往是密集或復(fù)雜的SQL查詢。當(dāng)系統(tǒng)資源被查詢語句消耗,反過來會(huì)影響數(shù)據(jù)寫入操作,進(jìn)而導(dǎo)致數(shù)據(jù)庫整體性能下降,響應(yīng)緩慢。因此,當(dāng)數(shù)據(jù)庫CPU和內(nèi)存資源占用居高不下,且讀寫比例較高時(shí),可以為數(shù)據(jù)庫添加只讀數(shù)據(jù)庫。
memcached的總結(jié)和分布式一致性hash
當(dāng)前很多大型的web系統(tǒng)為了減輕數(shù)據(jù)庫服務(wù)器負(fù)載,會(huì)采用memchached作為緩存系統(tǒng)以提高響應(yīng)速度。
目錄: ()
memchached簡(jiǎn)介
hash
取模
一致性hash
虛擬節(jié)點(diǎn)
源碼解析
參考資料
1. memchached簡(jiǎn)介
memcached是一個(gè)開源的高性能分布式內(nèi)存對(duì)象緩存系統(tǒng)。
其實(shí)思想還是比較簡(jiǎn)單的,實(shí)現(xiàn)包括server端(memcached開源項(xiàng)目一般只單指server端)和client端兩部分:
server端本質(zhì)是一個(gè)in-memory key-value store,通過在內(nèi)存中維護(hù)一個(gè)大的hashmap用來存儲(chǔ)小塊的任意數(shù)據(jù),對(duì)外通過統(tǒng)一的簡(jiǎn)單接口(memcached protocol)來提供操作。
client端是一個(gè)library,負(fù)責(zé)處理memcached protocol的網(wǎng)絡(luò)通信細(xì)節(jié),與memcached server通信,針對(duì)各種語言的不同實(shí)現(xiàn)分裝了易用的API實(shí)現(xiàn)了與不同語言平臺(tái)的集成。
web系統(tǒng)則通過client庫來使用memcached進(jìn)行對(duì)象緩存。
2. hash
memcached的分布式主要體現(xiàn)在client端,對(duì)于server端,僅僅是部署多個(gè)memcached server組成集群,每個(gè)server獨(dú)自維護(hù)自己的數(shù)據(jù)(互相之間沒有任何通信),通過daemon監(jiān)聽端口等待client端的請(qǐng)求。
而在client端,通過一致的hash算法,將要存儲(chǔ)的數(shù)據(jù)分布到某個(gè)特定的server上進(jìn)行存儲(chǔ),后續(xù)讀取查詢使用同樣的hash算法即可定位。
client端可以采用各種hash算法來定位server:
取模
最簡(jiǎn)單的hash算法
targetServer = serverList[hash(key) % serverList.size]
直接用key的hash值(計(jì)算key的hash值的方法可以自由選擇,比如算法CRC32、MD5,甚至本地hash系統(tǒng),如java的hashcode)模上server總數(shù)來定位目標(biāo)server。這種算法不僅簡(jiǎn)單,而且具有不錯(cuò)的隨機(jī)分布特性。
但是問題也很明顯,server總數(shù)不能輕易變化。因?yàn)槿绻黾?減少memcached server的數(shù)量,對(duì)原先存儲(chǔ)的所有key的后續(xù)查詢都將定位到別的server上,導(dǎo)致所有的cache都不能被命中而失效。
一致性hash
為了解決這個(gè)問題,需要采用一致性hash算法(consistent hash)
相對(duì)于取模的算法,一致性hash算法除了計(jì)算key的hash值外,還會(huì)計(jì)算每個(gè)server對(duì)應(yīng)的hash值,然后將這些hash值映射到一個(gè)有限的值域上(比如0~2^32)。通過尋找hash值大于hash(key)的最小server作為存儲(chǔ)該key數(shù)據(jù)的目標(biāo)server。如果找不到,則直接把具有最小hash值的server作為目標(biāo)server。
為了方便理解,可以把這個(gè)有限值域理解成一個(gè)環(huán),值順時(shí)針遞增。
如上圖所示,集群中一共有5個(gè)memcached server,已通過server的hash值分布到環(huán)中。
如果現(xiàn)在有一個(gè)寫入cache的請(qǐng)求,首先計(jì)算x=hash(key),映射到環(huán)中,然后從x順時(shí)針查找,把找到的第一個(gè)server作為目標(biāo)server來存儲(chǔ)cache,如果超過了2^32仍然找不到,則命中第一個(gè)server。比如x的值介于A~B之間,那么命中的server節(jié)點(diǎn)應(yīng)該是B節(jié)點(diǎn)
可以看到,通過這種算法,對(duì)于同一個(gè)key,存儲(chǔ)和后續(xù)的查詢都會(huì)定位到同一個(gè)memcached server上。
那么它是怎么解決增/刪server導(dǎo)致的cache不能命中的問題呢?
假設(shè),現(xiàn)在增加一個(gè)server F,如下圖
此時(shí),cache不能命中的問題仍然存在,但是只存在于B~F之間的位置(由C變成了F),其他位置(包括F~C)的cache的命中不受影響(刪除server的情況類似)。盡管仍然有cache不能命中的存在,但是相對(duì)于取模的方式已經(jīng)大幅減少了不能命中的cache數(shù)量。
虛擬節(jié)點(diǎn)
但是,這種算法相對(duì)于取模方式也有一個(gè)缺陷:當(dāng)server數(shù)量很少時(shí),很可能他們?cè)诃h(huán)中的分布不是特別均勻,進(jìn)而導(dǎo)致cache不能均勻分布到所有的server上。
如圖,一共有3臺(tái)server – 1,2,4。命中4的幾率遠(yuǎn)遠(yuǎn)高于1和2。
為解決這個(gè)問題,需要使用虛擬節(jié)點(diǎn)的思想:為每個(gè)物理節(jié)點(diǎn)(server)在環(huán)上分配100~200個(gè)點(diǎn),這樣環(huán)上的節(jié)點(diǎn)較多,就能抑制分布不均勻。
當(dāng)為cache定位目標(biāo)server時(shí),如果定位到虛擬節(jié)點(diǎn)上,就表示cache真正的存儲(chǔ)位置是在該虛擬節(jié)點(diǎn)代表的實(shí)際物理server上。
另外,如果每個(gè)實(shí)際server的負(fù)載能力不同,可以賦予不同的權(quán)重,根據(jù)權(quán)重分配不同數(shù)量的虛擬節(jié)點(diǎn)。
// 采用有序map來模擬環(huán)
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5來計(jì)算key和server的hash值
// 計(jì)算總權(quán)重
if ( this.totalWeight for ( int i = 0; i this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 為每個(gè)server分配虛擬節(jié)點(diǎn)
for ( int i = 0; i servers.length; i++ ) {
// 計(jì)算當(dāng)前server的權(quán)重
int thisWeight = 1;
if ( this.weights != null this.weights[i] != null )
thisWeight = this.weights[i];
// factor用來控制每個(gè)server分配的虛擬節(jié)點(diǎn)數(shù)量
// 權(quán)重都相同時(shí),factor=40
// 權(quán)重不同時(shí),factor=40*server總數(shù)*該server權(quán)重所占的百分比
// 總的來說,權(quán)重越大,factor越大,可以分配越多的虛擬節(jié)點(diǎn)
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j factor; j++ ) {
// 每個(gè)server有factor個(gè)hash值
// 使用server的域名或IP加上編號(hào)來計(jì)算hash值
// 比如server - "172.45.155.25:11111"就有factor個(gè)數(shù)據(jù)用來生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每個(gè)hash值生成4個(gè)虛擬節(jié)點(diǎn)
for ( int h = 0 ; h 4; h++ ) {
Long k =
((long)(d[3+h*4]0xFF) 24)
| ((long)(d[2+h*4]0xFF) 16)
| ((long)(d[1+h*4]0xFF) 8 )
| ((long)(d[0+h*4]0xFF));
// 在環(huán)上保存節(jié)點(diǎn)
consistentBuckets.put( k, servers[i] );
}
}
// 每個(gè)server一共分配4*factor個(gè)虛擬節(jié)點(diǎn)
}
// 采用有序map來模擬環(huán)
this.consistentBuckets = new TreeMap();
MessageDigest md5 = MD5.get();//用MD5來計(jì)算key和server的hash值
// 計(jì)算總權(quán)重
if ( this.totalWeight for ( int i = 0; i this.weights.length; i++ )
this.totalWeight += ( this.weights[i] == null ) ? 1 : this.weights[i];
} else if ( this.weights == null ) {
this.totalWeight = this.servers.length;
}
// 為每個(gè)server分配虛擬節(jié)點(diǎn)
for ( int i = 0; i servers.length; i++ ) {
// 計(jì)算當(dāng)前server的權(quán)重
int thisWeight = 1;
if ( this.weights != null this.weights[i] != null )
thisWeight = this.weights[i];
// factor用來控制每個(gè)server分配的虛擬節(jié)點(diǎn)數(shù)量
// 權(quán)重都相同時(shí),factor=40
// 權(quán)重不同時(shí),factor=40*server總數(shù)*該server權(quán)重所占的百分比
// 總的來說,權(quán)重越大,factor越大,可以分配越多的虛擬節(jié)點(diǎn)
double factor = Math.floor( ((double)(40 * this.servers.length * thisWeight)) / (double)this.totalWeight );
for ( long j = 0; j factor; j++ ) {
// 每個(gè)server有factor個(gè)hash值
// 使用server的域名或IP加上編號(hào)來計(jì)算hash值
// 比如server - "172.45.155.25:11111"就有factor個(gè)數(shù)據(jù)用來生成hash值:
// 172.45.155.25:11111-1, 172.45.155.25:11111-2, ..., 172.45.155.25:11111-factor
byte[] d = md5.digest( ( servers[i] + "-" + j ).getBytes() );
// 每個(gè)hash值生成4個(gè)虛擬節(jié)點(diǎn)
for ( int h = 0 ; h 4; h++ ) {
Long k =
((long)(d[3+h*4]0xFF) 24)
| ((long)(d[2+h*4]0xFF) 16)
| ((long)(d[1+h*4]0xFF) 8 )
| ((long)(d[0+h*4]0xFF));
// 在環(huán)上保存節(jié)點(diǎn)
consistentBuckets.put( k, servers[i] );
}
}
// 每個(gè)server一共分配4*factor個(gè)虛擬節(jié)點(diǎn)
}
// 用MD5來計(jì)算key的hash值
MessageDigest md5 = MD5.get();
md5.reset();
md5.update( key.getBytes() );
byte[] bKey = md5.digest();
// 取MD5值的低32位作為key的hash值
long hv = ((long)(bKey[3]0xFF) 24) | ((long)(bKey[2]0xFF) 16) | ((long)(bKey[1]0xFF) 8 ) | (long)(bKey[0]0xFF);
// hv的tailMap的第一個(gè)虛擬節(jié)點(diǎn)對(duì)應(yīng)的即是目標(biāo)server
SortedMap tmap = this.consistentBuckets.tailMap( hv );
return ( tmap.isEmpty() ) ? this.consistentBuckets.firstKey() : tmap.firstKey();
更多問題到問題求助專區(qū)()
前邊介紹了負(fù)載均衡,mysql同步,接下來介紹tp6分布式部署多個(gè)數(shù)據(jù)庫,實(shí)現(xiàn)讀寫分離。
tp6的分布式部署讀和寫仍然是一個(gè)系統(tǒng),這里我們分開操作,給用戶展示的就是從數(shù)據(jù)庫,后端添加文章就是主庫,然后同步到從庫。
1、配置數(shù)據(jù)庫鏈接參數(shù)
目標(biāo):實(shí)現(xiàn)隨機(jī)使用數(shù)據(jù)庫展示信息,只是讀操作。
測(cè)試:前臺(tái)可以讀取表中內(nèi)容(存放的不一致),查看是否是隨機(jī)顯示的。
打開.env文件進(jìn)行編輯
說明:
2、編輯database.php
找到deploy設(shè)置為1分布式部署,下邊不要改,都是讀,寫入的也就是后端的我們單獨(dú)建站連接主庫。
配置完成,tp6使用的是mt_rand取隨機(jī)數(shù)判斷使用哪個(gè)數(shù)據(jù)庫。
3、數(shù)據(jù)庫交互寫操作
比如瀏覽量沒必要每次都去更新數(shù)據(jù)庫,可以先使用redis緩存,存夠1000的整數(shù)倍,再去更新數(shù)據(jù)庫。
4、后臺(tái)獨(dú)立,也就是寫
可以前后端分離,單獨(dú)做一個(gè)網(wǎng)站(沒有前端)使用ip訪問或者獨(dú)立的域名連接后臺(tái)。
5、上傳附件(jquery ajax跨域上傳)
使用了nginx負(fù)載均衡,肯定是多個(gè)一樣的網(wǎng)站,如果圖片存放到一個(gè)站,別的就不能訪問了,可以單獨(dú)設(shè)置一個(gè)附件(壓縮包,圖片等)服務(wù)器,可以使用二級(jí)域名連接,這就要求我們上傳附件的時(shí)候,是上傳到附件服務(wù)器。
jqueryURL
API控制器apdpic方法
說明:
也可以先傳到后臺(tái)服務(wù)器然后使用(php)ftp上傳,或者是通過curl上傳到附件服務(wù)器,感覺那樣畢竟麻煩,直接設(shè)置跨域會(huì)比較簡(jiǎn)單。
也測(cè)試了使用jsonp跨域,但是不能上傳附件。
6、thinkphp6實(shí)現(xiàn)讀寫分離(在一個(gè)站點(diǎn))
我個(gè)人是不喜歡這樣的,負(fù)載均衡應(yīng)該是均衡地讀,也就是前臺(tái)單獨(dú)一個(gè)站點(diǎn),后端的寫是另一個(gè)獨(dú)立的站點(diǎn),看個(gè)人喜好吧。
獨(dú)立后臺(tái)的優(yōu)點(diǎn):可以提升安全性,因?yàn)槲覀兊暮笈_(tái)網(wǎng)址是不公開的,避免用戶猜測(cè)一些后臺(tái)的信息。
.env配置按照1所述編輯,默認(rèn)第一個(gè)是主庫。
database.php
愿大家在新的一年心想事成,萬事如意!!!
網(wǎng)頁名稱:php實(shí)現(xiàn)分布式數(shù)據(jù)庫 php分布式存儲(chǔ)技術(shù)
網(wǎng)頁鏈接:http://www.chinadenli.net/article6/doogiog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷型網(wǎng)站建設(shè)、定制開發(fā)、響應(yīng)式網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)