硬核乾貨!7600字帶你學會 Redis 性能優化點,建議收藏!

2020-12-11 酷扯兒

本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫

來源:rrd.me/gteAC

在一些網絡服務的系統中,Redis 的性能,可能是比 MySQL 等硬碟資料庫的性能更重要的課題。比如微博,把熱點微博[1],最新的用戶關係,都存儲在 Redis 中,大量的查詢擊中 Redis,而不走 MySQL。

那麼,針對 Redis 服務,我們能做哪些性能優化呢?或者說,應該避免哪些性能浪費呢?

Redis 性能的基本面

在討論優化之前,我們需要知道,Redis 服務本身就有一些特性,比如單線程運行。除非修改 Redis 的原始碼,不然這些特性,就是我們思考性能優化的基本面。

那麼,有哪些 Redis 基本特性需要我們考慮呢?Redis 的項目介紹中概括了它特性:

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported.

首先,Redis 使用作業系統提供的虛擬內存來存儲數據。而且,這個作業系統一般就是指 Unix。Windows 上也能運行 Redis,但是需要特殊處理。如果你的作業系統使用交換空間,那麼 Redis 的數據可能會被實際保存在硬碟上。

其次,Redis 支持持久化,可以把數據保存在硬碟上。很多時候,我們也確實有必要進行持久化來實現備份,數據恢復等需求。但持久化不會憑空發生,它也會佔用一部分資源。

第三,Redis 是用 key-value 的方式來讀寫的,而 value 中又可以是很多不同種類的數據;更進一步,一個數據類型的底層還有被存儲為不同的結構。不同的存儲結構決定了數據增刪改查的複雜度以及性能開銷。

最後,在上面的介紹中沒有提到的是,Redis 大多數時候是單線程運行[2]的(single-threaded),即同一時間只佔用一個 CPU,只能有一個指令在運行,並行讀寫是不存在的。很多操作帶來的延遲問題,都可以在這裡找到答案。

關於最後這個特性,為什麼 Redis 是單線程的,卻能有很好的性能(根據 Amdahl’s Law,優化耗時佔比大的過程,才更有意義),兩句話概括是:Redis 利用了多路 I/O 復用機制[3],處理客戶端請求時,不會阻塞主線程;Redis 單純執行(大多數指令)一個指令不到1 微秒[4],如此,單核 CPU 一秒就能處理 1 百萬個指令(大概對應著幾十萬個請求吧),用不著實現多線程(網絡才是瓶頸[5])。

優化網絡延時

Redis 的官方博客在幾個地方都說,性能瓶頸更可能是網絡[6],那麼我們如何優化網絡上的延時呢?

首先,如果你們使用單機部署(應用服務和 Redis 在同一臺機器上)的話,使用 Unix 進程間通訊來請求 Redis 服務,速度比 localhost 區域網(學名 loopback)更快。官方文檔[7]是這麼說的,想一想,理論上也應該是這樣的。

但很多公司的業務規模不是單機部署能支撐的,所以還是得用 TCP。

Redis 客戶端和伺服器的通訊一般使用 TCP 長連結。如果客戶端發送請求後需要等待 Redis 返回結果再發送下一個指令,客戶端和 Redis 的多個請求就構成下面的關係:

(備註:如果不是你要發送的 key 特別長,一個 TCP 包完全能放下 Redis 指令,所以只畫了一個 push 包)

這樣這兩次請求中,客戶端都需要經歷一段網絡傳輸時間。

但如果有可能,完全可以使用 multi-key 類的指令來合併請求,比如兩個

GET key

可以用

MGET key1 key2

合併。這樣在實際通訊中,請求數也減少了,延時自然得到好轉。

如果不能用 multi-key 指令來合併,比如一個

SET

,一個

GET

無法合併。怎麼辦?

Redis 中有至少這樣兩個方法能合併多個指令到一個 request 中,一個是

MULTI/EXEC

,一個是 script。前者本來是構建 Redis 事務的方法,但確實可以合併多個指令為一個 request,它到通訊過程如下。至於 script,最好利用緩存腳本的 sha1 hash key 來調起腳本,這樣通訊量更小。

這樣確實更能減少網絡傳輸時間,不是麼?但如此以來,就必須要求這個 transaction / script 中涉及的 key 在同一個 node 上,所以要酌情考慮。

如果上面的方法我們都考慮過了,還是沒有辦法合併多個請求,我們還可以考慮合併多個 responses。比如把 2 個回覆信息合併:

這樣,理論上可以省去 1 次回復所用的網絡傳輸時間。這就是 pipeline 做的事情。舉個 ruby 客戶端使用 pipeline 的例子:

require 'redis'@redis = Redis.new()@redis.pipelined do@redis.get 'key1' @redis.set 'key2' 'some value'end# => [1, 2]

據說,有些語言的客戶端,甚至默認就使用 pipeline 來優化延時問題,比如 node_redis。

另外,不是任意多個回覆信息都可以放進一個 TCP 包中,如果請求數太多,回復的數據很長(比如 get 一個長字符串),TCP 還是會分包傳輸,但使用 pipeline,依然可以減少傳輸次數。

pipeline 和上面的其他方法都不一樣的是,它不具有原子性。所以在 cluster 狀態下的集群上,實現 pipeline 比那些原子性的方法更有可能。

小結一下:

使用 unix 進程間通信,如果單機部署使用 multi-key 指令合併多個指令,減少請求數,如果有可能的話使用 transaction、script 合併 requests 以及 responses使用 pipeline 合併 response警惕執行時間長的操作

在大數據量的情況下,有些操作的執行時間會相對長,比如

KEYS *

LRANGE mylist 0 -1

,以及其他算法複雜度為 O(n) 的指令。因為 Redis 只用一個線程來做數據查詢,如果這些指令耗時很長,就會阻塞 Redis,造成大量延時。

儘管官方文檔中說

的查詢挺快的,(在普通筆記本上)掃描 1 百萬個 key,只需 40 毫秒(參見:https://redis.io/commands/keys),但幾十 ms 對於一個性能要求很高的系統來說,已經不短了,更何況如果有幾億個 key(一臺機器完全可能存幾億個 key,比如一個 key 100位元組,1 億個 key 只有 10GB),時間更長。

所以,儘量不要在生產環境的代碼使用這些執行很慢的指令,這一點 Redis 的作者在博客[8]中也提到了。另外,運維同學查詢 Redis 的時候也儘量不要用。甚至,Redis Essential 這本書建議利用

rename-command KEYS ''

來禁止使用這個耗時的指令。

除了這些耗時的指令,Redis 中 transaction,script,因為可以合併多個 commands 為一個具有原子性的執行過程,所以也可能佔用 Redis 很長時間,需要注意。

如果你想找出生產環境使用的「慢指令」,那麼可以利用

SLOWLOG GET count

來查看最近的 count 個執行時間很長的指令。至於多長算長,可以通過在 redis.conf 中設置 slowlog-log-slower-than 來定義。

除此之外,在很多地方都沒有提到的一個可能的慢指令是

DEL

,但 redis.conf 文件的注釋[9]中倒是說了。長話短說就是 DEL 一個大的 object 時候,回收相應的內存可能會需要很長時間(甚至幾秒),所以,建議用 DEL 的異步版本:

UNLINK

。後者會啟動一個新的 thread 來刪除目標 key,而不阻塞原來的線程。

更進一步,當一個 key 過期之後,Redis 一般也需要同步的把它刪除。其中一種刪除 keys 的方式是,每秒 10 次的檢查一次有設置過期時間的 keys,這些 keys 存儲在一個全局的 struct 中,可以用

server.db->expires

訪問。檢查的方式是:

從中隨機取出 20 個 keys把過期的刪掉。如果剛剛 20 個 keys 中,有 25% 以上(也就是 5 個以上)都是過期的,Redis 認為,過期的 keys 還挺多的,繼續重複步驟 1,直到滿足退出條件:某次取出的 keys 中沒有那麼多過去的 keys。這裡對於性能的影響是,如果真的有很多的 keys 在同一時間過期,那麼 Redis 真的會一直循環執行刪除,佔用主線程。

對此,Redis 作者的建議[10]是警惕

EXPIREAT

這個指令,因為它更容易產生 keys 同時過期的現象。我還見到過一些建議是給 keys 的過期時間設置一個隨機波動量。最後,redis.conf 中也給出了一個方法,把 keys 的過期刪除操作變為異步的,即,在 redis.conf 中設置

lazyfree-lazy-expire yes

優化數據結構、使用正確的算法

一種數據類型(比如 string,list)進行增刪改查的效率是由其底層的存儲結構決定的。

我們在使用一種數據類型時,可以適當關注一下它底層的存儲結構及其算法,避免使用複雜度太高的方法。舉兩個例子:

ZADD的時間複雜度是 O(log(N)),這比其他數據類型增加一個新元素的操作更複雜,所以要小心使用。若 Hash 類型的值的 fields 數量有限,它很有可能採用 ziplist 這種結構做存儲,而 ziplist 的查詢效率可能沒有同等欄位數量的 hashtable 效率高,在必要時,可以調整 Redis 的存儲結構。除了時間性能上的考慮,有時候我們還需要節省存儲空間。比如上面提到的 ziplist 結構,就比 hashtable 結構節省存儲空間(Redis Essentials 的作者分別在 hashtable 和 ziplist 結構的 Hash 中插入 500 個 fields,每個 field 和 value 都是一個 15 位左右的字符串,結果是 hashtable 結構使用的空間是 ziplist 的 4 倍。)。但節省空間的數據結構,其算法的複雜度可能很高。所以,這裡就需要在具體問題面前做出權衡。歡迎關注公眾號:朱小廝的博客,回覆:1024,可以領取redis專屬資料。

如何做出更好的權衡?我覺得得深挖 Redis 的存儲結構才能讓自己安心。這方面的內容我們下次再說。

以上這三點都是編程層面的考慮,寫程序時應該注意啊。下面這幾點,也會影響 Redis 的性能,但解決起來,就不只是靠代碼層面的調整了,還需要架構和運維上的考慮。

考慮作業系統和硬體是否影響性能

Redis 運行的外部環境,也就是作業系統和硬體顯然也會影響 Redis 的性能。在官方文檔中,就給出了一些例子:

CPU:Intel 多種 CPU 都比 AMD 皓龍系列好虛擬化:實體機比虛擬機好,主要是因為部分虛擬機上,硬碟不是本地硬碟,監控軟體導致 fork 指令的速度慢(持久化時會用到 fork),尤其是用 Xen 來做虛擬化時。內存管理:在 linux 作業系統中,為了讓 translation lookaside buffer,即 TLB,能夠管理更多內存空間(TLB 只能緩存有限個 page),作業系統把一些 memory page 變得更大,比如 2MB 或者 1GB,而不是通常的 4096 字節,這些大的內存頁叫做 huge pages。同時,為了方便程式設計師使用這些大的內存 page,作業系統中實現了一個 transparent huge pages(THP)機制,使得大內存頁對他們來說是透明的,可以像使用正常的內存 page 一樣使用他們。但這種機制並不是資料庫所需要的,可能是因為 THP 會把內存空間變得緊湊而連續吧,就像mongodb 的文檔[11]中明確說的,資料庫需要的是稀疏的內存空間,所以請禁掉 THP 功能。Redis 也不例外,但 Redis 官方博客上給出的理由是:使用大內存 page 會使 bgsave 時,fork 的速度變慢;如果 fork 之後,這些內存 page 在原進程中被修改了,他們就需要被複製(即 copy on write),這樣的複製會消耗大量的內存(畢竟,人家是 huge pages,複製一份消耗成本很大)。所以,請禁止掉作業系統中的 transparent huge pages 功能。交換空間:當一些內存 page 被存儲在交換空間文件上,而 Redis 又要請求那些數據,那麼作業系統會阻塞 Redis 進程,然後把想要的 page,從交換空間中拿出來,放進內存。這其中涉及整個進程的阻塞,所以可能會造成延時問題,一個解決方法是禁止使用交換空間(Redis Essentials 中如是建議,如果內存空間不足,請用別的方法處理)。考慮持久化帶來的開銷

Redis 的一項重要功能就是持久化,也就是把數據複製到硬碟上。基於持久化,才有了 Redis 的數據恢復等功能。

但維護這個持久化的功能,也是有性能開銷的。

首先說,RDB 全量持久化。

這種持久化方式把 Redis 中的全量數據打包成 rdb 文件放在硬碟上。但是執行 RDB 持久化過程的是原進程 fork 出來一個子進程,而 fork 這個系統調用是需要時間的,根據Redis Lab 6 年前做的實驗[12],在一臺新型的 AWS EC2 m1.small^13 上,fork 一個內存佔用 1GB 的 Redis 進程,需要 700+ 毫秒,而這段時間,redis 是無法處理請求的。

雖然現在的機器應該都會比那個時候好,但是 fork 的開銷也應該考慮吧。為此,要使用合理的 RDB 持久化的時間間隔,不要太頻繁

接下來,我們看另外一種持久化方式:AOF 增量持久化。

這種持久化方式會把你發到 redis server 的指令以文本的形式保存下來(格式遵循 redis protocol),這個過程中,會調用兩個系統調用,一個是

write(2)

,同步完成,一個是

fsync(2)

,異步完成。

這兩部都可能是延時問題的原因:

write 可能會因為輸出的 buffer 滿了,或者 kernal 正在把 buffer 中的數據同步到硬碟,就被阻塞了。fsync 的作用是確保 write 寫入到 aof 文件的數據落到了硬碟上,在一個 7200 轉/分的硬碟上可能要延時 20 毫秒左右,消耗還是挺大的。更重要的是,在 fsync 進行的時候,write 可能會被阻塞。其中,write 的阻塞貌似只能接受,因為沒有更好的方法把數據寫到一個文件中了。但對於 fsync,Redis 允許三種配置,選用哪種取決於你對備份及時性和性能的平衡:

always:當把 appendfsync 設置為 always,fsync 會和客戶端的指令同步執行,因此最可能造成延時問題,但備份及時性最好。everysec:每秒鐘異步執行一次 fsync,此時 redis 的性能表現會更好,但是 fsync 依然可能阻塞 write,算是一個折中選擇。no:redis 不會主動出發 fsync (並不是永遠不 fsync,那是不太可能的),而由 kernel 決定何時 fsync使用分布式架構 —— 讀寫分離、數據分片

以上,我們都是基於單臺,或者單個 Redis 服務進行優化。下面,我們考慮當網站的規模變大時,利用分布式架構來保障 Redis 性能的問題。

首先說,哪些情況下不得不(或者最好)使用分布式架構:

數據量很大,單臺伺服器內存不可能裝得下,比如 1 個 T 這種量級需要服務高可用單臺的請求壓力過大解決這些問題可以採用數據分片或者主從分離,或者兩者都用(即,在分片用的 cluster 節點上,也設置主從結構)。

這樣的架構,可以為性能提升加入新的切入點:

把慢速的指令發到某些從庫中執行把持久化功能放在一個很少使用的從庫上把某些大 list 分片其中前兩條都是根據 Redis 單線程的特性,用其他進程(甚至機器)做性能補充的方法。

當然,使用分布式架構,也可能對性能有影響,比如請求需要被轉發,數據需要被不斷複製分發。(待查)

後話

其實還有很多東西也影響 Redis 的性能,比如 active rehashing(keys 主表的再哈希,每秒 10 次,關掉它可以提升一點點性能),但是這篇博客已經寫的很長了。而且,更重要不是收集已經被別人提出的問題,然後記憶解決方案;而是掌握 Redis 的基本原理,以不變應萬變的方式決絕新出現的問題。

相關焦點

  • 觸碰到Redis的性能邊緣?看看久經考驗的Redis企業版(Tair)吧
    其中很多核心的改進如短連結優化,正則匹配效率等已經發布至官方。對於小型應用服務來說,阿里雲Redis社區版已經足夠。性能增強版性能增強版Redis即RDB3.0,旨在為用戶提供更強大的服務能力和靈活的構建能力,主要包括: 多線程Redis可以突破Redis單機性能極限,對於常用的數據結構加速可達三倍(400-450K OPS)。支持高達數萬連接的衝擊,足以應對大型的活動如熱播,秒殺等場景。
  • 華碩7600gs怎麼樣 華碩7600gs相關性能分析
    導語:隨著時代的不斷發展,人們生活水平的不斷提高,電腦已走進千家萬戶,電腦的運用使人們的生活更加便捷輕鬆,可以隨時隨地處理大劑量繁瑣工作,從過去人們只追求但方面的物質滿足到現在更追求美的享受,時代在進步,電腦更在隨著人們的需求在進步,由於當前市場電腦種類繁多,價格不一,性能不一,電腦被要求的質量反應速度都是一個重要的衡量標準,接下來小編將為大家介紹一款華碩
  • Redis 3.2.1 發布,超高性能 key-value 資料庫
    redis的出現,很大程度補償了memcached這類keyvalue存儲的不足,在部 分場合可以對關係資料庫起到很好的補充作用。它提供了Python,Ruby,Erlang,PHP客戶端,使用很方便。以下是該版本發布值得關注的內容:A critical bug in Sentinel was hopefully fixed.
  • redis系列-基礎操作和數據類型
    Windows版本的redis伺服器只要點擊redis-server.exe即可啟動。但是客戶端的啟動需要我們熟悉一些命令行的輸入。命令行這種模式的工具我們一般需要學那些命令呢?其實命令行的使用可以以下四點來歸納功能性命令清除屏幕信息幫助信息查閱退出指令以下簡單介紹幾個redis
  • 《明日之後》乾貨:營地官職七彩稱號、柜子變顏色,建議收藏!
    歡迎各位小夥伴們來到本期遊戲君開講的《明日之後》「生存那點事兒」~今天呢,咱們聊聊乾貨:營地官職七彩稱號、柜子名稱變顏色、NPC接不到任務的原因以及「天秀」房子等遊戲經歷~得,廢話不多說了,還是你熟悉的「老配方」:有圖有證據,邊看邊聊天兒吧~一、為什麼有的NPC接不了任務呢?
  • Caffeine 和 Redis 居然可以這麼搭,想不到吧!
    作者 | Garnett來源 | Garnett的Java之路(ID:gh_009246af52d4)頭圖 | CSDN 下載自東方IC前言各位可以回顧下上篇來自未來的緩存-Caffeine,帶你揭開它的神秘面紗在之前我們介紹了如何使用 Redis 或者
  • Redis:從應用到底層,都在這兒了!
    並且 Redis 底層對 SDS 有如下優化:SDS 修改後大小 > 1M 時 系統會多分配空間來進行空間預分配。SDS 是惰性釋放空間的,你 free 了空間,可是系統把數據記錄下來下次想用時候可直接使用。不用新申請空間。
  • Java 資料庫設計 性能優化 電商秒殺系統附帶源碼
    課程名稱: JAVA 資料庫設計 性能優化 電商秒殺系統附帶源碼課程簡介: Java 資料庫設計 性能優化 電商秒殺系統附帶源碼----------------------課程目錄----------------------------
  • Redis各種模式總結
    二、主從模式(master/slaver)   主從模式的概念:   主從模式就是N個redis實例,可以是1主N從,也可以N主N從(N主N從則不是嚴格意義上的主從模式了,後續的集群模式會說到,N主N從就是N+N個redis實例。)
  • Redis高級實用特性:發布及訂閱消息
    發布訂閱(pub/sub)是一種消息通信模式,主要的目的是解耦消息發布者和消息訂閱者之間的耦合,這點和設計模式中的觀察者模式比較相似。pub/sub不僅僅解決發布者和訂閱者直接代碼級別耦合也解決兩者在物理部署上的耦合。redis作為一個pub/sub的server,在訂閱者和發布者之間起到了消息路由的功能。
  • 飛天茅臺超賣P0事故:請慎用Redis分布式鎖!
    原因在於:之前的搶購商品都不是什麼稀缺性商品,而這次活動居然是飛天茅臺,通過埋點數據分析,各項數據基本都是成倍增長,活動熱烈程度可想而知!此處不禁點個讚,但也正因如此,讓用戶服務一直處於較高的運行負載中。搶購活動開始的一瞬間,大量的用戶校驗請求打到了用戶服務。導致用戶服務網關出現了短暫的響應延遲,有些請求的響應時長超過了 10s,但由於 HTTP 請求的響應超時我們設置的是 30s。
  • 計算redis的槽 - CSDN
    /redis-5.0.4/src/redis-cli --cluster reshard 192.168.0.111:7001[root@*** cluster]# ./redis-5.0.4/src/redis-cli --cluster reshard 192.168.0.111:7001>>> Performing Cluster Check (using node 192.168.0.111:7001)M: 38206edb37cf100e20085da0affaeced4ae42029 192.168.0.111:7001 slots
  • 分享這幾款好用的面膜,全是乾貨,建議收藏!
    滿滿都是乾貨,好東西不能獨享,強烈建議大家轉發收藏起來~ 1,一葉子黃金面膜一葉子「小金膜」蜂窩狀的黃金膜布,將黑炭纖維和蜂窩金膜有機地結合起來,打造出獨特的內外雙膜結構。復活草面膜是冰淇淋質地,在敷的過程中會越來越薄,五分鐘後你會發現它會慢慢地吸進你的皮膚!,洗掉之後,皮膚立刻變得軟嫩幼滑,復活草面膜對於肌膚的修復力和滋養力都是max的!7,SK-II前男友面膜這款面膜除了貴就沒啥缺點,面膜添加了Pitera成分,就是和神仙水一個成分,急救面膜的首選。
  • Redis面試:八問字典內部構造與rehash,給我整懵了
    redis的字典字典作為一種數據結構內置在很多高級程式語言裡面,但是redis是基於C語言進行開發的,所以沒有內置這種數據結構,redis只能構建自己的字典實現。字典通常可以由兩種底層數據結構組成,分別是線性表(數組)和hash表。
  • redis如何解決高並發問題?避免出現超賣的情況?
    相信你要處理高並發問題,肯定會想到使用redis緩存資料庫。但是使用了redis處理高並發數據時又會發現一個問題,比如:你商城裡面的一件秒殺商品只有一件庫存了,但是有兩個人同時點擊了進去,也就是說,這件只有一件的數量的商品要發貨兩件,但是你的庫存沒有這麼多了啊,這就出現了超賣的情況,那可就得不償失了啊。這樣的話,不僅僅會導致公司虧本,更展現出了一個系統的bug。這可怎麼辦呢?
  • 賽博朋克2077畫質優化指南:筆記本和甜品卡也能高畫質60幀爽玩!
    本帖會持續更新,想持續了解畫質畫質設置可以點擊關注或收藏。測試平臺聯想Y7000 2019CPU:I7-9750H(性能約等於桌面端i5-9400)cinebench:1279GPU:1660ti(性能約等於桌面端1660)
  • 新手做自媒體,這些短視頻乾貨,可以幫助你快速學會賺錢技能!
    新手做自媒體,收藏這些「短視頻乾貨」,我相信不會讓你失望,不僅如此,它們還可以幫助你快速學會賺技能,讓你快速賺取自己的第一桶,別急,往下看: 我簡單總結了一下,總共分為3個板塊,每一個板塊都是滿滿的乾貨,大家記得「點讚+收藏」 第一個板塊:零基礎自學網站。
  • 幫你解讀什麼是Redis緩存穿透和緩存雪崩(包括解決方案)
    一、緩存穿透1、概念緩存穿透的概念很簡單,用戶想要查詢一個數據,發現redis內存資料庫沒有,也就是緩存沒有命中,於是向持久層資料庫查詢。發現也沒有,於是本次查詢失敗。這裡需要注意和緩存擊穿的區別,緩存擊穿,是指一個key非常熱點,在不停的扛著大並發,大並發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大並發就穿破緩存,直接請求資料庫,就像在一個屏障上鑿開了一個洞。為了避免緩存穿透其實有很多種解決方案。下面介紹幾種。
  • 大疆發布OSMO ACTION新固件以優化性能
    新固件優化了記錄8倍慢動作視頻的畫質表現,同時修復了一系列機身bug,建議各位用戶都下載並升級,以帶來更好的拍攝體驗。前後雙屏取景拍攝,是這款相機最出彩的亮點之一大疆OSMO ACTION運動相機V01.03.00.10版固件升級內容:1、優化8倍慢動作視頻畫質。
  • 《姐夫美食課堂》帶你認識老廣的乾貨--海鮮乾貨篇
    老廣的乾貨種類很多,海鮮乾貨,水果乾貨,藥材種類更是首屈一指。這樣說吧,我相信中醫在全國範圍來說,數老廣最為常用,本人小時候有什麼病痛基本上都是喝中藥,今天我給大家介紹下老廣的海鮮乾貨。海鮮乾貨顧名思義肯定就是海鮮曬乾儲存啦,海鮮本身鮮,但是同樣的腥味濃重,曬乾後更是加倍,精華同樣的也濃縮。