在高并發(fā)場(chǎng)景下,送你這三根“救命毫毛”
高可用是指,系統(tǒng)在面對(duì)各種挑戰(zhàn)時(shí),如硬件故障、軟件缺陷、網(wǎng)絡(luò)問(wèn)題等,依然能夠持續(xù)提供服務(wù)。高可用通常用“五個(gè)九”(99.999%的可用性)這樣的術(shù)語(yǔ)來(lái)衡量,意味著系統(tǒng)一年中的停機(jī)時(shí)間只有幾分鐘。
分布式系統(tǒng)的高可用架構(gòu)設(shè)計(jì)如圖所示:
- 用戶請(qǐng)求:所有用戶的請(qǐng)求都首先到達(dá)負(fù)載均衡器。
- 負(fù)載均衡器:它是高可用架構(gòu)的關(guān)鍵組成部分。它接收來(lái)自用戶的請(qǐng)求,并將其均勻地分配給多個(gè)服務(wù)器,如服務(wù)器A和服務(wù)器B。這樣做的目的是防止任何單個(gè)服務(wù)器過(guò)載并提高資源利用率。負(fù)載均衡器還負(fù)責(zé)進(jìn)行健康檢查,以確保所有流量?jī)H被轉(zhuǎn)發(fā)到健康的服務(wù)器。
- 服務(wù)器A和服務(wù)器B:代表應(yīng)用服務(wù)器的集群,每個(gè)服務(wù)器都能獨(dú)立處理請(qǐng)求。這些服務(wù)器是冗余的,如果一個(gè)服務(wù)器失敗,則負(fù)載均衡器可以將流量重定向到其他健康的服務(wù)器。
- 數(shù)據(jù)庫(kù)A和數(shù)據(jù)庫(kù)B:代表數(shù)據(jù)層的冗余,確保數(shù)據(jù)的持久性和可用性。通過(guò)主從復(fù)制或其他同步機(jī)制,可以在一個(gè)數(shù)據(jù)庫(kù)發(fā)生故障時(shí)快速切換到另一個(gè)數(shù)據(jù)庫(kù),以維護(hù)服務(wù)的持續(xù)性。
- 監(jiān)控系統(tǒng):負(fù)載均衡器也可以連接一個(gè)監(jiān)控系統(tǒng),用來(lái)監(jiān)控整個(gè)架構(gòu)的健康狀態(tài),包括服務(wù)器和數(shù)據(jù)庫(kù)的性能指標(biāo)。監(jiān)控系統(tǒng)可以自動(dòng)響應(yīng)某些事件,如在檢測(cè)到服務(wù)器故障時(shí),自動(dòng)從服務(wù)器池中剔除故障服務(wù)器,或者在資源使用率達(dá)到某個(gè)閾值時(shí)觸發(fā)擴(kuò)容。
圖片
【實(shí)戰(zhàn)1】在高并發(fā)場(chǎng)景下,使用“限流”防止系統(tǒng)崩潰
在設(shè)計(jì)高可用架構(gòu)時(shí),除需要考慮冗余和備份機(jī)制外,還需要實(shí)施一系列服務(wù)治理策略,來(lái)確保系統(tǒng)在面對(duì)異常流量、服務(wù)依賴故障等特殊情況時(shí)的穩(wěn)定性和彈性。這些策略包括限流、降級(jí)、熔斷和隔離等,它們有助于系統(tǒng)在壓力下保持核心功能,避免全面崩潰。
是電商系統(tǒng)中常用的一種保護(hù)機(jī)制,用于控制流入系統(tǒng)的請(qǐng)求速率,防止系統(tǒng)因短時(shí)間內(nèi)請(qǐng)求過(guò)多而過(guò)載。
限流的常用策略如下。
- 固定窗口計(jì)數(shù)器:在固定的時(shí)間窗口(如每分鐘)內(nèi),只允許一定數(shù)量的請(qǐng)求通過(guò)。
- 滑動(dòng)窗口計(jì)數(shù)器:在滑動(dòng)的時(shí)間窗口內(nèi),計(jì)算請(qǐng)求的速率,并動(dòng)態(tài)調(diào)整允許的請(qǐng)求數(shù)量。
- 令牌桶(Token Bucket):系統(tǒng)以固定速率生成令牌,請(qǐng)求需要消耗令牌才能通過(guò),令牌的生成和消耗類似于漏桶模型。這種方式允許突發(fā)流量在短時(shí)間內(nèi)高速傳入,但長(zhǎng)期速率限制在固定值。
- 優(yōu)先級(jí)隊(duì)列:對(duì)請(qǐng)求進(jìn)行優(yōu)先級(jí)排序,高優(yōu)先級(jí)的請(qǐng)求先通過(guò)限流檢查。在電商系統(tǒng)中,可能會(huì)對(duì)以下幾方面實(shí)施限流。
- 用戶級(jí)別的限流:通過(guò)用戶ID進(jìn)行識(shí)別,為每個(gè)用戶都設(shè)置獨(dú)立的限流規(guī)則,防止單個(gè)用戶頻繁請(qǐng)求,如每秒限制用戶下單次數(shù)。例如,使用Redis等緩存數(shù)據(jù)庫(kù)記錄每個(gè)用戶的請(qǐng)求時(shí)間戳,只有當(dāng)時(shí)間間隔滿足要求時(shí),才允許新的請(qǐng)求通過(guò)。
- 接口級(jí)別的限流:對(duì)特定的API設(shè)置限流規(guī)則,如每個(gè)API在一定時(shí)間內(nèi)只能處理一定數(shù)量的請(qǐng)求??梢允褂肧entinel等工具,為每個(gè)接口都配置限流規(guī)則,并在網(wǎng)關(guān)或API控制器中實(shí)現(xiàn)限流邏輯。
- 全局級(jí)別的限流:對(duì)整個(gè)系統(tǒng)或服務(wù)集群設(shè)置總體的流量控制,防止整個(gè)系統(tǒng)因流量過(guò)大而崩潰??梢栽谪?fù)載均衡器或網(wǎng)關(guān)層面實(shí)現(xiàn)全局限流,如Nginx的限流模塊。
1.接口級(jí)別的限流
以訪問(wèn)電商系統(tǒng)中的商品詳情頁(yè)為例,假設(shè)我們希望限制每個(gè)用戶每秒對(duì)商品詳情頁(yè)的訪問(wèn)次數(shù)不超過(guò)5次,則可以通過(guò)使用令牌桶算法實(shí)現(xiàn)。Spring Cloud Gateway提供了集成令牌桶算法限流的能力,結(jié)合Redis使用,可以實(shí)現(xiàn)分布式的限流策略。Spring Cloud的代碼如下。
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
@Configuration
public class GatewayConfig {
// 定義路由規(guī)則,指向商品詳情服務(wù)
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder.routes()
.route("product_detail_route", r -> r.path("/product/details/**")
.filters(f -> f.requestRateLimiter().configure(c -> c.setRateLimiter(redisRateLimiter())))
.uri("lb://PRODUCT-SERVICE"))
.build();
}
// 應(yīng)用限流過(guò)濾器,使用Redis實(shí)現(xiàn)
@Bean
RedisRateLimiter redisRateLimiter() {
// 創(chuàng)建RedisRateLimiter實(shí)例
// 參數(shù)分別是允許用戶每秒進(jìn)行5次請(qǐng)求,突發(fā)流量大小為10個(gè)令牌
return new RedisRateLimiter(5, 10);
}
}
對(duì)代碼的解析如下。
requestRateLimiter():應(yīng)用限流過(guò)濾器,使用Redis實(shí)現(xiàn)。
RedisRateLimiter(5, 10):配置令牌桶參數(shù),表示每秒生成5個(gè)令牌,允許的突發(fā)流量大小為10個(gè)令牌。
通過(guò)上述配置,當(dāng)用戶對(duì)商品詳情頁(yè)的訪問(wèn)頻率超過(guò)每秒5次時(shí),額外的請(qǐng)求將被限流策略攔截,從而保護(hù)了背后的商品詳情服務(wù)不會(huì)因?yàn)檫^(guò)高的訪問(wèn)頻率而過(guò)載。
提示:在實(shí)際部署時(shí),需要考慮Redis的性能和高可用配置,確保限流服務(wù)本身不成為系統(tǒng)的瓶頸。
全局級(jí)別的限流
在電商系統(tǒng)中,全局限流是一個(gè)關(guān)鍵的策略,它能夠幫助系統(tǒng)在面對(duì)大量用戶請(qǐng)求時(shí)保持穩(wěn)定和高效運(yùn)行。全局限流策略通常涉及多個(gè)層面,包括客戶端、接入層、應(yīng)用層、數(shù)據(jù)層的優(yōu)化。
圖10-2是一個(gè)常見(jiàn)的電商系統(tǒng)架構(gòu),在該架構(gòu)的基礎(chǔ)上實(shí)施全局限流的具體步驟和策略如下。
圖片
(1)接入層限流。
接入層限流是對(duì)進(jìn)入系統(tǒng)的請(qǐng)求進(jìn)行控制的第一道防線,旨在保護(hù)后端服務(wù)不被突發(fā)的高流量擊潰。這通常在API網(wǎng)關(guān)(位置③)或負(fù)載均衡器層面實(shí)現(xiàn)南北流量的限流。通過(guò)定義流量閾值來(lái)限制短時(shí)間內(nèi)處理的請(qǐng)求量,超過(guò)閾值的請(qǐng)求會(huì)被暫時(shí)阻塞或拒絕,以此來(lái)確保系統(tǒng)穩(wěn)定運(yùn)行并防止服務(wù)過(guò)載。
(2)讀緩存的優(yōu)化。
①客戶端緩存??蛻舳司彺妫ㄎ恢芒伲┲饕槍?duì)變化不頻繁的數(shù)據(jù),如用戶的配置信息、商品的靜態(tài)詳情等。通過(guò)在客戶端(如Web瀏覽器、移動(dòng)應(yīng)用)存儲(chǔ)這些數(shù)據(jù),可以減少對(duì)后端服務(wù)的請(qǐng)求次數(shù)。
②CDN緩存。CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))(位置②)可以緩存靜態(tài)資源如圖片、CSS、JS文件等,使用戶能就近訪問(wèn)這些資源。這不僅加速了用戶的訪問(wèn)速度,還大大減輕了后端服務(wù)器的讀取壓力。
③Redis緩存。將熱點(diǎn)數(shù)據(jù)(如頻繁查詢的商品庫(kù)存信息、用戶會(huì)話等)緩存到Redis(位置⑦),可以顯著提高讀取效率,減輕數(shù)據(jù)庫(kù)的查詢壓力。
【實(shí)戰(zhàn)2】在高并發(fā)場(chǎng)景下,使用“熔斷”防止服務(wù)崩潰
在電商系統(tǒng)中,服務(wù)間的依賴關(guān)系復(fù)雜,一旦某個(gè)服務(wù)發(fā)生故障,很容易引發(fā)連鎖反應(yīng),導(dǎo)致整個(gè)系統(tǒng)癱瘓,這就是所謂的“服務(wù)雪崩”效應(yīng)。
以商品詳情頁(yè)服務(wù)為例,這個(gè)服務(wù)在電商系統(tǒng)中非常關(guān)鍵,它需要從多個(gè)依賴服務(wù)中獲取數(shù)據(jù),如商品描述服務(wù)、商品價(jià)格服務(wù)、商品評(píng)論服務(wù)等。如果其中一個(gè)服務(wù)發(fā)生故障,沒(méi)有熔斷保護(hù),則導(dǎo)致用戶無(wú)法正常訪問(wèn)商品詳情頁(yè),嚴(yán)重時(shí)甚至可能影響整個(gè)系統(tǒng),如圖10-3所示。
圖片
熔斷策略是一種有效的機(jī)制,用于防止這種情況的發(fā)生。就像電路中的保險(xiǎn)絲一樣,當(dāng)電流過(guò)大時(shí),保險(xiǎn)絲會(huì)熔斷以保護(hù)電路不受損害。在高可用架構(gòu)中,熔斷器也能夠在服務(wù)出現(xiàn)問(wèn)題時(shí)“斷開(kāi)”,從而保護(hù)系統(tǒng)不受進(jìn)一步損害。
在上述商品詳情頁(yè)服務(wù)中添加熔斷器后,如圖10-4所示。
圖片
熔斷器主要有如下三種狀態(tài)。
- 關(guān)閉(CLOSED):在正常狀態(tài)下,所有請(qǐng)求都可以直接調(diào)用服務(wù)。
- 打開(kāi)(OPEN):當(dāng)錯(cuò)誤率超過(guò)閾值時(shí),熔斷器打開(kāi)。此時(shí),對(duì)該服務(wù)的調(diào)用會(huì)立即失敗,不會(huì)執(zhí)行實(shí)際的業(yè)務(wù)邏輯。這個(gè)狀態(tài)會(huì)持續(xù)一段時(shí)間,被稱為“熔斷時(shí)間”。
- 半開(kāi)(HALF-OPEN):熔斷時(shí)間過(guò)后,熔斷器進(jìn)入半開(kāi)狀態(tài)。這時(shí),允許有限的請(qǐng)求通過(guò)以測(cè)試服務(wù)是否恢復(fù)正常。如果這些請(qǐng)求都成功了,則熔斷器回到閉合狀態(tài);如果仍有過(guò)多的請(qǐng)求失敗,則熔斷器再次打開(kāi)。
以下是使用Spring Cloud Hystrix實(shí)現(xiàn)的熔斷器示例。假設(shè)有一個(gè)獲取商品評(píng)論的服務(wù),當(dāng)評(píng)論服務(wù)發(fā)生故障時(shí),熔斷器將自動(dòng)斷開(kāi),調(diào)用備用方法返回默認(rèn)評(píng)論。
(1)添加Hystrix依賴到項(xiàng)目中(以Maven為例),代碼如下。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
(2)在Spring Boot應(yīng)用主類或配置類上添加@EnableCircuitBreaker注解來(lái)啟用Hystrix,代碼如下。
@SpringBootApplication
@EnableCircuitBreaker
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
(3)創(chuàng)建一個(gè)服務(wù)類,使用@HystrixCommand注解定義熔斷策略,代碼如下。
@Service
public class CommentService {
@HystrixCommand(fallbackMethod = "getDefaultComments")
public String getComments(String productId) {
// 模擬從評(píng)論服務(wù)獲取評(píng)論的操作,可能會(huì)因?yàn)榉?wù)發(fā)生故障而拋出異常
if (new Random().nextInt(10) < 8) { // 假設(shè)有80%的概率服務(wù)會(huì)失敗
throw new RuntimeException("評(píng)論服務(wù)異常");
}
return "正常獲取評(píng)論數(shù)據(jù)";
}
// 定義熔斷時(shí)的備用方法
public String getDefaultComments(String productId) {
return "評(píng)論服務(wù)當(dāng)前不可用,請(qǐng)稍后再試";
}
}
在上述代碼中,getComments()方法嘗試獲取商品的評(píng)論信息。這里我們通過(guò)隨機(jī)數(shù)模擬服務(wù)的不穩(wěn)定性。@HystrixCommand注解指定了當(dāng)getComments()方法調(diào)用失敗時(shí),將自動(dòng)調(diào)用getDefaultComments()方法作為備用邏輯,向用戶返回一個(gè)友好的提示信息。
通過(guò)上面的示例,我們可以將這種策略應(yīng)用到所有的服務(wù)調(diào)用中,以保證即使在某個(gè)服務(wù)發(fā)生故障時(shí),也能向用戶提供最基本的服務(wù),從而提高系統(tǒng)的整體可用性和用戶的體驗(yàn)。
此外,在Node.js中可以使用Hystrix.js庫(kù)來(lái)實(shí)現(xiàn)熔斷策略,代碼如下。
const Hystrix = require('hystrix-js');
// 創(chuàng)建一個(gè)熔斷器,設(shè)置錯(cuò)誤率閾值為50%
const paymentHystrix = new Hystrix({
metrics: {
healthPercentThresholds: [50]
}
});
// 包裝支付服務(wù)的調(diào)用
function makePaymentRequest() {
return paymentHystrix.wrap(((resolve, reject) => {
// 假設(shè)的支付服務(wù)調(diào)用
payService支付((err, result) => {
if (err) {
reject(err); // 支付失敗,觸發(fā)熔斷器
} else {
resolve(result); // 支付成功
}
});
})).then(() => {
// 處理支付成功
}).catch(err => {
// 處理支付失敗,可能觸發(fā)熔斷器
console.error('支付失敗:', err);
});
}
在這段代碼中,Hystrix對(duì)象包裝了支付服務(wù)的調(diào)用。如果支付服務(wù)的錯(cuò)誤率達(dá)到了50%,則將觸發(fā)熔斷器,之后的支付請(qǐng)求將會(huì)立即失敗,從而保護(hù)系統(tǒng)不受進(jìn)一步的損害。
【實(shí)戰(zhàn)3】在高并發(fā)場(chǎng)景下,使用“降級(jí)”應(yīng)對(duì)性能瓶頸
在高并發(fā)場(chǎng)景下,電商系統(tǒng)經(jīng)常會(huì)遇到性能瓶頸,這可能導(dǎo)致用戶體驗(yàn)下降,甚至服務(wù)中斷。為了應(yīng)對(duì)這種情況,開(kāi)發(fā)團(tuán)隊(duì)通常會(huì)采用降級(jí)策略,有計(jì)劃地降低系統(tǒng)的部分功能,以確保核心功能的穩(wěn)定運(yùn)行。
常用的降級(jí)策略如下。
- 服務(wù)降級(jí):在后端服務(wù)響應(yīng)慢時(shí),返回緩存的數(shù)據(jù)或者簡(jiǎn)化的響應(yīng)內(nèi)容。
- 功能降級(jí):暫時(shí)關(guān)閉或簡(jiǎn)化一些非核心功能,如商品推薦、促銷活動(dòng)等。
- 用戶體驗(yàn)降級(jí):在無(wú)法提供完整服務(wù)時(shí),只提供基本的服務(wù),如用文本描述代替圖片等。
1.服務(wù)降級(jí)
對(duì)于電商系統(tǒng)的后端服務(wù)(如商品服務(wù)),服務(wù)降級(jí)的具體實(shí)現(xiàn)策略如下。
(1)使用緩存數(shù)據(jù)。
- 系統(tǒng)預(yù)先將熱門商品的詳情頁(yè)信息緩存起來(lái),如緩存在Redis或Memcached中。
- 當(dāng)后端服務(wù)響應(yīng)變慢或不可用時(shí),系統(tǒng)自動(dòng)切換為返回緩存數(shù)據(jù)。
- 可以定期更新緩存,以保證信息的相對(duì)新鮮度。
(2)簡(jiǎn)化響應(yīng)內(nèi)容。
- 對(duì)于一些非核心的信息(如用戶評(píng)論、推薦商品等),可以在系統(tǒng)負(fù)載高時(shí)不加載這些內(nèi)容。
- 提供一個(gè)簡(jiǎn)化版本的商品詳情頁(yè),只包含最關(guān)鍵的購(gòu)買信息,如價(jià)格、庫(kù)存和基本描述。這樣可以減少網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)量和前端渲染的復(fù)雜度。
- 在某些情況下,可以根據(jù)實(shí)時(shí)的系統(tǒng)負(fù)載動(dòng)態(tài)決定是否觸發(fā)降級(jí)處理。例如,如果檢測(cè)到CPU或內(nèi)存使用率超過(guò)預(yù)設(shè)閾值,則自動(dòng)開(kāi)始返回簡(jiǎn)化的響應(yīng)內(nèi)容。
下面是一段簡(jiǎn)單的Java代碼,展示了如何根據(jù)后端服務(wù)的狀態(tài)返回不同的響應(yīng)。
public class ProductService {
private CacheManager cacheManager;
public ProductService(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
// 獲取商品詳情
public ProductDetail getProductDetail(String productId) {
try {
// 嘗試從數(shù)據(jù)庫(kù)中獲取最新的商品詳情頁(yè)
ProductDetail productDetail = fetchProductDetailFromDB(productId);
return productDetail;
} catch (Exception e) {
// 如果數(shù)據(jù)庫(kù)訪問(wèn)出錯(cuò)或超時(shí),則使用緩存數(shù)據(jù)
ProductDetail cachedDetail = cacheManager.getCachedProductDetail(productId);
if (cachedDetail != null) {
return cachedDetail; // 返回緩存的商品詳情頁(yè)信息
}
// 如果沒(méi)有緩存,則返回簡(jiǎn)化的商品信息
return new ProductDetail(productId, "暫無(wú)詳細(xì)描述,請(qǐng)稍后再試。");
}
}
// 模擬從數(shù)據(jù)庫(kù)中獲取商品詳情頁(yè)
private ProductDetail fetchProductDetailFromDB(String productId) throws Exception {
// 模擬數(shù)據(jù)庫(kù)操作可能的延遲
Thread.sleep(200); // 假設(shè)有200ms的延遲
return new ProductDetail(productId, "完整的商品描述。");
}
}
對(duì)代碼的解析如下。
- ProductService類負(fù)責(zé)處理商品詳情頁(yè)的獲取。
- 如果從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)失敗(如拋出異常),則嘗試從緩存中獲取商品詳情頁(yè)。
- 如果緩存也不存在,則返回一個(gè)包含極簡(jiǎn)信息的ProductDetail對(duì)象,提示用戶稍后再試。
通過(guò)這種方式,即使后端服務(wù)由于某些原因而性能下降,用戶依然可以得到必要的商品信息,保證了用戶體驗(yàn)的連續(xù)性和系統(tǒng)的高可用。
2.功能降級(jí)
假設(shè)電商系統(tǒng)中有一個(gè)商品推薦服務(wù),它根據(jù)用戶的瀏覽歷史和購(gòu)買歷史來(lái)推薦商品。雖然這項(xiàng)服務(wù)可以增強(qiáng)用戶體驗(yàn),但它并不是完成交易的核心部分。在高流量事件中,如大型促銷活動(dòng)或購(gòu)物季等,服務(wù)器可能會(huì)面臨極大的壓力。
這時(shí)就需要對(duì)商品推薦服務(wù)進(jìn)行降級(jí)處理,處理步驟如下。
(1)定義服務(wù)狀態(tài)控制。
在服務(wù)的Java實(shí)現(xiàn)中,定義一個(gè)靜態(tài)變量isServiceEnabled,用來(lái)標(biāo)識(shí)推薦服務(wù)當(dāng)前是否可用。
(2)服務(wù)降級(jí)開(kāi)關(guān)。
在服務(wù)的Java實(shí)現(xiàn)中,提供一個(gè)公共方法setServiceStatus(boolean status),允許動(dòng)態(tài)地控制推薦服務(wù)的開(kāi)啟或關(guān)閉。
(3)服務(wù)方法調(diào)整。
在推薦方法中,首先檢查isServiceEnabled的狀態(tài)。如果服務(wù)被設(shè)置為不可用,則進(jìn)行降級(jí)處理,推薦方法將直接返回一個(gè)空列表或預(yù)設(shè)的簡(jiǎn)單推薦列表,這樣可以大幅減少對(duì)系統(tǒng)資源的占用。
上述降級(jí)處理的具體代碼如下。
public class RecommendationService {
// 標(biāo)志位,用于標(biāo)識(shí)推薦服務(wù)是否可用
private static volatile boolean isServiceEnabled = true;
// 設(shè)置服務(wù)狀態(tài)的方法,可以被外部調(diào)用來(lái)開(kāi)啟或關(guān)閉服務(wù)
public static void setServiceStatus(boolean status) {
isServiceEnabled = status;
}
// 推薦商品的方法
public List<Product> recommendProducts(User user) {
// 檢查推薦服務(wù)是否被降級(jí)(即關(guān)閉)
if (!isServiceEnabled) {
// 在推薦服務(wù)被關(guān)閉時(shí),返回一個(gè)空列表或者預(yù)設(shè)的簡(jiǎn)單推薦列表
return Collections.emptyList(); // 這里為了簡(jiǎn)化,直接返回空列表
}
// 正常情況下的推薦邏輯
// 假設(shè)有一個(gè)復(fù)雜的邏輯,根據(jù)用戶的瀏覽歷史、購(gòu)買歷史等信息生成推薦列表
// ……
return new ArrayList<>(); // 在實(shí)際業(yè)務(wù)中應(yīng)有復(fù)雜邏輯返回推薦商品
}
}
在系統(tǒng)監(jiān)控工具觀察到服務(wù)器負(fù)載達(dá)到臨界點(diǎn)時(shí),系統(tǒng)管理員或自動(dòng)化腳本可以調(diào)用setServiceStatus(false)方法來(lái)關(guān)閉推薦服務(wù),減輕服務(wù)器的壓力。當(dāng)系統(tǒng)負(fù)載恢復(fù)正常后,再次調(diào)用setServiceStatus(true)方法來(lái)重新開(kāi)啟推薦服務(wù)。
3.用戶體驗(yàn)降級(jí)
假設(shè)一個(gè)電商網(wǎng)站在特價(jià)促銷期間遭遇流量激增,服務(wù)器負(fù)載急劇上升,導(dǎo)致圖片服務(wù)器響應(yīng)變慢。為了不影響核心購(gòu)買流程,網(wǎng)站可以實(shí)施用戶體驗(yàn)降級(jí)策略,即在圖片加載困難時(shí)用文本描述或圖標(biāo)作為替代,確保頁(yè)面加載速度和核心交易功能的正常運(yùn)行。
用戶體驗(yàn)降級(jí)策略如下。
- 用文本描述代替圖片:在圖片加載緩慢或失敗時(shí),使用文本描述來(lái)代替圖片,讓用戶至少知道商品的基本信息。
- 簡(jiǎn)化頁(yè)面布局:在前端頁(yè)面渲染能力受限時(shí),提供一個(gè)簡(jiǎn)化的頁(yè)面布局,只包含必要的元素和信息。
- 延遲加載:對(duì)于非關(guān)鍵的頁(yè)面元素,如廣告和推薦商品,可以采用延遲加載的方式,優(yōu)先保證核心內(nèi)容的加載。
例如,在前端代碼中實(shí)現(xiàn)降級(jí)邏輯,確保在后端服務(wù)不穩(wěn)定或網(wǎng)絡(luò)條件差時(shí),用戶仍然能夠獲取基本信息。前端的代碼如下。
// 假設(shè)這是一個(gè)商品詳情頁(yè)的前端代碼片段
function fetchProductDetails(productId) {
fetch(`/api/product/${productId}`)
.then(response => {
if (!response.ok) {
// 如果請(qǐng)求失敗,則返回降級(jí)內(nèi)容
return getDegradedProductDetails(productId);
}
return response.json();
})
.then(details => renderProductDetails(details))
.catch(error => {
// 如果請(qǐng)求失敗,則返回降級(jí)內(nèi)容
getDegradedProductDetails(productId).then(degradedDetails =>{
renderDegradedProductDetails(degradedDetails);
});
});
}
function getDegradedProductDetails(productId) {
// 這里可以從本地緩存中獲取,或者是更簡(jiǎn)單的數(shù)據(jù)
return new Promise(resolve => {
resolve({
name: '商品名稱',
description: '商品描述',
price: '商品價(jià)格'
});
});
}
function renderDegradedProductDetails(degradedDetails) {
// 使用簡(jiǎn)化的模板或布局渲染降級(jí)內(nèi)容
const container = document.getElementById('product-details');
container.innerHTML = '
<h1>${degradedDetails.name}</h1>
<p>${degradedDetails.description}</p>
<p>價(jià)格:$${degradedDetails.price}</p>
';
}
在上述代碼中,fetchProductDetails()方法嘗試從后端獲取完整的商品詳情頁(yè)。如果請(qǐng)求失敗,則它會(huì)調(diào)用getDegradedProductDetails()方法來(lái)獲取一個(gè)簡(jiǎn)化的商品詳情頁(yè),并使用 renderDegradedProductDetails()方法來(lái)渲染。