當前位置:首頁 » 硬碟大全 » 緩存機制應用
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

緩存機制應用

發布時間: 2023-01-13 06:15:23

1. php 中如何使用緩存,使用哪種緩存機制最好;

php的緩存三種.有文件緩存,資料庫緩存,memcache緩存;
memcache緩存要求對伺服器支持,而且它的緩存是由期限的,一般是30天。這種緩存的效率是最高的。讀存取的速度最快。
資料庫緩存

文件緩存比較簡單。適用小的項目。和php新手

2. 資料庫緩存機制是什麼緩存是如何作用資料庫

緩存的介質一般是內存,所以讀寫速度很快。但如果緩存中存放的數據量非常大時,也會用硬碟作為緩存介質。緩存的實現不僅僅要考慮存儲的介質,還要考慮到管理緩存的並發訪問和緩存數據的生命周期。

3. 談談RecyclerView中的緩存

Android深入理解RecyclerView的緩存機制

RecyclerView在項目中的使用已經很普遍了,可以說是項目中最高頻使用的一個控制項了。除了布局靈活性、豐富的動畫,RecyclerView還有優秀的緩存機制,本文嘗試通過源碼深入了解一下RecyclerView中的緩存機制。

RecyclerView做性能優化要說復雜也復雜,比如說布局優化,緩存,預載入等等。其優化的點很多,在這些看似獨立的點之間,其實存在一個樞紐:Adapter。因為所有的ViewHolder的創建和內容的綁定都需要經過Adaper的兩個函數onCreateViewHolder和onBindViewHolder。

因此我們性能優化的本質就是要減少這兩個函數的調用時間和調用的次數。如果我們想對RecyclerView做性能優化,必須清楚的了解到我們的每一步操作背後,onCreateViewHolder和onBindViewHolder調用了多少次。因此,了解RecyclerView的緩存機制是RecyclerView性能優化的基礎。

為了理解緩存的應用場景,本文首先會簡單介紹一下RecyclerView的繪制原理,然後再分析其緩存實現原理。

RecyclerView滑動時會觸發onTouchEvent#onMove,回收及復用ViewHolder在這里就會開始。我們知道設置RecyclerView時需要設置LayoutManager,LayoutManager負責RecyclerView的布局,包含對ItemView的獲取與復用。以LinearLayoutManager為例,當RecyclerView重新布局時會依次執行下面幾個方法:

上述的整個調用鏈:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是從RecyclerView的回收機制實現類Recycler中獲取合適的View,下面主要就來從看這個Recycler#getViewForPosition()的實現。

上述邏輯用流程圖表示:

RecyclerView在Recyler裡面實現ViewHolder的緩存,Recycler裡面的實現緩存的主要包含以下5個對象:

public final class Recycler {

final ArrayList mAttachedScrap = new ArrayList<>();

ArrayList mChangedScrap = null;

RecyclerView在設計的時候講上述5個緩存對象分為了3級。每次創建ViewHolder的時候,會按照優先順序依次查詢緩存創建ViewHolder。每次講ViewHolder緩存到Recycler緩存的時候,也會按照優先順序依次緩存進去。三級緩存分別是:

使用自定義ViewCacheExtension後,view離屏後再回來不會走onBindViewHolder()方法。

holder.setIsRecyclable(false),這樣的話每次都會走onCreateViewHolder()和onBindViewHolder()方法

1.提前初始化viewHolder,放到緩存池中

viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))

2.提前初始化view,在onCreateViewHolder的時候去取view

3.自定義ViewCacheExtension

4.適當的增加cacheSize

4.公用緩存池,比如多個viewPager+fragment場景使用,或者全局單利緩存池,感覺用戶不大。

有2中做法有值

第一種

第二種

不會,因為prefetch(GapWorker中的一個方法)之後mViewCacheMax會變成mRequestedCacheMax + extraCache

有2種方式可以讓緩存失效

第一種

recyclerView.setItemViewCacheSize(-1)

第二種

recyclerView.setItemViewCacheSize(0)

layoutManager.isItemPrefetchEnabled = false

設置不緩存後,來回滑動讓view進入屏幕離開屏幕,viewHolder的item時會多次走onBindViewHolder()方法。

4. 求生之路系列(一)瀏覽器緩存機制

http可以說是現在前端領域(甚至整個互聯網)發展過程中使用最多的一個應用層協議。其傳輸層一般都是使用tcp協議來保證可靠傳輸的,由於tcp3次握手以及4次揮手的鏈接建立與斷開機制,導致每一次進行http請求所消耗的網路資源相對較大。。所以減少請求次數,合理的數據緩存成為互聯網開發的重中之重!!

尤其在前端領域,http緩存在加快網頁性能和為用戶節約網路資源。作為一名小前端,又恰好面試的時候又被問蒙蔽了。。就在這里對http緩存機制進行一個小小的總結吧~~

總的來說,瀏覽器要從伺服器上面真正的拿到數據還要通過下面幾關:

Cache-control是http響應頭的一個欄位。就是用來與客戶端約定響應的數據的緩存的有效時間。

在上圖中可以發現Cache-Control有一個max-age=691200的參數。這個就是表示該資源的最大生存時間為691200秒。 在這個時間過後才會再次向伺服器發出請求申請新的資源 ,否則直接使用本地資源。不過,就算生存時間過了,伺服器不會這么溫順地給你發新的資源(你說發就發豈不是很丟臉???),還會進一步的進行判斷,是否應該發送新的資源(看到後面就知道啦~)

除了max-age之外,Cache-Control還有別的參數可以選擇:

另外,瀏覽器的不同行為例如enter f5也會有不同的表現哦。(這個後面再總結吧~)

更多的介紹可以看看下面網路和幾位老哥的總結:

眼尖的盆友,可能會發現 上面的圖中還有一個Expires欄位,有些還有Pragma,其實這兩個都是個http1.0的舊產物,跟Cache-Control設置max-age是一個意思。由於Cache-Control是http1.1提出的,而且在http1.1甚至http2.0大行其道的今日,這兩個東西已經沒有作用了。當Cache-Control和上面兩個東西同時在http頭中存在時,優先使用Cache-Control。

注意:瀏覽器要發出請求必須要先在max-age時間過後(可以用ctrl+F5,來跳過這個檢查)。如果在一個時間內在發出請求,chrome的network會返回一個假200(其實是讀緩存的假請求2333333)。

一句話總結:Cache-Control是一個用於控制(告訴)客戶端,該響應的資源應該存哪裡,存多久。

當瀏覽器發現max-age(或其他)時間過後 ,瀏覽器就開始向伺服器請求獲取新的資源。但是伺服器並不會輕易的把新的資源返回給客戶端。

當瀏覽器第一次訪問某個網站,請求伺服器時,伺服器在返回的http響應頭中加入Last-Modified欄位,故名思意表示該資源最後一次修改是在某一個時間,如下圖

瀏覽器在收到了Last-Modified後,在以後的每一次請求中(請求頭)都會帶上一個欄位If-Modified-Since,這個欄位的值就是上一次收到的Last-Modified的值。

伺服器端則根據查看該資源是否在這個時間點後被修改過!!~如果沒有被修改過,則伺服器會返回304,表示資源未被修改過,使用緩存就可以了。否則如果有Etag則進行下一步判斷(後面說),沒有則200返回新資源。

Last-Modified 表面上非常靠譜,但是也存在一種情況,如果在伺服器上,一個資源被修改了,但其實際內容根本沒發生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)。

ETag是http1.1中為了解決上面問題的一個http欄位(一般是在響應頭裡面的)。這個ETag的值的什麼呢?一般是由伺服器根據資源的內容通過md5(或者其他)計算出的一個唯一標志。ok,瀏覽器得到這個東西之後,每次請求該資源的時候就會帶上這個值,這個值是放在請求頭的if-None-Match中,表示如果不匹配就給我新的吧,匹配就返回304~~

還有這個if-Match,這個我就不是很理解到底是什麼意思了。。。知道的朋友可以告訴我一下。。。
什麼是412錯誤,先決條件失敗是什麼意思。。

最後盜個圖:

另外,瀏覽器有多個刷新頁面的方法,下面來看看對緩存來說都有什麼區別吧(用chrome來測試,據說不同瀏覽器不同哦~):

從上面圖中可以看出,這種形式的刷新頁面,是會判斷過期的(max-age)。。就是說是按整個緩存流程走下去。。

哇 好多304。。說明F5刷新頁面跳過了過期判斷(包括了max-age、expire等等),直接從ETage開始。。

全部200!!說明 這個是真·強刷·無雙!!從請求頭的圖中,可以看到瀏覽器是同配置Cache-Control: no-cache來叫伺服器重發請求的!~

第一次寫博客,各位老哥,給個面子,有錯就提出來哈~~

by the offer, of the offer, for the offer!!~~~

相關參考:

5. 緩存機制是一種常用的平滑切換方法

是的。緩存機制是屬於一種常用的平滑切換方法的。緩存機制是介於應用程序和物理數據源之間,其作用是為了降低應用程序對物理數據源訪問的頻次,從而提高了應用的運行性能。

6. 來了解 Github 當前最火開源項目 RecyclerView 的緩存機制

最近在網上看到許多關於 RecyclerView 緩存相關的技術文章,也是在其中看到了許多的知識點,我將之收集了起來進行匯總和整理,利用自己的見解來分析 RecyclerView 的緩存機制的相關問題

首先 RecyclerView 是由 Google 推出來對 GridView 和 ListView 進行取代的列表方案,RecyclerView 本身它是不關心視圖相關的問題的,由於 ListView的緊耦合的問題, google 的改進就是 RecyclerView 自身不用參與任何視圖有關的問題,它不用在意應該將子 View 放在合適的位置,也不在意如何進行分割這些子 View,更不在意每個子View所顯示的外觀,本質上來說就是 RecyclerView 它只負責回收和重用的工作

● 能夠替代 Listview 和 GridView ,不僅可以載入列表同時也能夠載入表格

● 能夠支持瀑布流這種高級的顯示方式

● 內置了強勁的垃圾回收機制

● 規范了其 Viewholder 的使用

在 RecyclerView 中,是沒有 onItemClickListener 方法的,所以只能在適配器中處理事件,如果要從適配器上添加或移除條目,就必須要明確通知適配器。這跟先前的 notifyDataSetChanged 方法有略微不同

整體總結了幾點如下:

● Adapter:包裝數據集合且為每個條目創建視圖

● ViewHolder:對每個用於顯示數據條目的子View進行保存

● LayoutManager:在適當的位置放置於每個條目的視圖

● ItemDecoration:繪制一些裝飾視圖在每個條目的視圖的周圍或上面

● ItemAnimator:在條目被添加、移除或者重排序時對其添加動畫效果

RecyclerView 的緩存可以分為四級,也有的人將之分成三級,但大致的理解是一樣的

● mAttachedScrap 和 mChangedScrap ,用來緩存其還在屏幕內的 ViewHolder

● mAttachedScrap 對當前還在屏幕中的 ViewHolder進行存儲;從 id 和 position 來對 ViewHolder進行查找

● mChangedScrap 表達數據已經改變的 ViewHolder 列表, 存儲 notifyXXX 方法時必須對 ViewHolder進行改變

● mCachedViews ,是用來緩存移除屏幕之外的 ViewHolder,通常其緩存容量是 2,但可以通過 setViewCacheSize 方法來改變緩存的容量大小,假如mCachedViews 的容量已滿,那麼則會根據 FIFO 其中的規則來對舊 ViewHolder 進行移除處理

● ViewCacheExtension ,是開發給用戶的自定義擴展緩存,是需要用戶自己管理 View 的創建和緩存

● RecycledViewPool ,ViewHolder 緩存池,如果在有限的 mCachedViews 中存不下新的 ViewHolder 時,那麼就會把 ViewHolder 存入RecyclerViewPool 中

● 根據 Type 來對進行 ViewHolder 查找

● 每個 Type 基本上默認最多緩存 5 個

● 具有可以多個 RecyclerView 共享 RecycledViewPool

onCreateViewHolder 用於對 item.xml 進行機芯實例化,並會以 ViewHolder 的形式呈現

onBindViewHolder 致用在初始和滑動 RecyclerView 時,給予item裡面的子控制項賦值

在我的理解中, onCreateViewHolde r和 onBindViewHolder 加起來就類似於 ListView adapter 裡面的

雖然getView()裡面既有parent可以用來實例化 item.xml ,又有 position 可以找到item位置來賦值,但是本質上還是如同 onCreateViewHolder 和 onBindViewHolder 的功能!

差異區別就只是在item的表示形式從View變成了 ViewHolder

以上就是關於 RecyclerView 緩存的所有內容

關於RecyclerView的緩存,總的來說,Scrap是屏幕內的緩存一般我們不怎麼需要特別注意;Cache可直接拿來復用的緩存,性能高效

ViewCacheExtension 需要開發者自定義的緩存,API設計比較奇怪,慎用

RecycledViewPool 四級緩存,可以避免用戶調用onCreateViewHolder 方法,提高性能,在 ViewPager+RecyclerView 的應用場景下可以大有作為

如果喜歡文章中的內容歡迎大家點贊和評論,你們的鼓勵將是我前進的動力

有需要文章中的源碼,或者想要了解更多關於Android開發相關的進階資料

歡迎大家在評論區下發留言,或者私信我

7. 什麼是緩存機制

緩存是介於應用程序和物理數據源之間,其作用是為了降低應用程序對物理數據源訪問的頻次,從而提高了應用的運行性能。緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。
緩存的介質一般是內存,所以讀寫速度很快。但如果緩存中存放的數據量非常大時,也會用硬碟作為緩存介質。緩存的實現不僅僅要考慮存儲的介質,還要考慮到管理緩存的並發訪問和緩存數據的生命周期。
Hibernate的緩存包括Session的緩存和SessionFactory的緩存,其中SessionFactory的緩存又可以分為兩類:內置緩存和外置緩存。Session的緩存是內置的,不能被卸載,也被稱為Hibernate的第一級緩存。SessionFactory的內置緩存和Session的緩存在實現方式上比較相似,前者是SessionFactory對象的一些集合屬性包含的數據,後者是指Session的一些集合屬性包含的數據。SessionFactory的內置緩存中存放了映射元數據和預定義SQL語句,映射元數據是映射文件中數據的拷貝,而預定義SQL語句是在Hibernate初始化階段根據映射元數據推導出來,SessionFactory的內置緩存是只讀的,應用程序不能修改緩存中的映射元數據和預定義SQL語句,因此SessionFactory不需要進行內置緩存與映射文件的同步。SessionFactory的外置緩存是一個可配置的插件。在默認情況下,SessionFactory不會啟用這個插件。外置緩存的數據是資料庫數據的拷貝,外置緩存的介質可以是內存或者硬碟。SessionFactory的外置緩存也被稱為Hibernate的第二級緩存。

8. APP中緩存、載入與刷新機制設計【轉載】

1、為什麼要加緩存?

場景一:【等待】,在向伺服器請求新的數據時。我們讓用戶看到什麼?第一種是漂亮的等待載入頁面;第二種是緩存的內容。對於第二種,用戶可以對頁面進行操作,等待新數據時可以查看舊數據,更具有「可操作性」與「可用性」,從而減輕了從伺服器獲取數據這一動作的大小和時間長短,增強了用戶體驗。另一方面,如果內容更新的間隔較長或者用戶刷新的間隔較短,在沒有緩存的情況下,很多數據我們會多次重復的向伺服器獲取,增加了成本。

場景二:【結果】沒有聯網,或者在地鐵上網路太差無法載入數據時,如果留給用戶一個空白頁面,實在是感覺有點不負責任啊。並且很多功能在沒有聯網的情況下也有使用的可能性,比如:APP中的通訊錄,查看一些聊天記錄,通知信息,文章列表等。因為用戶打開APP不一定是要看新信息,說不定是回顧老信息(或許老信息里也有用戶之前沒看的),所以恰當的緩存可以滿足更多的用戶場景。

場景三:【金錢】有一天,一個用戶發現自己裝了某個APP後流量用的特別快,Ta可能永遠將這個APP打入冷宮了,而增加緩存正是節省流量的一個方法。雖然節省的不多或者用戶也察覺不到,但是作為一個有態度的產品經理,應該多做一些思考。

2、什麼是緩存?

緩存可分為如下幾類:

(1)app緩存。

(2)固定緩存。

(3)可手動清理的緩存。

(4)不可手動清理的緩存。

(5)臨時緩存。

其中,臨時緩存常用於一個功能頁面內,保存各欄目的緩存。同一個功能里會把子功能分為多個欄目進行劃分,每個標簽欄目下的內容在本次使用中都可保存為臨時緩存,在該功能里切換欄目,不需要重新載入數據,使用緩存顯示。

對於用戶來說,使用時達到了無縫切換瀏覽,對於伺服器來說,在短時間內數據很少會有更新,所以在一般情況下能滿足用戶的正常需求,並達到體驗優秀。

臨時緩存的清理機制是:退出該功能模塊就清除之前的緩存。也就是說下次進入該功能模塊,需要重新獲取一次數據。

很多時候我們都會用到臨時緩存,因為那些信息真的不是那麼重要,而且不需要經常反復查看,那對於那些我們經常使用而且經常需要反復查看的信息,馬海祥建議採取固定緩存,保存在本地,方便下次翻閱時不需要再一次向伺服器請求數據了。

對於固定緩存又會細分為可手動清理的緩存和不可手動清理的緩存。

第一種是我們最常見的緩存,幾乎所有產品都採用這種緩存方式。平時用戶瀏覽文章、圖集載入的數據就以這種形式緩存在本地,下次看回這篇文章、圖集時就不需要載入了。用戶也可以手動把這些緩存清理了,釋放空間。

而對於某些特殊場景,例如一些相對固定的數據,我們不願意一開始就打包進App里,這樣會占太大容量,造成產品包很大,也不願意每次進入頁面都向伺服器載入這些信息,那怎麼辦?建議的解決方法就是我們可以只載入一次就永遠存在本地了,這樣安裝包也不會大,以後也不用載入了。

3、如何清理緩存?

一般App都會在「設置」里提供一個清理緩存的功能,一鍵把空間釋放。除此之外,App最好要設計自動清理機制,可以通過兩個維度來設計這個機制。

(1)、時間

通過設定一個固定的時間,或者根據用戶使用周期靈活設定時間來清理緩存。每個產品的場景不一,用戶使用頻率不一,設定這個機制的時候就需要結合實際情況考慮了。

(2)、容量

一般是設定一個容量上限,採用堆棧的設計原理進行緩存清理,溢出堆棧的舊數據將自動清除。

1、頁面載入

方案1:單頁面整體載入

這種載入比較簡單,一般運用在頁面內容比較單一的情況下,所以直接一次性載入完所有數據後再顯示內容。其單頁面載入失敗的狀態相對來說也比較好處理。

方案2:單頁面分塊載入

這種方案的特點是,能讓用戶逐步看到內容,在這個漸進的過程中降低用戶的焦慮心理。

其中又可以分為,模塊間有關聯性的,先載入父內容,再載入子內容。如優酷,先把欄目載入出來,再載入各欄目的內容。

模塊間沒有絕對關聯性的,可獨自載入各自模塊內容,根據請求的速度不同分別顯示。這樣處理有一定幾率讓用戶在沒完全刷出數據的情況下就能找到自己需要的功能,如大眾點評、淘寶客戶端等。

框架固定,內容更新的,可先把框架顯示出來,再把各模塊的數據各自載入顯示,如各種iOS自帶應用。

這種分模塊載入的需要特別注意載入失敗的狀態,畢竟每個模塊都提示載入失敗,點擊重試是很挫的一件事,可以根據信息的優先順序來決定哪些數據失敗了採用默認狀態,哪些數據採用失敗提示。

方案3:跨頁面載入

父頁面&子頁面 or 同一app內,頁面間欄位可以復用的,在載入子頁面時不需要重新載入新數據。

方案4:預載入

這種載入方式的特點是,在載入一個頁面內容的同時,預測用戶的下一步行為,並為他下一步需要使用的頁面載入內容,使得他在下一步的操作中能立刻獲取信息而不需要載入等待。

預載入提供給用戶無縫的產品使用體驗,使得用戶在使用產品的過程中更直接流暢,沒有被打斷的感覺。

具體的例子有:

在瀏覽圖集的時候,當看到第一張的圖片時,就自動後台載入第二第三第四張圖片,用戶瀏覽完第一張圖片切換到第二張時就不會有載入等待的過程。

在瀏覽新聞列表時,就把每篇新聞的內容在後台進行預載入,用戶選擇看某篇新聞時,能立刻閱讀到內容。

但是這種方案也需要面臨很多的問題,馬海祥覺得最直接的就是流量問題,因為會自動跑掉很多用戶可能根本用不上的數據流量,所以,一般情況下馬海祥建議可以設定在wifi環境才採用這種載入模式。又或者設定載入規則,只把主要內容預載入,而部分次要內容可以在用戶真的用到的時候才載入,例如預載入新聞正文的情況,可以只載入文本信息,圖片信息等到用戶進入內頁才載入。這種預載入與分塊載入結合的方式也普遍運用在各個場景。

另外,預載入也需要時間的,他只是不在客戶端顯示給用戶,默默在後台運作而已,需要特殊考慮未載入完用戶就使用到那些信息的情況,所以在做預載入設計時需要同時考慮另一種適合該情況的普通載入方式。

預載入需要根據具體的場景來進行設計,設定好信息優先順序,綜合考慮各種類型信息的具體大小流量,整體考慮預載入的方式,這些都是需要經過精心分析思考的。

隨著網路環境的發展,預載入將成為以後產品普遍的載入方式,他提供給用戶的無縫使用體驗**地提升了產品的可用性。

2、操作載入

除了頁面的信息需要載入,頁面內的操作也是需要通過給伺服器發送請求記錄的。

方案1:載入層

進行一個操作後,彈出模態的提示層,告知用戶正在載入。採用模態的提示主要是防止用戶在該過程中進行其他操作,導致當前載入出錯。由於採用模態的提示,並且有可能因為網路原因導致長時間處於載入狀態,建議提供一個「關閉」的操作,中止本次載入,恢復App可用狀態。載入失敗時可在當前浮層變換為失敗提示。模態提示層是最穩妥的方式,但他會使用戶在使用過程中有打斷的感覺。

方案2:控制項自身載入狀態

這種方式是把操作載入的狀態與控制項的樣式結合起來了,對某個控制項進行操作後,控制項變換為載入狀態,此時控制項不能重復操作。由於這種載入方式是控制項的自身狀態,不影響其他操作,所以用戶也可以對頁面進行其他操作,可能會導致同時有多個請求的情況,增加了載入失敗的風險,這也算是這種方式的弊端,不過這種極端情況很少出現。請求失敗後,可配合Toast提示告知用戶失敗的原因。

方案3:後台載入

用戶在操作後,客戶端立刻反饋操作成功,然後把請求放到後台與伺服器交互,這一過程用戶不需要了解,不需要等待,在正常情況**驗是非常棒的。

但是在極端情況下會出現一些莫名其妙的狀況,由於是後台記錄請求並與伺服器交互,所以實際請求是否成功客戶端是不說明的,全部以操作成功來顯示,這就會導致用戶誤以為操作成功了,但實際上下次來看發現沒有成功。

所以,這種載入方式是需要根據具體使用場景來權衡使用的,對於一些重要的操作,建議還是使用模態的方式載入,對於一些小操作,如點贊、訂閱、關注,可採用後台載入的方式。

3、下一頁載入還是當前也載入

用戶進入首頁,正式邁出體驗的第一步,接下來迎接的就是基於用戶目標的界面間跳轉。完成界面的跳轉,會有各種載入策略,但無論形式如何,我們都可以將其歸為兩大類:「下一頁載入」、「當前頁載入」。

(1)「下一頁載入」滿足了用戶提前窺視的需求

我們把頁面看成「點」,頁面流是連接這些點的「線」,我們以「用戶想買一條牛仔褲」這一場景作為案例做了簡單的眼動研究,從應用啟動到商品瀏覽再到商品確定最後進入下單頁,用戶所呈現的瞳孔梯次增大,即E>D>C>B>A,為了解釋這一現象,通過與被試交流,我們發現相比於各種瀏覽,用戶更期待看到他們想看到的東西。因此此時的」下一頁載入「正好,滿足了用戶提前窺視的需求。

(2) Wait!I Need Think Think

我們以同樣的方式又對「使用支付寶對手機充值」這一場景做了研究,從開始支付到二次確認支付,用戶所呈現的瞳孔都比較大,即A與B近似相等,通過訪談,我們發現與「遞增體驗流」不同的是,當用戶遇到判斷邏輯的界面時,用戶並非急於想看下一頁面到底包含怎樣的內容,而是非0即1的驗證心態,即我的操作效成功了嗎?因此在判斷邏輯界面中,用戶的內容窺視需求並不強,當然也沒什麼內容,要麼僅是一個小小的Toast,再大一點就是一個簡單的信息反饋界面(意味著「下一頁載入」在這里就是個雞肋),用戶反而對非0即1的驗證需求較為強烈,其中還伴隨著等待結果過程中的緊張感、激動感,因此界面通過 當前頁載入 表明系統正在努力地處理用戶交代的指令**了用戶的緊張感、激動感,直到結果顯現——「處理成功」,完成了非0即1驗證的滿足感。

4、先載入還是先展示

當需載入的是功能時,可以先展示再載入,當需載入的是內容時,則反過來。

淘寶

打開APP的第一個頁面是功能,所以先展示再載入的:

隨便點擊一個模塊(不要點菜單),下面要展示的將要是內容(商品),所以是先載入再展示的,沒有載入完都不展示:

京東

同樣的,功能模塊先展示後載入:

內容先載入,沒載入完不展示:

兩種方式各有利弊:

先展示,後載入:

優點:給用戶0等待的錯覺

缺點:當前數據有可能是錯的,而且得等用戶操作到最後一步才會發現

先載入,後展示:

優點:保證數據的質量和准確

缺點:網路不好時,造成等待

顯然,功能模塊對於一個產品來說是既有固定的,在短時間內幾乎不會更新,所以這種數據出現錯誤或與當前狀態不同的幾率小得多,因此,可以使用先展示後載入的方式。

另一方面,內容(特別是商品數據)是最容易產生變動的,為了保證每一個消費者看到的數據都是最真實,最准確的,所以務必要先載入再展示。

1、空白頁面刷新失敗有提示

現在的應用都標榜以內容為中心,所以都會極力避免空白頁面的出現。對於大部分的應用,最好的方法就是使用緩存,進入頁面之後,先顯示之前的緩存,然後再進行內容的刷新。其次,消滅空白頁面的第二種方法就是提供系統推薦項進行替代。但是對於一些頁面,頁面內容跟用戶的使用狀態關系密切,無法避免會出現空白頁面,這時候會使用一些引導類的提示,使得頁面變得更加豐富,同時可以促進用戶產生內容。

但是一些資訊類應用,比如讀讀日報,打開默認是空白頁面,然後再載入內容(我不是很明白這種設定)。其他一些應用,比如:豆瓣一刻和MONO,每天第一次進入應用的時候也會出現空白頁面。我猜想第二類應用的展示方式的原因是這樣的。他們的內容**都是嚴格以天為單位的,每天固定時段**精選內容。他們會希望你每天只看並且看完當天的東西,所以一旦到了第二天,昨天的內容就是累贅了。所以每天第一次進入應用的時候會出現空白頁面,象徵著每天都是從新開始。此時就會對應一個「空白刷新」邏輯。

空白刷新對應的場景是這樣子的:用戶想要刷新出內容,並且用戶知道這里可以刷出新內容,但是沒有刷新成功,這時候需要給用戶一個交待。所以需要提示用戶。同時,提示完用戶之後需要給用戶一個解決方法,這就是「點擊後重試」。

2、緩存頁面刷新失敗無提示

常見的應用比如知乎、網易新聞、好奇心日報、微信朋友圈等,這些應用都會採用緩存的形式,打開之後顯示的是緩存內容,然後系統會給伺服器發送請求,如果有內容更新的話就會自動更新一次內容,更新之後的內容直接覆蓋當前的內容。更新失敗之後是沒有提示的。但是有一些應用,比如有道詞典、企鵝FM、網易雲音樂等,他們更新失敗之後是有提示的。

我覺得這兩種應用的區分點在於

應用的使用頻率;

內容的時間連續性;

界面之間的關系緊密度。

比如說網易新聞,作為一個打發時間的工具,每天使用頻率就會比較高,所以用戶進來之後是想看看有沒有更新。其次,網易新聞的內容是連續不斷更新的,所以用戶會知道當前顯示的內容是我看看過並且處理過的。最後,新聞列表頁面顯示的是摘要,用戶可以通過摘要快速進行判斷是否要進入詳情頁,摘要有助於幫助用戶回憶上一次的使用場景。

所以這就對應著一個這樣的場景:用戶只是想看看有沒有更新,所以他們已經做好了「沒有新內容」的心理預期,所以即使是更新不了內容,用戶也不會想太多。反倒是,如果進行了錯誤提示,用戶可能會有一種挫敗感。因為他知道現在有內容,只是因為網路的原因而沒有更新,他要進行的任務受到了外界因素的阻礙,由此產生一種細微的挫敗感。

3、緩存頁面刷新失敗有提示

另一類應用,使用頻率沒那麼高,或者內容不具備時間連續性的,又或者說當前界面無法喚起用戶上一次的使用場景。那麼就有必要進行率先你失敗提示了。

比如說企鵝FM,音頻類的應用註定使用不會那麼頻繁,因為通過視覺接收的信息會比通過聽覺接收的信息更快更多,同時音頻類對環境的要求較高(比如用耳機時要求環境不那麼嘈雜,外放時要求在私人場所)。其次,此類應用都是實時推薦的,不存在時間連續性的問題,用戶無法通過時間來判斷內容是否被閱讀過。再者,標題也無法幫你快速做出判斷,你還是要進去聽過才知道內容是什麼。最後如果不提醒,用戶進入到詳情頁再收到提醒,就會覺得應用浪費了用戶的時間。所以,對於此類內容,刷新失敗是有必要進行提醒的。

9. 華為技術架構師分享:高並發場景下緩存處理的一些思路

在實際的開發當中,我們經常需要進行磁碟數據的讀取和搜索,因此經常會有出現從資料庫讀取數據的場景出現。但是當數據訪問量次數增大的時候,過多的磁碟讀取可能會最終成為整個系統的性能瓶頸,甚至是壓垮整個資料庫,導致系統卡死等嚴重問題。

常規的應用系統中,我們通常會在需要的時候對資料庫進行查找,因此系統的大致結構如下所示:

1.緩存和資料庫之間數據一致性問題

常用於緩存處理的機制我總結為了以下幾種:

首先來簡單說說Cache aside的這種方式:

Cache Aside模式

這種模式處理緩存通常都是先從資料庫緩存查詢,如果緩存沒有命中則從資料庫中進行查找。

這裡面會發生的三種情況如下:

緩存命中:

當查詢的時候發現緩存存在,那麼直接從緩存中提取。

緩存失效:

當緩存沒有數據的時候,則從database裡面讀取源數據,再加入到cache裡面去。

緩存更新:

當有新的寫操作去修改database裡面的數據時,需要在寫操作完成之後,讓cache裡面對應的數據失效。

關於這種模式下依然會存在缺陷。比如,一個是讀操作,但是沒有命中緩存,然後就到資料庫中取數據,此時來了一個寫操作,寫完資料庫後,讓緩存失效,然後,之前的那個讀操作再把老的數據放進去,所以,會造成臟數據。

Facebook的大牛們也曾經就緩存處理這個問題發表過相關的論文,鏈接如下:

分布式環境中要想完全的保證數據一致性是一件極為困難的事情,我們只能夠盡可能的減低這種數據不一致性問題產生的情況。

Read Through模式

Read Through模式是指應用程序始終從緩存中請求數據。 如果緩存沒有數據,則它負責使用底層提供程序插件從資料庫中檢索數據。 檢索數據後,緩存會自行更新並將數據返回給調用應用程序。使用Read Through 有一個好處。

我們總是使用key從緩存中檢索數據, 調用的應用程序不知道資料庫, 由存儲方來負責自己的緩存處理,這使代碼更具可讀性, 代碼更清晰。但是這也有相應的缺陷,開發人員需要給編寫相關的程序插件,增加了開發的難度性。

Write Through模式

Write Through模式和Read Through模式類似,當數據發生更新的時候,先去Cache裡面進行更新,如果命中了,則先更新緩存再由Cache方來更新database。如果沒有命中的話,就直接更新Cache裡面的數據。

2.緩存穿透問題

在高並發的場景中,緩存穿透是一個經常都會遇到的問題。

什麼是緩存穿透?

大量的請求在緩存中沒有查詢到指定的數據,因此需要從資料庫中進行查詢,造成緩存穿透。

會造成什麼後果?

大量的請求短時間內湧入到database中進行查詢會增加database的壓力,最終導致database無法承載客戶單請求的壓力,出現宕機卡死等現象。

常用的解決方案通常有以下幾類:

1.空值緩存

在某些特定的業務場景中,對於數據的查詢可能會是空的,沒有實際的存在,並且這類數據信息在短時間進行多次的反復查詢也不會有變化,那麼整個過程中,多次的請求資料庫操作會顯得有些多餘。

不妨可以將這些空值(沒有查詢結果的數據)對應的key存儲在緩存中,那麼第二次查找的時候就不需要再次請求到database那麼麻煩,只需要通過內存查詢即可。這樣的做法能夠大大減少對於database的訪問壓力。

2.布隆過濾器

通常對於database裡面的數據的key值可以預先存儲在布隆過濾器裡面去,然後先在布隆過濾器裡面進行過濾,如果發現布隆過濾器中沒有的話,就再去redis裡面進行查詢,如果redis中也沒有數據的話,再去database查詢。這樣可以避免不存在的數據信息也去往存儲庫中進行查詢情況。

什麼是緩存雪崩?

當緩存伺服器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給後端系統(比如DB)帶來很大壓力。

如何避免緩存雪崩問題?

1.使用加鎖隊列來應付這種問題。當有多個請求湧入的時候,當緩存失效的時候加入一把分布式鎖,只允許搶鎖成功的請求去庫裡面讀取數據然後將其存入緩存中,再釋放鎖,讓後續的讀請求從緩存中取數據。但是這種做法有一定的弊端,過多的讀請求線程堵塞,將機器內存占滿,依然沒有能夠從根本上解決問題。

2.在並發場景發生前,先手動觸發請求,將緩存都存儲起來,以減少後期請求對database的第一次查詢的壓力。數據過期時間設置盡量分散開來,不要讓數據出現同一時間段出現緩存過期的情況。

3.從緩存可用性的角度來思考,避免緩存出現單點故障的問題,可以結合使用 主從+哨兵的模式來搭建緩存架構,但是這種模式搭建的緩存架構有個弊端,就是無法進行緩存分片,存儲緩存的數據量有限制,因此可以升級為Redis Cluster架構來進行優化處理。(需要結合企業實際的經濟實力,畢竟Redis Cluster的搭建需要更多的機器)

4.Ehcache本地緩存 + Hystrix限流&降級,避免MySQL被打死。

使用 Ehcache本地緩存的目的也是考慮在 Redis Cluster 完全不可用的時候,Ehcache本地緩存還能夠支撐一陣。

使用 Hystrix進行限流 & 降級 ,比如一秒來了5000個請求,我們可以設置假設只能有一秒 2000個請求能通過這個組件,那麼其他剩餘的 3000 請求就會走限流邏輯。

然後去調用我們自己開發的降級組件(降級),比如設置的一些默認值呀之類的。以此來保護最後的 MySQL 不會被大量的請求給打死。

10. Glide 圖片庫原理(三)緩存機制

查找緩存使用

用完移除

源碼中查看EngineKey-----相當於key,演算法序列abcdsxxfaskldfjklf...
源碼中查看Source-----相當於value(Bitmap),調用系統轉換成Bitmap

情景: 相冊類的App經常需要同時展示大量的圖片,這種情況下圖片的質量可以低一點,因為載入速度優先於圖片的質量。

解決辦法: 我們可以設置解碼的格式,在RequestOptions中加入.encodeFormat(Bitmap.CompressFormat.WEBP).encodeQuality(10))的選項,①encodeFormat的參數有Bitmap.CompressFormat.PNG,Bitmap.CompressFormat.JPEG,Bitmap.CompressFormat.WEBP(質量從高到低);②encodeQuality設置的是0-100的int類型,一個質量百分比參數,越小質量越低。

情景: 大體的意思應該是同一個URL在不同的時間可能會指向不同的資源,所以同樣需要實時更新。

解決辦法相同

情景: 開發一款有頭像的APP,我們修改了頭像並且更新到了服務端,可是當我們點擊查看大圖時載入出來的還是原來的頭像。

解決辦法: 這是Glide強大的緩存帶來的副作用,我們可以在RequestOptions中加入.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)的選項。那麼緩存的功能就會全部關閉,從而使得每次都是從服務端載入,所以頭像會是最新。

情景: 省流量模式的應用情景就是減少不必要圖片的載入。

解決辦法: 我們可以在RequestOptions中加入onlyRetrieveFromCache(true)的選項。那麼圖片就只會從緩存中讀取,如果沒有緩存則不載入圖片,從而達到減少流量消耗的目的。