中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站建設(shè)都包括哪些方面怎么做平臺(tái)推廣

網(wǎng)站建設(shè)都包括哪些方面,怎么做平臺(tái)推廣,最大的房產(chǎn)網(wǎng)站,網(wǎng)站建設(shè)如何運(yùn)營(yíng)JVM JVM是Java virtual machine(Java虛擬機(jī))的縮寫(xiě),是一種用于計(jì)算機(jī)的規(guī)范,是通過(guò)在實(shí)際計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。 主要組件構(gòu)成: 1.類(lèi)加載器 子系統(tǒng)負(fù)責(zé)從文件系統(tǒng)或者網(wǎng)絡(luò)中加載Class文件&…

JVM

JVM是Java virtual machine(Java虛擬機(jī))的縮寫(xiě),是一種用于計(jì)算機(jī)的規(guī)范,是通過(guò)在實(shí)際計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。

主要組件構(gòu)成:

1.類(lèi)加載器

子系統(tǒng)負(fù)責(zé)從文件系統(tǒng)或者網(wǎng)絡(luò)中加載Class文件,Class文件在文件開(kāi)頭有特定的文件標(biāo)識(shí),ClassLoader只負(fù)責(zé)加載Class文件,是否運(yùn)行取決于ExecutionEngine。

2.執(zhí)行引擎

執(zhí)行字節(jié)碼或者執(zhí)行本地方法

3.內(nèi)存管理系統(tǒng)

負(fù)責(zé)管理Java程序運(yùn)行時(shí)的內(nèi)存分配和回收,包括堆、方法區(qū)等。

4.即時(shí)編譯器

將頻繁執(zhí)行的字節(jié)碼轉(zhuǎn)換為本地機(jī)器代碼,以提高執(zhí)行效率。

5.運(yùn)行時(shí)數(shù)據(jù)區(qū)

包括方法區(qū)、堆、Java棧、程序計(jì)數(shù)器、本地方法棧。

jvm的內(nèi)存結(jié)構(gòu):堆內(nèi)存、方法區(qū)、棧

1.堆內(nèi)存(heap)

Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線(xiàn)程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。

2.方法區(qū)(Method Area)

方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線(xiàn)程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。

3、程序計(jì)數(shù)器(Program Counter Register)

程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼的行號(hào)指示器。

4、Java虛擬機(jī)棧(JVM Stacks)

Java虛擬機(jī)棧(Java Virtual Machine Stacks)也是線(xiàn)程私有的,它的生命周期與線(xiàn)程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程。

5、本地方法棧(Native Method Stacks)

本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。

JVM內(nèi)存分配機(jī)制

JVM內(nèi)存≈Heap(堆內(nèi)存)+PermGen(方法區(qū))+Thrend(棧) Heap(堆內(nèi)存)=Young(年輕代)+Old(老年代),官方文檔建議整個(gè)年輕代占整個(gè)堆內(nèi)存的3/8,老年代占整個(gè)堆內(nèi)存的5/8,但是可以配置為其他比例。 Young(年輕代)=EdenSpace+FromSurvivor+ToSurvivor,Eden區(qū)與兩個(gè)存活區(qū)的內(nèi)存大小比例是:8:1:1,同樣可以配置為其他比例。

java代碼如何被JVM執(zhí)行的?

java文件計(jì)算機(jī)是識(shí)別不了的,所以首先我們寫(xiě)的代碼需要從.java文件編譯為.class文件,.class是字節(jié)碼文件,里面都是一些字節(jié)碼指令,這樣的字節(jié)碼指令才是計(jì)算機(jī)可以識(shí)別的。

?JVM垃圾回收機(jī)制

?

1、new出來(lái)的對(duì)象先放在Eden區(qū),Eden區(qū)放滿(mǎn)后第一次觸發(fā)Young GC(垃圾回收),把存活對(duì)象移到S1存活區(qū)。

2、第二次Eden區(qū)又滿(mǎn)了,再次觸發(fā)Young GC,把Eden區(qū)的存活對(duì)象移到S2存活區(qū),把S1存活區(qū)的存活對(duì)象也移到S2存活區(qū),這時(shí)S1存活區(qū)清空了。

3、第三次Eden區(qū)又滿(mǎn)了,再次觸發(fā)Young GC,把Eden區(qū)的存活對(duì)象移到S1存活區(qū),把S2存活區(qū)的存活對(duì)象也移到S1存活區(qū),這時(shí)S2存活區(qū)清空了。

4、這樣S1和S2交替互換,輪流為清空,大大拉長(zhǎng)了存活對(duì)象進(jìn)入老年代的時(shí)間間隔。

類(lèi)對(duì)象什么時(shí)候進(jìn)入老年代:   

a、大對(duì)象直接進(jìn)入老年代:Eden區(qū)放不下直接進(jìn)入老年代   

b、長(zhǎng)期存活的對(duì)象進(jìn)入老年代:以Young GC次數(shù)進(jìn)行判斷的,默認(rèn)次數(shù)15次后進(jìn)入老年代  

c、執(zhí)行Young GC時(shí),存活區(qū)放不下時(shí),存活對(duì)象也直接進(jìn)入老年代

5、一直這樣循環(huán)往復(fù)直到老年代滿(mǎn)了,觸發(fā)Full GC。首先清除老年代中的沒(méi)有引用的對(duì)象,再對(duì)Eden區(qū)進(jìn)行GC,還會(huì)對(duì)持久代進(jìn)行GC(持久代一般沒(méi)什么可清理)

6、老年代里面放滿(mǎn)以后,執(zhí)行Full GC也釋放不了內(nèi)存空間,就會(huì)報(bào)內(nèi)存溢出的錯(cuò)誤了。

總結(jié):

1、Young GC只發(fā)生在Eden區(qū),Eden區(qū)是整個(gè)Java堆內(nèi)存分配的入口,new對(duì)象優(yōu)先分配到Eden區(qū),Eden區(qū)滿(mǎn)之后觸發(fā)Young GC

2、Young GC觸發(fā)后,然后它會(huì)判斷Eden區(qū)的對(duì)象是否是存活的,如果是存活的則放到存活區(qū),不是存活的則清除掉釋放內(nèi)存空間。

3、觸發(fā)Full GC是雖然也清理了Eden區(qū),但是Young GC次數(shù)不會(huì)+1,它是Full GC在干活。

什么時(shí)候觸發(fā)Full GC:   

a、老年代空間不足   

b、持久代空間不足的時(shí)候也會(huì)觸發(fā)Full GC   

c、顯示調(diào)用也可以觸發(fā)Full GC,比如說(shuō)RunTime.GC、System.GC   

d、RMI框架,會(huì)產(chǎn)生大量的對(duì)象,會(huì)進(jìn)行顯示調(diào)用,觸發(fā)Full GC   

e、Young GC時(shí)的悲觀策略dump live的內(nèi)存信息時(shí)(jmap-dump:live)

4、執(zhí)行Young GC和Full GC應(yīng)用程序的所有線(xiàn)程都是暫停的、停止工作,但Full GC時(shí)間比較長(zhǎng) 5、JVM調(diào)優(yōu)的核心思想:   

a、盡量減少Full GC的次數(shù),或者說(shuō)延長(zhǎng)Full GC間隔時(shí)間。不要頻繁觸發(fā)Full GC,因?yàn)閳?zhí)行Full GC的時(shí)間比較長(zhǎng)。   

b、盡量減少Young GC執(zhí)行的時(shí)間

回收算法

標(biāo)記-清除算法

分為兩個(gè)階段:標(biāo)記和清除,內(nèi)存使用了一段時(shí)間之后,里面肯定有垃圾對(duì)象也有正常對(duì)象,第一個(gè)階段進(jìn)行標(biāo)記,就是把每個(gè)對(duì)象標(biāo)記出是垃圾對(duì)象還是正常對(duì)象,而具體判斷依據(jù)就是上面的垃圾判斷算法;第二個(gè)階段進(jìn)行清除,就是把所有垃圾對(duì)象進(jìn)行清除:

?標(biāo)記-清除算法適用于存活對(duì)象比較多的情況,清除的對(duì)象越少效率就高,缺點(diǎn)是清除之后會(huì)產(chǎn)生內(nèi)存碎片,隨著多次垃圾回收,多次標(biāo)記-清除之后,內(nèi)存碎片現(xiàn)象會(huì)更加嚴(yán)重,導(dǎo)致大對(duì)象找不到連續(xù)內(nèi)存進(jìn)行存放。?

標(biāo)記-復(fù)制算法

復(fù)制算法就是說(shuō)有把內(nèi)存劃分為兩塊,A塊和B塊,第一次使用時(shí)比如說(shuō)使用了B塊,就會(huì)只在B塊中分配對(duì)象,當(dāng)進(jìn)行垃圾回收的時(shí)候,把B塊中存活的對(duì)象全部復(fù)制出來(lái),然后放在A塊里面,清空B塊;垃圾回收之后,進(jìn)行第二次使用時(shí),使用A塊,依次往復(fù):

?

?復(fù)制算法的適用于存活對(duì)象比較少的情況,復(fù)制的對(duì)象越少效率就高,缺點(diǎn)就是內(nèi)存使用率不高,因?yàn)槭冀K有一塊內(nèi)存是閑置的。

標(biāo)記-整理算法

分為兩個(gè)階段:標(biāo)記和整理,內(nèi)存使用了一段時(shí)間之后,里面有垃圾對(duì)象和正常對(duì)象,第一個(gè)階段進(jìn)行標(biāo)記,和標(biāo)記-清除算法中的標(biāo)記過(guò)程一樣,把每個(gè)對(duì)象標(biāo)記出來(lái)是垃圾對(duì)象還是正常對(duì)象,具體判斷依據(jù)就是上面的垃圾判斷算法;第二個(gè)階段進(jìn)行整理,就是把垃圾對(duì)象清理之后,并且把存活對(duì)象進(jìn)行內(nèi)存整理,整齊地在內(nèi)存中排列:

?

標(biāo)記-整理算法同樣適用于存活對(duì)象比較多的情況,清除的對(duì)象越少效率就越高,而且通過(guò)內(nèi)存整理解決了內(nèi)存碎片的問(wèn)題,但同時(shí)也意味著更慢了,因?yàn)樾枰獣r(shí)間來(lái)進(jìn)行內(nèi)存整理。

分代收集算法

我們將內(nèi)存區(qū)域分成兩片,一邊叫新生代,另一邊叫老年代

并且引入一個(gè)屬性:年齡
我們將年齡定義為:經(jīng)歷過(guò)多少次 GC,且還存活的輪次,例如,經(jīng)歷 3 次 GC,還健在的對(duì)象年齡為 3

新生代再分為伊甸區(qū)和兩個(gè)幸存區(qū),然后每次新建立的對(duì)象都會(huì)放在伊甸區(qū),并且根據(jù)經(jīng)驗(yàn)規(guī)律,大部分對(duì)象連一輪 GC 都撐不過(guò),所以每次 GC 后,伊甸區(qū)只會(huì)剩下小部分對(duì)象

然后將這部分對(duì)象通過(guò)復(fù)制算法移動(dòng)到其中一個(gè)幸存區(qū)中,再釋放伊甸區(qū)的對(duì)象(注意:幸存區(qū)有兩個(gè),可以方便復(fù)制算法在這兩個(gè)區(qū)域運(yùn)行)

在這里插入圖片描述

?移動(dòng)到幸存區(qū)后,還會(huì)經(jīng)歷多次 GC,每次 GC 運(yùn)行后,幸存的對(duì)象又會(huì)通過(guò)復(fù)制算法移動(dòng)到另一個(gè)幸存區(qū),再將之前的幸存區(qū)釋放

隨后,將幸存區(qū)中滿(mǎn)足年齡要求的對(duì)象會(huì)通過(guò)復(fù)制算法移動(dòng)到老年代

能夠到達(dá)老年區(qū)也就足以說(shuō)明這些對(duì)象在短時(shí)間內(nèi)還死不了,所以老年代中會(huì)進(jìn)行頻率更低的 GC,如果老年代中發(fā)現(xiàn)了垃圾,就會(huì)通過(guò)標(biāo)記-整理算法清除。(如果對(duì)象空間很大,則會(huì)被直接移動(dòng)到老年代中)

垃圾收集器,問(wèn)什么時(shí)候下會(huì)觸發(fā)gc

GC是由JVM自動(dòng)完成的,根據(jù)JVM系統(tǒng)環(huán)境而定,所以機(jī)制是不確定的,當(dāng)然我們也可以手動(dòng)進(jìn)行垃圾回收,比如調(diào)用System.gc()方法通知JVM進(jìn)行垃圾回收,但是具體什么時(shí)候運(yùn)行也是無(wú)法控制的,也就是說(shuō)我們調(diào)用了System.gc()只是通知JVM要去回收,但是什么時(shí)候回收是由JVM決定的,但是不建議手動(dòng)調(diào)用該方法,因?yàn)镚C消耗的資源比較大。

那會(huì)觸發(fā)垃圾回收的情況有以下幾種:

1.當(dāng)Eden區(qū)或者S區(qū)不夠用了

2.老年代空間不夠用了

3.方法區(qū)空間不夠用了

4.System.gc() 執(zhí)行的是Full GC的操作

參考:垃圾回收(GC) 很干,很全_gc垃圾回收_浩展的博客-CSDN博客

垃圾回收機(jī)制——GC詳講_gc回收機(jī)制_答辣喇叭的博客-CSDN博客

Redis

redis是一款高性能的NOSQL系列的非關(guān)系型數(shù)據(jù)庫(kù),?NoSQL(NoSQL = Not Only SQL),意即“不僅僅是SQL”,是一項(xiàng)全新的數(shù)據(jù)庫(kù)理念,泛指非關(guān)系型的數(shù)據(jù)庫(kù)。

? Redis是用C語(yǔ)言開(kāi)發(fā)的一個(gè)開(kāi)源的高性能鍵值對(duì)(key-value)數(shù)據(jù)庫(kù),官方提供測(cè)試數(shù)據(jù),50個(gè)并發(fā)執(zhí)行100000個(gè)請(qǐng)求,讀的速度是110000次/s,寫(xiě)的速度是81000次/s ,且Redis通過(guò)提供多種鍵值數(shù)據(jù)類(lèi)型來(lái)適應(yīng)不同場(chǎng)景下的存儲(chǔ)需求,目前為止Redis支持的鍵值數(shù)據(jù)類(lèi)型如下:
? ? ? ? ? ? ? ? 1) 字符串類(lèi)型 string
? ? ? ? ? ? ? ? 2) 哈希類(lèi)型 hash
? ? ? ? ? ? ? ? 3) 列表類(lèi)型 list
? ? ? ? ? ? ? ? 4) 集合類(lèi)型 set
? ? ? ? ? ? ? ? 5) 有序集合類(lèi)型 sortedset


redis的數(shù)據(jù)結(jié)構(gòu)

redis存儲(chǔ)的是:key,value格式的數(shù)據(jù),其中key都是字符串,value有5種不同的數(shù)據(jù)結(jié)構(gòu)
value的數(shù)據(jù)結(jié)構(gòu):
? ? ? ? ? ? ? ? ? ? 1) 字符串類(lèi)型 string
? ? ? ? ? ? ? ? ? ? 2) 哈希類(lèi)型 hash : map格式 ?
? ? ? ? ? ? ? ? ? ? 3) 列表類(lèi)型 list : linkedlist格式。支持重復(fù)元素
? ? ? ? ? ? ? ? ? ? 4) 集合類(lèi)型 set ?: 不允許重復(fù)元素
? ? ? ? ? ? ? ? ? ? 5) 有序集合類(lèi)型 sortedset:不允許重復(fù)元素,且元素有順序

Redis優(yōu)缺點(diǎn)


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

讀寫(xiě)性能優(yōu)異, Redis能讀的速度是110000次/s,寫(xiě)的速度是81000次/s。
支持?jǐn)?shù)據(jù)持久化,支持AOF和RDB兩種持久化方式。
支持事務(wù),Redis的所有操作都是原子性的,同時(shí)Redis還支持對(duì)幾個(gè)操作合并后的原子性執(zhí)行。
數(shù)據(jù)結(jié)構(gòu)豐富,除了支持string類(lèi)型的value外還支持hash、set、zset、list等數(shù)據(jù)結(jié)構(gòu)。
支持主從復(fù)制,主機(jī)會(huì)自動(dòng)將數(shù)據(jù)同步到從機(jī),可以進(jìn)行讀寫(xiě)分離。


缺點(diǎn)

數(shù)據(jù)庫(kù)容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫(xiě),因此Redis適合的場(chǎng)景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。
Redis 不具備自動(dòng)容錯(cuò)和恢復(fù)功能,主機(jī)從機(jī)的宕機(jī)都會(huì)導(dǎo)致前端部分讀寫(xiě)請(qǐng)求失敗,需要等待機(jī)器重啟或者手動(dòng)切換前端的IP才能恢復(fù)。
主機(jī)宕機(jī),宕機(jī)前有部分?jǐn)?shù)據(jù)未能及時(shí)同步到從機(jī),切換IP后還會(huì)引入數(shù)據(jù)不一致的問(wèn)題,降低了系統(tǒng)的可用性。
Redis 較難支持在線(xiàn)擴(kuò)容,在集群容量達(dá)到上限時(shí)在線(xiàn)擴(kuò)容會(huì)變得很復(fù)雜。為避免這一問(wèn)題,運(yùn)維人員在系統(tǒng)上線(xiàn)時(shí)必須確保有足夠的空間,這對(duì)資源造成了很大的浪費(fèi)。

redis 五種數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)的數(shù)據(jù)場(chǎng)景


1.String 字符串類(lèi)型

String是redis中最基本的數(shù)據(jù)類(lèi)型,一個(gè)key對(duì)應(yīng)一個(gè)value。

String類(lèi)型是二進(jìn)制安全的,意思是 redis 的 string 可以包含任何數(shù)據(jù)。如數(shù)字,字符串,jpg圖片或者序列化的對(duì)象。

這里稍微講一下什么是二進(jìn)制安全,一個(gè)二進(jìn)制安全功能(函數(shù)),其本質(zhì)上將操作輸入作為原始的、無(wú)任何特殊格式意義的數(shù)據(jù)流。對(duì)于每個(gè)字符都公平對(duì)待,不特殊處理某一個(gè)字符。

什么意思呢,舉個(gè)例子:

C語(yǔ)言中的字符串是根據(jù)特殊字符“\0”來(lái)判斷該字符串是否結(jié)束,對(duì)于字符串str="0123456789\0123456789”來(lái)說(shuō),在C語(yǔ)言里面str的長(zhǎng)度就是10(strlen(str)=10),所以strlen()函數(shù)不是二進(jìn)制安全的。而在Redis中,strlen str的結(jié)果是21,是二進(jìn)制安全的(Redis底層所使用的字符串表示是Sds),它只關(guān)心二進(jìn)制化的字符串,不關(guān)心字符串的具體格式,里面有啥字符,只會(huì)嚴(yán)格的按照二進(jìn)制的數(shù)據(jù)存取,不會(huì)以某種特殊格式解析字符串。

實(shí)戰(zhàn)場(chǎng)景:
1.緩存: 經(jīng)典使用場(chǎng)景,把常用信息,字符串,圖片或者視頻等信息放到redis中,redis作為緩存層,mysql做持久化層,降低mysql的讀寫(xiě)壓力。

舉個(gè)我曾經(jīng)做看守所項(xiàng)目時(shí)候使用過(guò)的例子:做很多流程操作的時(shí)候比如家屬會(huì)見(jiàn)、財(cái)務(wù)管理等等我們往往都會(huì)先判斷當(dāng)前人員是否為在押人員,而判斷是否為在押人員是另外一個(gè)微服務(wù)接口,如果直接實(shí)時(shí)的去調(diào)用那個(gè)接口,短時(shí)的高并發(fā)很有可能把這個(gè)服務(wù)也拖掛,最終導(dǎo)致整個(gè)系統(tǒng)不可用,并且 RPC 本身也是比較耗時(shí)的,所以就考慮在這里進(jìn)行優(yōu)化。

那當(dāng)時(shí)我們是怎么做呢?很簡(jiǎn)單的一個(gè)思路,提前將所有的在押人員的user_id存到redis中,這樣,當(dāng)請(qǐng)求到來(lái)的時(shí)候我們直接通過(guò)緩存可以快速判斷是否為在押人員。如果不是則直接在這里返回前端。

通過(guò)預(yù)先處理減少了實(shí)時(shí)鏈路上的 RPC 調(diào)用,既減少了系統(tǒng)的外部依賴(lài),也極大的提高了系統(tǒng)的吞吐量。

2.計(jì)數(shù)器:redis是單線(xiàn)程模型,一個(gè)命令執(zhí)行完才會(huì)執(zhí)行下一個(gè),同時(shí)數(shù)據(jù)可以一步落地到其他的數(shù)據(jù)源。一般會(huì)使用decr、incr命令用于計(jì)數(shù)器的實(shí)現(xiàn)。

當(dāng)遇到需求,在規(guī)定時(shí)間,用戶(hù)的訪問(wèn)量不能超過(guò)規(guī)定次數(shù)的時(shí)候就可以用redis中的計(jì)數(shù)器來(lái)實(shí)現(xiàn)了又可以使用這個(gè)技術(shù)用來(lái)做限流(使用用戶(hù)的ip作為key,用戶(hù)訪問(wèn)一次,就加1,如果超過(guò)次數(shù)就返回false)可以處理業(yè)務(wù)上面的的一些訪問(wèn)次數(shù)之類(lèi)的,例如:文章的點(diǎn)贊數(shù),閱讀量,允許有一點(diǎn)的延遲效果,先保存到redis中,然后在同步到數(shù)據(jù)庫(kù)當(dāng)中3.session:常見(jiàn)方案spring session + redis實(shí)現(xiàn)session共享

2.Hash (哈希)

Hash是一個(gè)Mapmap,Value值本身又是一種鍵值對(duì)結(jié)構(gòu),如 value={{field1,value1},…fieldN,valueN}}

實(shí)戰(zhàn)場(chǎng)景:
1.緩存: 能直觀,相比string更節(jié)省空間一些,可以維護(hù)緩存信息,如用戶(hù)信息,視頻信息等,但用hash實(shí)現(xiàn)的,string也可以實(shí)現(xiàn)。

為什么這么說(shuō)呢?

其實(shí)hash類(lèi)型的(key、field、value)的結(jié)構(gòu)與對(duì)象的(對(duì)象id,屬性,值)的結(jié)構(gòu)相似,也可以用來(lái)存儲(chǔ)對(duì)象。

所以hash也可以用string+json存儲(chǔ)對(duì)象的一種方式,那么存儲(chǔ)對(duì)象時(shí),到底用string+json還是用hash呢?

string+json

hash

效率

很高

容量

靈活性

序列化

簡(jiǎn)單

復(fù)雜

所以說(shuō),當(dāng)對(duì)象的某個(gè)屬性需要頻繁修改時(shí),不適合用string+json,因?yàn)椴粔蜢`活,每次修改都需要重新將整個(gè)對(duì)象序列化并賦值,如果使用hash類(lèi)型,則可以針對(duì)某個(gè)屬性單獨(dú)修改,沒(méi)有序列化,也不需要修改整個(gè)對(duì)象。比如,商品的價(jià)格、銷(xiāo)量、關(guān)注數(shù)、評(píng)論數(shù)等可能經(jīng)常發(fā)生變化的屬性,就適合存儲(chǔ)在hash類(lèi)型里面。

綜上,一般對(duì)象用string+json存儲(chǔ),對(duì)象中某些頻繁變化的屬性抽出來(lái)用hash存儲(chǔ)。

2.購(gòu)物車(chē):以用戶(hù)id為key,商品id為field,商品數(shù)量為value,恰好構(gòu)成購(gòu)物車(chē)的3個(gè)要素。

3.鏈表

List 說(shuō)白了就是鏈表(redis 使用雙端鏈表實(shí)現(xiàn)的 List),是有序的,value可以重復(fù),可以通過(guò)下標(biāo)取出對(duì)應(yīng)的value值,左右兩邊都能進(jìn)行插入和刪除數(shù)據(jù)。

實(shí)戰(zhàn)場(chǎng)景:
1.timeline:例如微博的時(shí)間軸,有人發(fā)布微博,用lpush加入時(shí)間軸,展示新的列表信息。

2.排行榜

list類(lèi)型的lrange命令可以分頁(yè)查看隊(duì)列中的數(shù)據(jù)??蓪⒚扛粢欢螘r(shí)間計(jì)算一次的排行榜存儲(chǔ)在list類(lèi)型中,如京東每日的手機(jī)銷(xiāo)量排行、學(xué)校每次月考學(xué)生的成績(jī)排名。但是,并不是所有的排行榜都能用list類(lèi)型實(shí)現(xiàn),只有定時(shí)計(jì)算的排行榜才適合使用list類(lèi)型存儲(chǔ),與定時(shí)計(jì)算的排行榜相對(duì)應(yīng)的是實(shí)時(shí)計(jì)算的排行榜,list類(lèi)型不能支持實(shí)時(shí)計(jì)算的排行榜

但是,對(duì)于頻繁更新的列表,list類(lèi)型的分頁(yè)可能導(dǎo)致列表元素重復(fù)或漏掉。

舉個(gè)例子,當(dāng)前列表里由表頭到表尾依次有(E,D,C,B,A)五個(gè)元素,每頁(yè)獲取3個(gè)元素,用戶(hù)第一次獲取到(E,D,C)三個(gè)元素,然后表頭新增了一個(gè)元素F,列表變成了(F,E,D,C,B,A),此時(shí)用戶(hù)取第二頁(yè)拿到(C,B,A),元素C重復(fù)了。只有不需要分頁(yè)(比如每次都只取列表的前5個(gè)元素)或者更新頻率低(比如每天凌晨更新一次)的列表才適合用list類(lèi)型實(shí)現(xiàn)。對(duì)于需要分頁(yè)并且會(huì)頻繁更新的列表,需用使用有序集合sorted set類(lèi)型實(shí)現(xiàn)。另外,需要通過(guò)時(shí)間范圍查找的最新列表,list類(lèi)型也實(shí)現(xiàn)不了,也需要通過(guò)有序集合sorted set類(lèi)型實(shí)現(xiàn),如以成交時(shí)間范圍作為條件來(lái)查詢(xún)的訂單列表。

4.Set 集合

集合類(lèi)型也是用來(lái)保存多個(gè)字符串的元素,但和列表不同的是集合中 1. 不允許有重復(fù)的元素,2.集合中的元素是無(wú)序的,不能通過(guò)索引下標(biāo)獲取元素,3.支持集合間的操作,可以取多個(gè)集合取交集、并集、差集。跟Java的HashSet類(lèi)似。

實(shí)戰(zhàn)場(chǎng)景:
1.標(biāo)簽(tag),給用戶(hù)添加標(biāo)簽,或者用戶(hù)給消息添加標(biāo)簽,這樣有同一標(biāo)簽或者類(lèi)似標(biāo)簽的可以給推薦關(guān)注的事或者關(guān)注的人。

2.點(diǎn)贊,或點(diǎn)踩,收藏等,可以放到set中實(shí)現(xiàn)

因?yàn)镽edis為set類(lèi)型提供了求交集,并集,差集的操作,可以非常方便地實(shí)現(xiàn)譬如共同關(guān)注、共同愛(ài)好、共同好友等功能。

sinter交集命令可以獲得A和B兩個(gè)用戶(hù)的共同好友sismember命令可以判斷A是否是B的好友scard命令可以獲取好友數(shù)量關(guān)注時(shí),smove命令可以將B從A的粉絲集合轉(zhuǎn)移到A的好友集合srandmember命令可以隨機(jī)展示當(dāng)然黑名單白名單也一樣,set類(lèi)型適合存儲(chǔ)這些黑名單數(shù)據(jù),sismember命令可用于判斷用戶(hù)、ip、設(shè)備是否處于黑名單之中。

5.zset 有序集合

有序集合和集合有著必然的聯(lián)系,它和set一樣是不可重復(fù)的,區(qū)別在于多了score值,用來(lái)代表排序的權(quán)重。也就是當(dāng)你需要一個(gè)有序的,不可重復(fù)的集合列表時(shí),就可以考慮使用這種數(shù)據(jù)類(lèi)型。

(有序集合中的元素不可以重復(fù),但是score 分?jǐn)?shù)可以重復(fù),就和一個(gè)班里的同學(xué)學(xué)號(hào)不能重復(fù),但考試成績(jī)可以相同)。

實(shí)戰(zhàn)場(chǎng)景:
1.排行榜:有序集合經(jīng)典使用場(chǎng)景。例如小說(shuō)視頻等網(wǎng)站需要對(duì)用戶(hù)上傳的小說(shuō)視頻做排行榜,榜單可以按照用戶(hù)關(guān)注數(shù),更新時(shí)間,字?jǐn)?shù)等打分,做排行。
?

使用redis做緩存的原因


高性能:

redis是用C語(yǔ)言編寫(xiě)的,穩(wěn)定性和性能更好。

用戶(hù)第一次訪問(wèn)數(shù)據(jù)庫(kù)中的某些數(shù)據(jù),因?yàn)槭菑挠脖P(pán)上讀取的,這個(gè)過(guò)程會(huì)比較慢。將該用戶(hù)訪問(wèn)的數(shù)據(jù)存在redis緩存中,這樣下一次再訪問(wèn)這些數(shù)據(jù)的時(shí)候就可以直接從緩存中獲取了。操作緩存就是直接操作內(nèi)存,所以速度相當(dāng)快。如果數(shù)據(jù)庫(kù)中的對(duì)應(yīng)數(shù)據(jù)改變的之后,同步改變緩存中相應(yīng)的數(shù)據(jù)即可!

高可靠:

支持集群模式和持久化等特性,不會(huì)應(yīng)為緩存量太多而導(dǎo)致虛擬機(jī)崩潰。Redis是獨(dú)立部署的,即使網(wǎng)站更新,redis緩存的數(shù)據(jù)也不會(huì)消失。

高并發(fā):

直接操作緩存能夠承受的請(qǐng)求是遠(yuǎn)遠(yuǎn)大于直接訪問(wèn)數(shù)據(jù)庫(kù)的,所以我們可以考慮把數(shù)據(jù)庫(kù)中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶(hù)的一部分請(qǐng)求會(huì)直接到緩存這里而不用經(jīng)過(guò)數(shù)據(jù)庫(kù)。

redis 高性能原理的原因

1、完全基于內(nèi)存,絕大部分請(qǐng)求是純粹的內(nèi)存操作,非??焖佟?shù)據(jù)存在內(nèi)存中,類(lèi)似于 HashMap,

HashMap 的優(yōu)勢(shì)就是查找和操作的時(shí)間復(fù)雜度都是O(1);

2、數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單,對(duì)數(shù)據(jù)操作也簡(jiǎn)單,Redis 中的數(shù)據(jù)結(jié)構(gòu)是專(zhuān)門(mén)進(jìn)行設(shè)計(jì)的;

?

合理的數(shù)據(jù)編碼

對(duì)于每一種數(shù)據(jù)類(lèi)型來(lái)說(shuō),底層的支持可能是多種數(shù)據(jù)結(jié)構(gòu),什么時(shí)候使用哪種數(shù)據(jù)結(jié)構(gòu),這就涉及到了編碼轉(zhuǎn)化的問(wèn)題。

那我們就來(lái)看看,不同的數(shù)據(jù)類(lèi)型是如何進(jìn)行編碼轉(zhuǎn)化的:

String:存儲(chǔ)數(shù)字的話(huà),采用int類(lèi)型的編碼,如果是非數(shù)字的話(huà),采用 raw 編碼;

List:字符串長(zhǎng)度及元素個(gè)數(shù)小于一定范圍使用 ziplist 編碼,任意條件不滿(mǎn)足,則轉(zhuǎn)化為 linkedlist 編碼;

Hash:hash 對(duì)象保存的鍵值對(duì)內(nèi)的鍵和值字符串長(zhǎng)度小于一定值及鍵值對(duì);

Set:保存元素為整數(shù)及元素個(gè)數(shù)小于一定范圍使用 intset 編碼,任意條件不滿(mǎn)足,則使用 hashtable 編碼;

Zset:zset 對(duì)象中保存的元素個(gè)數(shù)小于及成員長(zhǎng)度小于一定值使用 ziplist 編碼,任意條件不滿(mǎn)足,則使用 skiplist 編碼。

3、采用單線(xiàn)程,避免了不必要的上下文切換和競(jìng)爭(zhēng)條件,也不存在多進(jìn)程或者多線(xiàn)程導(dǎo)致的切換?

而消耗CPU,不用去考慮各種鎖的問(wèn)題,不存在加鎖釋放鎖操作,沒(méi)有因?yàn)榭赡艹霈F(xiàn)死鎖而導(dǎo)致的

性能消耗;

?

4、使用多路 I/O 復(fù)用模型,非阻塞 IO;

?

5、使用底層模型不同,它們之間底層實(shí)現(xiàn)方式以及與客戶(hù)端之間通信的應(yīng)用協(xié)議不一樣,Redis

直接自己構(gòu)建了 VM 機(jī)制 ,因?yàn)橐话愕南到y(tǒng)調(diào)用系統(tǒng)函數(shù)的話(huà),會(huì)浪費(fèi)一定的時(shí)間去移動(dòng)和請(qǐng)

求;

redis 緩存 出現(xiàn)的緩存擊穿、緩存雪崩、緩存穿透的具體解決方法

三者出現(xiàn)的根本原因:Redis命中率下降,請(qǐng)求直接打在DB上

正常情況下,大量的資源請(qǐng)求都會(huì)被redis響應(yīng),在redis得不到響應(yīng)的小部分請(qǐng)求才會(huì)去請(qǐng)求DB,這樣DB的壓力是非常小的,是可以正常工作的(如下圖):

?

如果大量的請(qǐng)求在redis上得不到響應(yīng),那么就會(huì)導(dǎo)致這些請(qǐng)求會(huì)直接去訪問(wèn)DB,導(dǎo)致DB的壓力瞬間變大而卡死或者宕機(jī)。如下圖:

① 大量的高并發(fā)的請(qǐng)求打在redis上

② 這些請(qǐng)求發(fā)現(xiàn)redis上并沒(méi)有需要請(qǐng)求的資源,redis命中率降低

③ 因此這些大量的高并發(fā)請(qǐng)求轉(zhuǎn)向DB(數(shù)據(jù)庫(kù)服務(wù)器)請(qǐng)求對(duì)應(yīng)的資源

④ DB壓力瞬間增大,直接將DB打垮,進(jìn)而引發(fā)一系列“災(zāi)害”

?那么為什么redis會(huì)沒(méi)有需要訪問(wèn)的數(shù)據(jù)呢?通過(guò)分析大致可以總結(jié)為三種情況,也就對(duì)應(yīng)著redis的雪崩、穿透和擊穿(下文開(kāi)始進(jìn)行詳解)

問(wèn)題名稱(chēng)

緩存穿透

緩存擊穿

緩存雪崩

資源是否存在DB數(shù)據(jù)庫(kù)服務(wù)器中

×

資源是否存在Redis中

×

×

×

redis沒(méi)有對(duì)應(yīng)資源的原因

根本不存在該資源(DB也沒(méi)有)

某個(gè)熱點(diǎn)key過(guò)期

大部分key集體過(guò)期

根本原因: 大量的高并發(fā)的請(qǐng)求打在Redis上,但是發(fā)現(xiàn)Redis中并沒(méi)有請(qǐng)求的數(shù)據(jù),redis的命令率降低,所以這些請(qǐng)求就只能直接打在DB(數(shù)據(jù)庫(kù)服務(wù)器)上,在大量的高并發(fā)的請(qǐng)求下就會(huì)導(dǎo)致DB直接卡死、宕機(jī)。

1.緩存穿透

緩存穿透產(chǎn)生的原因:請(qǐng)求根本不存在的資源(DB本身就不存在,Redis更是不存在)這時(shí)的用戶(hù)很可能是攻擊者,如發(fā)起為id為"-1"的數(shù)據(jù)或id為特別大(不存在的數(shù)據(jù)),導(dǎo)致數(shù)據(jù)庫(kù)壓力過(guò)大或宕機(jī)。

解決方式:
對(duì)空值進(jìn)行緩存:
類(lèi)似于上面的例子,雖然數(shù)據(jù)庫(kù)中沒(méi)有id=-3872的用戶(hù)的數(shù)據(jù),但是在redis中對(duì)他進(jìn)行緩存(key=-3872,value=null),這樣當(dāng)請(qǐng)求到達(dá)redis的時(shí)候就會(huì)直接返回一個(gè)null的值給客戶(hù)端,避免了大量無(wú)法訪問(wèn)的數(shù)據(jù)直接打在DB上

實(shí)時(shí)監(jiān)控:
對(duì)redis進(jìn)行實(shí)時(shí)監(jiān)控,當(dāng)發(fā)現(xiàn)redis中的命中率下降的時(shí)候進(jìn)行原因的排查,配合運(yùn)維人員對(duì)訪問(wèn)對(duì)象和訪問(wèn)數(shù)據(jù)進(jìn)行分析查詢(xún),從而進(jìn)行黑名單的設(shè)置限制服務(wù)(拒絕黑客攻擊)

使用布隆過(guò)濾器:
使用BitMap作為布隆過(guò)濾器,將目前所有可以訪問(wèn)到的資源通過(guò)簡(jiǎn)單的映射關(guān)系放入到布隆過(guò)濾器中(哈希計(jì)算),當(dāng)一個(gè)請(qǐng)求來(lái)臨的時(shí)候先進(jìn)行布隆過(guò)濾器的判斷,如果有那么才進(jìn)行放行,否則就直接攔截

接口校驗(yàn):
類(lèi)似于用戶(hù)權(quán)限的攔截,對(duì)于id=-3872這些無(wú)效訪問(wèn)就直接攔截,不允許這些請(qǐng)求到達(dá)Redis、DB上。

注意事項(xiàng):
1).使用空值作為緩存的時(shí)候,key設(shè)置的過(guò)期時(shí)間不能太長(zhǎng),防止占用太多redis資源

2).使用空值作為緩存只能防止黑客重復(fù)使用相同的id暴力攻擊,但是如果黑客使用動(dòng)態(tài)的無(wú)效id攻擊就沒(méi)有效果(需要配合網(wǎng)警)

3).使用布隆過(guò)濾器也是有哈希沖突的可能

2.緩存雪崩

緩存雪崩產(chǎn)生的原因:redis中大量的key集體過(guò)期,?緩存集中過(guò)度,或者緩存服務(wù)器宕機(jī),導(dǎo)致大量請(qǐng)求訪問(wèn)數(shù)據(jù)庫(kù),造成數(shù)據(jù)庫(kù)瞬間壓力過(guò)大,宕機(jī)。

?

解決方式:
將失效時(shí)間分散開(kāi)
通過(guò)使用自動(dòng)生成隨機(jī)數(shù)使得key的過(guò)期時(shí)間是隨機(jī)的,防止集體過(guò)期

使用多級(jí)架構(gòu)
使用nginx緩存+redis緩存+其他緩存,不同層使用不同的緩存,可靠性更強(qiáng)

設(shè)置緩存標(biāo)記
記錄緩存數(shù)據(jù)是否過(guò)期,如果過(guò)期會(huì)觸發(fā)通知另外的線(xiàn)程在后臺(tái)去跟新實(shí)際的key

使用鎖或者隊(duì)列的方式
如果查不到就加上排它鎖,其他請(qǐng)求只能進(jìn)行等待

?3.緩存擊穿

產(chǎn)生緩存雪崩的原因:redis中的某個(gè)熱點(diǎn)key過(guò)期,但是此時(shí)有大量的用戶(hù)訪問(wèn)該過(guò)期key,??高并發(fā)時(shí),當(dāng)一個(gè)key非常熱點(diǎn)(類(lèi)似于爆款),在不停的扛著大并發(fā),當(dāng)這個(gè)key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)庫(kù)并設(shè)置到緩存中,導(dǎo)致性能下降。

?

解決方案:
提前對(duì)熱點(diǎn)數(shù)據(jù)進(jìn)行設(shè)置
類(lèi)似于新聞、某博等軟件都需要對(duì)熱點(diǎn)數(shù)據(jù)進(jìn)行預(yù)先設(shè)置在redis中

監(jiān)控?cái)?shù)據(jù),適時(shí)調(diào)整
監(jiān)控哪些數(shù)據(jù)是熱門(mén)數(shù)據(jù),實(shí)時(shí)的調(diào)整key的過(guò)期時(shí)長(zhǎng)

使用鎖機(jī)制
最后的防線(xiàn),當(dāng)熱點(diǎn)key過(guò)期,那么就使用鎖機(jī)制防止大量的請(qǐng)求直接打在DB

如何保證Redis與數(shù)據(jù)庫(kù)的數(shù)據(jù)一致!

ONE 案例

先刪除“緩存”再去更新“數(shù)據(jù)庫(kù)”。但是該方案還存在問(wèn)題:

????????在高并發(fā)情況下,第一個(gè)線(xiàn)程刪除緩存,還沒(méi)來(lái)得及去操作數(shù)據(jù)庫(kù),這時(shí)第二個(gè)線(xiàn)程訪問(wèn)緩存,發(fā)現(xiàn)為null,于是去數(shù)據(jù)庫(kù)查詢(xún),獲取到需要的值,這時(shí)候第一個(gè)線(xiàn)程才開(kāi)始操作數(shù)據(jù)庫(kù),然后設(shè)置緩存,但是第二個(gè)線(xiàn)程又跟奇怪的將第一個(gè)線(xiàn)程剛設(shè)置的緩存給覆蓋掉,然后就出現(xiàn)“烏龍”,數(shù)據(jù)不一致的問(wèn)題也出現(xiàn)了!

解決方案:

① 先操作緩存去修改數(shù)據(jù)庫(kù),但不刪除緩存。將這個(gè)不刪除的緩存設(shè)置為一個(gè)特殊值(*123),當(dāng)客戶(hù)端讀緩存的時(shí)候,發(fā)現(xiàn)有前綴包含( * ???),知道他是壞值,就會(huì)進(jìn)行休眠(1秒這樣),然后再去查詢(xún)Redis。 //這樣做的弊端是:特殊值對(duì)業(yè)務(wù)可能出現(xiàn)影響,休眠時(shí)間會(huì)重復(fù)(高并發(fā)情況下,修改操作頻繁,反復(fù)會(huì)修改這個(gè)特殊值的內(nèi)容,然后同時(shí)出現(xiàn)睡眠),影響性能。

②延遲雙刪,先刪除緩存數(shù)據(jù),再把數(shù)據(jù)更新到數(shù)據(jù)庫(kù)中,休眠一會(huì)(根據(jù)業(yè)務(wù)邏輯的耗時(shí),更改休眠時(shí)間)后再次刪除該緩存數(shù)據(jù)。若線(xiàn)程1是更新請(qǐng)求,線(xiàn)程2是查詢(xún)請(qǐng)求,延遲雙刪,可以保證再這兩個(gè)請(qǐng)求同時(shí)存在的情況下的數(shù)據(jù)一致性!確保查詢(xún)請(qǐng)求結(jié)束,更新請(qǐng)求可以刪除查詢(xún)請(qǐng)求造成的緩存臟數(shù)據(jù)。

總結(jié):寫(xiě)操作不能太頻繁!

TWO 案例

先刪除“數(shù)據(jù)庫(kù)”再去更新“緩存”。

該案例的問(wèn)題是:數(shù)據(jù)庫(kù)寫(xiě)完之后,再刪除緩存,但刪除失敗了,這會(huì)導(dǎo)致數(shù)據(jù)不一致。

解決方案:

①給緩存設(shè)置一個(gè)過(guò)期時(shí)間,但缺點(diǎn)是,過(guò)期時(shí)間內(nèi) 不能保證數(shù)據(jù)是有用的數(shù)據(jù),可能是上次沒(méi)刪掉的壞數(shù)據(jù)。

②引入MQ,保證原子操作。

一個(gè)去刪緩存,一個(gè)去操作數(shù)據(jù)庫(kù)。MQ若是刪除操作失敗了,啟動(dòng)MQ重試機(jī)制,在重試的這段時(shí)間,緩存數(shù)據(jù)不會(huì)更新。

③將熱點(diǎn)數(shù)據(jù)緩存設(shè)置為永不過(guò)期,但是在value當(dāng)中寫(xiě)入一個(gè)邏輯上的過(guò)期時(shí)間,另外起一個(gè)后臺(tái)線(xiàn)程,掃描這些key,對(duì)于已邏輯上過(guò)期的緩存,進(jìn)行刪除。

總結(jié):始終只能保證一定時(shí)間內(nèi)的最終一致性。

THREE 案例

Redis和Mysql集群實(shí)現(xiàn)的讀寫(xiě)分離架構(gòu)

????????如果MySQL采用的是讀寫(xiě)分離的架構(gòu),主從服務(wù)器之間也會(huì)存在時(shí)間差,也就是A更新操作,刪除緩存,并請(qǐng)求主數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)更新,主庫(kù)與從庫(kù)進(jìn)行同步數(shù)據(jù)的操作,B進(jìn)行查詢(xún)操作時(shí),緩存中沒(méi)有數(shù)據(jù),就去從庫(kù)中讀取數(shù)據(jù),此時(shí)主從數(shù)據(jù)未更新完成,拿到的還是舊數(shù)據(jù)。

解決方法是:查詢(xún)數(shù)據(jù)經(jīng)過(guò)Redis時(shí),若查詢(xún)緩存為空時(shí),強(qiáng)制將其指向主數(shù)據(jù)庫(kù)中進(jìn)行查詢(xún)。

Four 案例

異步更新緩存(基于訂閱binlog的同步機(jī)制)

MySQL binlog增量訂閱消費(fèi)+消息隊(duì)列+增量數(shù)據(jù)更新到redis

讀Redis:熱數(shù)據(jù)基本都在Redis

寫(xiě)MySQL:增刪改都是操作MySQL

更新Redis數(shù)據(jù):MySQ的數(shù)據(jù)操作binlog,來(lái)更新到Redis Redis更新

①數(shù)據(jù)操作主要分為兩大塊:

一個(gè)是全量(將全部數(shù)據(jù)一次寫(xiě)入到redis)

一個(gè)是增量(實(shí)時(shí)更新) 這里說(shuō)的是增量,指的是mysql的update、insert、delate變更數(shù)據(jù)。

②讀取binlog后分析 ,利用消息隊(duì)列,推送更新各臺(tái)的redis緩存數(shù)據(jù)。

這樣一旦MySQL中產(chǎn)生了新的寫(xiě)入、更新、刪除等操作,就可以把binlog相關(guān)的消息推送至Redis,Redis再根據(jù)binlog中的記錄,對(duì)Redis進(jìn)行更新。

這種機(jī)制,很類(lèi)似MySQL的主從備份機(jī)制,因?yàn)镸ySQL的主備也是通過(guò)binlog來(lái)實(shí)現(xiàn)的數(shù)據(jù)一致性。

這里可以結(jié)合使用canal(阿里的一款開(kāi)源框架),通過(guò)該框架可以對(duì)MySQL的binlog進(jìn)行訂閱,而canal正是模仿了mysql的slave數(shù)據(jù)庫(kù)的備份請(qǐng)求,使得Redis的數(shù)據(jù)更新達(dá)到了相同的效果。

參考:redis常見(jiàn)面試題_鯊魚(yú)辣椒_TUT的博客-CSDN博客

反射

1.反射是什么?

反射(Reflection)能夠讓運(yùn)行于 JVM 中的程序檢測(cè)和修改運(yùn)行時(shí)的行為。

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制。
要想解剖一個(gè)類(lèi),必須先要獲取到該類(lèi)的字節(jié)碼文件對(duì)象。而解剖使用的就是Class類(lèi)中的方法.所以先要獲取到每一個(gè)字節(jié)碼文件對(duì)應(yīng)的Class類(lèi)型的對(duì)象.

反射就是把java類(lèi)中的各種成分映射成一個(gè)個(gè)的Java對(duì)象

例如:一個(gè)類(lèi)有:成員變量、方法、構(gòu)造方法、包等等信息,利用反射技術(shù)可以對(duì)一個(gè)類(lèi)進(jìn)行解剖,把個(gè)個(gè)組成部分映射成一個(gè)個(gè)對(duì)象。

2.反射機(jī)制有什么用??

運(yùn)行時(shí)動(dòng)態(tài)獲取類(lèi)的信息:在編寫(xiě)代碼時(shí),對(duì)于類(lèi)的信息是必須在編譯時(shí)確定的,但在運(yùn)行時(shí),有時(shí)需要根據(jù)某些條件,動(dòng)態(tài)獲取某個(gè)類(lèi)的信息,這時(shí)就可以使用Java中的反射機(jī)制。

動(dòng)態(tài)生成對(duì)象:反射機(jī)制可以在運(yùn)行時(shí)生成對(duì)象,這樣就可以根據(jù)參數(shù)的不同,動(dòng)態(tài)的創(chuàng)建不同的類(lèi)的實(shí)例對(duì)象。

動(dòng)態(tài)調(diào)用方法:通過(guò)反射機(jī)制可以調(diào)用類(lèi)中的方法,不論這些方法是否是公共的,也不論這些方法的參數(shù)個(gè)數(shù)和類(lèi)型是什么,反射機(jī)制都具有這樣的能力。

動(dòng)態(tài)修改屬性:利用反射機(jī)制可以獲取到類(lèi)中的所有成員變量,并可以對(duì)其進(jìn)行修改。

實(shí)現(xiàn)動(dòng)態(tài)代理:利用反射機(jī)制可以實(shí)現(xiàn)代理模式,通過(guò)代理對(duì)象完成原對(duì)象對(duì)某些方法的調(diào)用,同時(shí)也可以在這些方法的調(diào)用前后做一些額外的處理。

3.反射的實(shí)現(xiàn)原理?

調(diào)用反射的總體流程如下:

1、當(dāng)我們編寫(xiě)完一個(gè)Java項(xiàng)目之后,每個(gè)java文件都會(huì)被編譯成一個(gè).class文件。


2、這些class文件在程序運(yùn)行時(shí)會(huì)被ClassLoader加載到JVM中,當(dāng)一個(gè)類(lèi)被加載以后,JVM就會(huì)在內(nèi)存中自動(dòng)產(chǎn)生一個(gè)Class對(duì)象。

?

?


3、通過(guò)Class對(duì)象獲取Field/Method/Construcor


我們一般平時(shí)是通過(guò)new的形式創(chuàng)建對(duì)象實(shí)際上就是通過(guò)這些Class來(lái)創(chuàng)建的,只不過(guò)這個(gè)class文件是編譯的時(shí)候就生成的,程序相當(dāng)于寫(xiě)死了給jvm去跑。


反射是什么呢?當(dāng)我們的程序在運(yùn)行時(shí),需要?jiǎng)討B(tài)的加載一些類(lèi)這些類(lèi)可能之前用不到所以不用加載到j(luò)vm,而是在運(yùn)行時(shí)根據(jù)需要才加載。

?

?

原來(lái)使用new的時(shí)候,需要明確的指定類(lèi)名,這個(gè)時(shí)候?qū)儆谟簿幋a實(shí)現(xiàn),而在使用反射的時(shí)候,可以只傳入類(lèi)名參數(shù),就可以生成對(duì)象,降低了耦合性,使得程序更具靈活性。

4.java反射技術(shù)的應(yīng)用場(chǎng)景

框架開(kāi)發(fā):許多流行的Java框架,比如Spring、Hibernate、Struts等,都使用了反射機(jī)制,以提供更靈活、可擴(kuò)展的特性。

應(yīng)用程序開(kāi)發(fā):反射機(jī)制常常用于某些需要?jiǎng)討B(tài)加載或訪問(wèn)類(lèi)信息的應(yīng)用程序中,比如動(dòng)態(tài)配置,插件管理等。

單元測(cè)試:JUnit測(cè)試框架中,反射機(jī)制被廣泛應(yīng)用,可以方便地創(chuàng)建測(cè)試對(duì)象和調(diào)用測(cè)試方法。

動(dòng)態(tài)代理:反射機(jī)制可以實(shí)現(xiàn)動(dòng)態(tài)代理,實(shí)現(xiàn)不改變?cè)瓉?lái)代碼的情況下,對(duì)原來(lái)對(duì)象的方法進(jìn)行增強(qiáng)。

JavaBean工具:JavaBean工具中,使用反射機(jī)制可以獲取類(lèi)的屬性名、屬性值、調(diào)用屬性的setter和getter方法等信息,方便進(jìn)行對(duì)象的序列化與反序列化操作。

????????在我們平時(shí)的項(xiàng)目開(kāi)發(fā)過(guò)程中,基本上很少會(huì)直接使用到反射機(jī)制,但這不能說(shuō)明反射機(jī)制沒(méi)有用,實(shí)際上有很多設(shè)計(jì)、開(kāi)發(fā)都與反射機(jī)制有關(guān),例如模塊化的開(kāi)發(fā),通過(guò)反射去調(diào)用對(duì)應(yīng)的字節(jié)碼;動(dòng)態(tài)代理設(shè)計(jì)模式也采用了反射機(jī)制,還有我們?nèi)粘J褂玫?Spring/Hibernate 等框架,也是利用CGLIB 反射機(jī)制才得以實(shí)現(xiàn),下面就舉例最常見(jiàn)的兩個(gè)例子,來(lái)說(shuō)明反射機(jī)制的強(qiáng)大之處:

  • JDBC 的數(shù)據(jù)庫(kù)的連接

在JDBC 的操作中,如果要想進(jìn)行數(shù)據(jù)庫(kù)的連接,則必須按照以上的幾步完成

  1. 通過(guò)Class.forName()加載數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序 (通過(guò)反射加載,前提是引入相關(guān)了Jar包)
  2. 通過(guò) DriverManager 類(lèi)進(jìn)行數(shù)據(jù)庫(kù)的連接,連接的時(shí)候要輸入數(shù)據(jù)庫(kù)的連接地址、用戶(hù)名、密碼
  3. 通過(guò)Connection 接口接收連接
public class ConnectionJDBC {  /** * @param args */  //驅(qū)動(dòng)程序就是之前在classpath中配置的JDBC的驅(qū)動(dòng)程序的JAR 包中  public static final String DBDRIVER = "com.mysql.jdbc.Driver";  //連接地址是由各個(gè)數(shù)據(jù)庫(kù)生產(chǎn)商單獨(dú)提供的,所以需要單獨(dú)記住  public static final String DBURL = "jdbc:mysql://localhost:3306/test";  //連接數(shù)據(jù)庫(kù)的用戶(hù)名  public static final String DBUSER = "root";  //連接數(shù)據(jù)庫(kù)的密碼  public static final String DBPASS = "";  public static void main(String[] args) throws Exception {  Connection con = null; //表示數(shù)據(jù)庫(kù)的連接對(duì)象  Class.forName(DBDRIVER); //1、使用CLASS 類(lèi)加載驅(qū)動(dòng)程序 ,反射機(jī)制的體現(xiàn) con = DriverManager.getConnection(DBURL,DBUSER,DBPASS); //2、連接數(shù)據(jù)庫(kù)  System.out.println(con);  con.close(); // 3、關(guān)閉數(shù)據(jù)庫(kù)  }  
  • Spring 框架的使用

??在 Java的反射機(jī)制在做基礎(chǔ)框架的時(shí)候非常有用,行內(nèi)有一句這樣的老話(huà):反射機(jī)制是Java框架的基石。一般應(yīng)用層面很少用,不過(guò)這種東西,現(xiàn)在很多開(kāi)源框架基本都已經(jīng)封裝好了,自己基本用不著寫(xiě)。典型的除了hibernate之外,還有spring也用到很多反射機(jī)制。最經(jīng)典的就是xml的配置模式。

Spring 通過(guò) XML 配置模式裝載 Bean 的過(guò)程:

  • 將程序內(nèi)所有 XML 或 Properties 配置文件加載入內(nèi)存中
  • Java類(lèi)里面解析xml或properties里面的內(nèi)容,得到對(duì)應(yīng)實(shí)體類(lèi)的字節(jié)碼字符串以及相關(guān)的屬性信息
  • 使用反射機(jī)制,根據(jù)這個(gè)字符串獲得某個(gè)類(lèi)的Class實(shí)例
  • 動(dòng)態(tài)配置實(shí)例的屬性


Spring這樣做的好處是:

  • 不用每一次都要在代碼里面去new或者做其他的事情
  • 以后要改的話(huà)直接改配置文件,代碼維護(hù)起來(lái)就很方便了
  • 有時(shí)為了適應(yīng)某些需求,Java類(lèi)里面不一定能直接調(diào)用另外的方法,可以通過(guò)反射機(jī)制來(lái)實(shí)現(xiàn)

模擬 Spring 加載 XML 配置文件:

public class BeanFactory {private Map<String, Object> beanMap = new HashMap<String, Object>();/*** bean工廠的初始化.* @param xml xml配置文件*/public void init(String xml) {try {//讀取指定的配置文件SAXReader reader = new SAXReader();ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//從class目錄下獲取指定的xml文件InputStream ins = classLoader.getResourceAsStream(xml);Document doc = reader.read(ins);Element root = doc.getRootElement();  Element foo;//遍歷beanfor (Iterator i = root.elementIterator("bean"); i.hasNext();) {  foo = (Element) i.next();//獲取bean的屬性id和classAttribute id = foo.attribute("id");  Attribute cls = foo.attribute("class");//利用Java反射機(jī)制,通過(guò)class的名稱(chēng)獲取Class對(duì)象Class bean = Class.forName(cls.getText());//獲取對(duì)應(yīng)class的信息java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);//獲取其屬性描述java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();//設(shè)置值的方法Method mSet = null;//創(chuàng)建一個(gè)對(duì)象Object obj = bean.newInstance();//遍歷該bean的property屬性for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {  Element foo2 = (Element) ite.next();//獲取該property的name屬性Attribute name = foo2.attribute("name");String value = null;//獲取該property的子元素value的值for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {Element node = (Element) ite1.next();value = node.getText();break;}for (int k = 0; k < pd.length; k++) {if (pd[k].getName().equalsIgnoreCase(name.getText())) {mSet = pd[k].getWriteMethod();//利用Java的反射極致調(diào)用對(duì)象的某個(gè)set方法,并將值設(shè)置進(jìn)去mSet.invoke(obj, value);}}}//將對(duì)象放入beanMap中,其中key為id值,value為對(duì)象beanMap.put(id.getText(), obj);}} catch (Exception e) {System.out.println(e.toString());}}//other codes
}

http://m.risenshineclean.com/news/64551.html

相關(guān)文章:

  • 國(guó)外有哪些網(wǎng)站做推廣的比較好黃頁(yè)88網(wǎng)站推廣方案
  • 網(wǎng)站制作專(zhuān)業(yè)的公司叫什么win優(yōu)化大師有用嗎
  • 云南網(wǎng)絡(luò)公司網(wǎng)站萬(wàn)能瀏覽器
  • wordpress for bae哪里搜索引擎優(yōu)化好
  • 網(wǎng)站需要做實(shí)名認(rèn)證如何做優(yōu)化大師百科
  • 網(wǎng)站制作b s的基本步驟百度公司電話(huà)
  • 手機(jī)版網(wǎng)站模板網(wǎng)頁(yè)優(yōu)化最為重要的內(nèi)容是
  • 京東電子商務(wù)網(wǎng)站建設(shè)目的愛(ài)站站長(zhǎng)工具
  • 雅思真題有網(wǎng)站做嗎網(wǎng)絡(luò)培訓(xùn)機(jī)構(gòu)排名前十
  • 網(wǎng)站開(kāi)發(fā)注銷(xiāo)代碼搜索引擎營(yíng)銷(xiāo)的常見(jiàn)方式
  • 常州做的網(wǎng)站的公司哪家好投稿平臺(tái)
  • 手機(jī)網(wǎng)站進(jìn)不去怎么辦推廣項(xiàng)目
  • 廣州外貿(mào)公司聯(lián)系方式刷seo關(guān)鍵詞排名軟件
  • 寧夏網(wǎng)站建設(shè)優(yōu)化蘭州網(wǎng)絡(luò)推廣優(yōu)化服務(wù)
  • 做賭博網(wǎng)站危險(xiǎn)嗎怎么弄一個(gè)自己的鏈接
  • 先用ps后用dw做網(wǎng)站私域流量營(yíng)銷(xiāo)
  • 答題做任務(wù)網(wǎng)站查網(wǎng)站流量查詢(xún)工具
  • 龍崗沙灣社區(qū)網(wǎng)站建設(shè)邵陽(yáng)網(wǎng)站seo
  • 浦東企業(yè)網(wǎng)站建設(shè)網(wǎng)盟推廣是什么意思
  • 做網(wǎng)站基本教程關(guān)鍵詞推廣seo
  • 重慶做網(wǎng)站有哪些seo泛目錄培訓(xùn)
  • 網(wǎng)站后臺(tái)管理頁(yè)面模板國(guó)際新聞網(wǎng)站
  • 1建設(shè)網(wǎng)站的重要性win7優(yōu)化工具
  • 怎樣做自己的小說(shuō)網(wǎng)站外貿(mào)營(yíng)銷(xiāo)型網(wǎng)站建設(shè)公司
  • 全面的網(wǎng)站建設(shè)免費(fèi)sem工具
  • 慈善系統(tǒng)網(wǎng)站建設(shè)需求網(wǎng)站建設(shè)教程
  • 快速學(xué)制作網(wǎng)站百度小說(shuō)排行榜第一名
  • wordpress 導(dǎo)航站模板營(yíng)銷(xiāo)型網(wǎng)站建設(shè)論文
  • 布偶貓網(wǎng)頁(yè)設(shè)計(jì)教程百度seo入駐
  • 注冊(cè)網(wǎng)站頁(yè)面跳轉(zhuǎn)錯(cuò)誤惠州seo排名優(yōu)化