java—11 Redis

目錄

一、Redis概述

二、Redis類型及編碼

三、Redis對象的編碼

1. 類型&編碼的對應關系

2. string類型常用命令

(1)string類型內部實現——int編碼

(2)string類型內部實現——embstr編碼

?編輯

?(3)string類型內部實現——raw編碼?

3. list類型常用命令

(1)列表常用操作

(2)list類型內部實現——ziplist編碼

?(3)list類型內部實現——linkedlist編碼

4. set類型常用命令

(1)set類型內部實現——intset編碼

(2)set類型內部實現——hashtable編碼?

5. zset類型常用命令

(1)zset類型內部實現——ziplist編碼

(2)zset類型內部實現——skiplist編碼?

6. hash類型常用命令

(1)hash類型內部實現——ziplist編碼

四、Redis數據結構

1. SDS簡單動態字符串

2. 為什么Redis使用SDS而不是C字符串?

(1)SDS空間預分配

(2)SDS惰性空間釋放

3.?list雙向鏈表

(1)list雙向鏈表源碼部分

(2)list雙向鏈表數據結構及特點

4. 哈希表

(1)哈希表源碼部分

(2)哈希表數據結構

5. dict字典

(1)dict字典源碼部分

(2)Dict字典數據結構

6. skiplist跳躍表

(1)skiplist跳躍表源碼部分

(2)跳表的數據結構

五、Redis持久化

1. RDB概述

2. RDB的備份與恢復

3. AOF概述

4. appendfsync配置詳解

5.?什么叫寫入?什么叫同步?有什么區別呢?

6. AOF加載流程

7. AOF重寫

六、三種特殊數據類型

1. geospatial地理位置

2. hyperloglog預估集合的基數

3. bitmap位圖

七、事務管理

事務中異常的處理

八、發布訂閱

1.?Redis針對發布訂閱相關指令?

九、主從復制

1. 主從復制的用處?

2. 主從復制實現原理

?3. psync指令

4. 復制偏移量

5. 復制積壓緩沖區&節點ID

十、Redis哨兵

1. 多哨兵模式

2. 環境搭建(3哨兵 1主2從)

3. INFO指令獲得最新節點拓撲圖

4.?哨兵監測集群狀態方法

5. 選舉流程

十一、Redis Cluster

1. 分片方式

(1)哈希取模

(2)一致性哈希

(3)虛擬節點 + 一致性哈希

2. 集群搭建

十二、面試

1. 緩存穿透(查不到數據)

2. 緩存擊穿(高并發查詢某數據,且緩存過期)

3. 緩存雪崩(緩存大批量失效或Redis宕機)

4. 布隆過濾器


面:

數據結構:String、hash、set、zset、list

什么是RDB?RDB和AOF的區別:

一、Redis概述

Redis就是緩存,Redis基于內存,將大量訪問的數據放到緩存,而不是數據庫,這樣不會訪問數據庫,如果都放到內存,內存是jvm中的,無法保證多線程共享同一份內存,所以使用Redis。

數據存在內存中,但是可以對其進行持久化,這樣內存宕機之后,數據也不會丟失。

Redis是開源的(BSD許可),數據結構存儲于內存中,被用來作為數據庫,緩存和消息代理。 它支持多種數據結構,例如:字符串(string),哈希(hash),列表(list),集合(set), 帶范圍查詢的排序集合(zset),位圖(bitmap),hyperloglog,帶有半徑查詢和流的地理 空間索引(geospatial)。 Redis具有內置的復制,Lua腳本,事務和不同級別的磁盤持久性, 并通過Redis Sentinel(負責主從情況下選主Redis Cluster自動分區提供高可用性。

安裝Redis

官網 :Downloads - Redis

  1. 啟動redis服務端:src/redis-server --daemonize yes
  2. 開啟redis客戶端:src/redis-cli

Redis Sentinel

二、Redis類型及編碼

5種基本數據類型:String、hash、set、zset、list

Redis是key-value鍵值對,key肯定是string類型的,value是RedisObject類型的,包括多種類型。

  • OBJECT encoding key:可以查看key對應的value的encoding類型。

三、Redis對象的編碼

encoding常量編碼所對應的底層數據結構
REDIS_ENCODING_INTlong類型的整數
REDIS_ENCODING_EMBSTRembstr編碼的簡單動態字符串
REDIS ENCODING_RAW簡單動態字符串
REDIS_ENCODING_HT字典
REDIS_ENCODING_LINKEDLIST雙向鏈表
REDIS_ENCODING_ZIPLIST壓縮列表
REDIS_ENCODING_INTSET整數集合
REDIS_ENCODING_SKIPLIST跳表和字典

跳表的概念重要:因為可以快速查詢,比樹結構好維護,查詢效率也不會差多少?

1. 類型&編碼的對應關系

對象類型(type)對象編碼(encoding)
REDIS_STRINGREDIS_ENCODING_INT
REDIS_ENCODING_EMBSTR
REDIS_ENCODING_RAW
REDIS_LISTREDIS_ENCODING_ZIPLIST
REDIS_ENCODING_LINKEDLIST
REDIS_SETREDIS_ENCODING_INTSET
REDIS_ENCODING_HT
REDIS_ZSETREDIS_ENCODING_ZIPLIST
REDIS_ENCODING_SKIPLIST
REDIS_HASHREDIS_ENCODING_ZIPLIST
REDIS_ENCODING_HT

(能記住最好)

2. string類型常用命令

命令行

含義

set key value

賦值key的值為value

get key / del key

獲取key的value值 / 刪除key

expire key seconds

設置key在seconds秒后過期

setex key seconds value

SET + EXPIRE的組合指令

ttl key

查看key還有多久過期

setnx key value

如果key不存在,才新增key和value

strlen key

計算指定key的值的長度

incr key value

值加1

incrby key numbers

指定增加值,numbers可以是負值

mset key1 value1 key2 value2 …

批量添加

mget key1 key2 key3 …

批量獲取

用JSON的形式將對象存到value中,擴容規則:當value<=1M時翻倍擴容,當>1M時,每次擴容1M。字符串的長度不能超過512M

setex key time value :在設置key-value對象的同時設置了過期時間,

string類型的三種編碼:

REDIS_ENCODING_INT
REDIS_ENCODING_EMBSTR
REDIS_ENCODING_RAW

int:long長度范圍內的純數字,超過long長度范圍的話就是embstr

embstr:長度小于40位的數字+字符。一次內存分配,RedisObject和sdshdr是連續的。

raw:>=40位的數字加字符。兩次內存分配,靠指針連接RedisObject和sdshdr。訪問速度比embstr慢,但是因為不連續使得內存要求不高。

(1)string類型內部實現——int編碼

如果保存的value值,可以用long類型表示(-9223372036854775808 ~ 9223372036854775807),那么encoding就是int編碼,如果超過了long類型的長度,則會轉換為embstr編碼。

(2)string類型內部實現——embstr編碼

value值的長度如果小于40,則使用embstr,它可以保存數字類型和字符類型的值。embstr編碼是專門用于保存短字符串的一種優化編碼方式。

Redis沒有為embstr編碼的字符串對象提供修改功能,所以embstr是只讀的。如果我們對其進行修改,其實是先轉換成raw,再執行修改命令。所以,修改后embstr就會變為raw編碼的字符串對象了

?(3)string類型內部實現——raw編碼?

當value值的長度如果大于等于40時,則使用raw編碼。

如果將原本保存的整數轉換為字符串,那么字符串對象的編碼也將從int變為raw。

3. list類型常用命令

命令行

含義

lpush key value1 value2

左側插入value

rpush key value1 value2

右側插入value

lpop key

左側彈出value

rpop key

右側彈出value

llen key

查看key的長度

lindex key index

查看列表中某個index對應的value值

lrange key startIndex endIndex

查看指定元素,下標從0開始,-1為倒數第一個

ltrm key startIndex endIndex

僅保留某區間的列表,其余元素全被刪除

ltrm key start end中是去掉start之前和end之后的,保留start到end的閉區間的。ltrm key 1 0是刪除所有元素。

(1)列表常用操作

list類型的兩種編碼:?

REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_LINKEDLIST

(2)list類型內部實現——ziplist編碼

ziplist編碼列表對象,采用壓縮列表實現。每個列表節點保存一個列表中的元素。當我們執行RPUSH testlist a b c之后,其數據結構如下:

?(3)list類型內部實現——linkedlist編碼

linkedlist編碼列表對象,采用雙向鏈表作為底層實現,每個節點保存一個元素。數據結構如下:

如果滿足所有元素長度小于65字節 并且 列表中元素的個數小于512個ziplist類型,否則是linkedlist類型;連續存儲,內存連續時訪問速度是最快的

4. set類型常用命令

Set類型:主要目的是去重

命令行

含義

sadd key value1 value2

添加元素到集合中

smembers key

查看集合中的所有元素

sismember key value

查看value是否在集合中

scard key

查詢集合的長度

spop key

取出集合中的一個元素

del key

刪除集合

set類型的兩種編碼:

REDIS_ENCODING_INTSET
REDIS_ENCODING_HT

(1)set類型內部實現——intset編碼

intset編碼集合對象使用整數集合作為底層實現,集合對象包含的所有元素都被保存在整數 集合里面。數據結構如下所示:

(2)set類型內部實現——hashtable編碼?

當使用字典作為底層實現,每個鍵都是一個字符串對象,每個字符串對象包含了一個集合 元素,而字典的值則全部被設置為NULL。數據結構如下所示:

如果填加的是字符類型的,輸出的就是亂序的。如果填加的是純數字類型的話,輸出就是升序的。

當集合對象同時滿足以下 兩個條件時,使用intset 編碼,否則使用 hashtable編碼:

  • ① 集合對象保存的所有元 素都是整數值。
  • ② 集合對象保存的元素數 量不超過512個。

Intset -->?hashtable:

  • 1. 存入幾個數字是intset,再存入字符類型的變成hashtable;
  • 2. 存入了512個數字是intset,再存入一個數字也會變成hashtable。

5. zset類型常用命令

命令行

含義

zadd key score1 value1 value2 score2

添加元素到有序集合中

zscore key value

查看key的score值,輸出score>=負無窮, score<=正無窮的所有元素

zrange key 0 -1

正序輸出

zrangebyscore key -inf +inf

正序輸出

zrevrange key 0 -1

倒序輸出

zcard key

查看key中的元素個數

zrangebyscore key indexStart endStart

獲得key中score>=indexStart 且 score<=endStart的元素,正序排列

zrevrangebyscore key indexStart endStart

同上,倒序排列

zrem key value

刪除key中的元素value

zrangebyscore key indexStart endStart

獲得key中score>=indexStart 且 score<=endStart的元素,正序排列

相當于閉區間,如果想要開區間,則zrangebyscore key (indexStart endStart.

zset類型的兩種編碼:

REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_SKIPLIST

(1)zset類型內部實現——ziplist編碼

ziplist使用壓縮列表作為底層實現,每個集合元素使用兩個緊挨在一起的壓縮列表節點來保 存,第一個節點保存元素的成員(member),而第二個節點則保存元素的分值(score)。 壓縮列表內的集合元素按分值(score)從小到大進行排序

當有序集合對象可以同時滿足以下兩個條件時,使用ziplist編碼,否則使用skiplist編碼:

  • ① 有序集合保存的元素數量小于等于128個。
  • ② 有序集合保存的所有元素長度都小于64字節。

(2)zset類型內部實現——skiplist編碼?

skiplist編碼的有序集合采用zset結構作為底層實現,一個zset同時包含一個字典dict和一個跳躍表zskiplist。?

6. hash類型常用命令

命令行

含義

hset key name value

添加屬性元素name和value到key中

hget key name

查看key的name值

hmset key name1 value1 name2 value2

批量添加key的屬性元素

hmget key name1 name2

批量獲取key的屬性元素

hlen key

獲得key的屬性元素個數

hgetall key

查詢key中的所有元素

hash類型的兩種編碼:

REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_HT

(1)hash類型內部實現——ziplist編碼

ziplist編碼底層使用壓縮列表實現,當有新的鍵值對要加入到哈希對象時,會先將key值從 隊尾推入壓縮列表中,再將這個key對應的value值從隊尾推入壓縮列表中;所以,同一鍵 值對的兩個節點總是緊挨在一起的——key在前,value在后

(2)hash類型內部實現——hashtable編碼

同時滿足兩個條件時是ziplist編碼類型,否則為hashtable編碼類型

  • ① 哈希對象中所有鍵值對中,key和value的長度均小于等于64字節
  • ② 哈希對象中鍵值對的個數小于512個

四、Redis數據結構

1. SDS簡單動態字符串

SDS(simple dynamic string),簡單動態字符串。是由Redis自己創建的一種表示字符串 的抽象類型。與C語言不同的是,C語言字符串是不可被修改的。但是SDS是動態可以被修 改的。

最后一位遵循C字符串的空字符('\0')結尾的規則,目的是可以直接使用C字符串的函數。 其中:len計數不包含‘\0’。

2. 為什么Redis使用SDS而不是C字符串?

第1點:C語言沒有字符串的類型,關于字符串長度的計算。C字符串沒有記錄字符個數,每次都需要遍歷,所以復雜度為 O(n)。SDS的len記錄了當前字符串的長度,所以獲取字符串長度的復雜度為O(1)。(C語言沒有字符串的類型,只能用數組表示。只能存儲數據,沒有數據計算的能力。Sdshdr中存儲了字符串的長度,當需要查詢長度的時候直接從sdshdr中獲取即可,時間復雜度O(1),而如果是C語言數組的話要去計算每個字符串的長度,時間復雜度是O(N)?)

第2點:關于緩沖區溢出。C字符串無法杜絕緩沖區溢出。比如執行strcat函數時,如果 沒有指定足夠的內存,那么拼接后會造成緩沖區溢出。SDS在進行修改時,會先查看空 間是否足夠,如果不夠了,那么它的API會自動的進行空間擴展。用name1的muse去拼接John的時候,之前的bob就會被沖掉。具體情況如下所示:

比如:之前name1是muse,name2是bob, 然后忘記在執行strcat操作之前為s1分配足夠 空間了,name1變成了musejohn,那么, name2的內容就被修改了。

第3點:SDS采用了空間預分配&惰性空間釋放來減少性能消耗。空間預分配:SDS會提前多申請一些空間(如下圖)。惰性空間釋放:當刪除了一些字符,空出來一些空間,這些空間不會被釋放,無需跟操作系統交流。而是在sdshdr中更改free記錄的空余空間數,當有新的字符串需要這些空間時,直接使用空余的空間,不需要重新請求空間。

(1)SDS空間預分配

如果對SDS進行修改后,SDS的 長度(len的長度)小于1MB的 時候,那么程序分配和len屬性同樣大小的未使用空間 (free)。如果大于1MB,那么程序會分配1MB的未使用空 間(free)

(2)SDS惰性空間釋放

當有縮短SDS字符串操作時,程序并不立即把空閑出來的字節釋放掉,而是使用free屬性將這個空閑的字節記錄起 來,等待將來使用。如右圖所示:

3.?list雙向鏈表

(1)list雙向鏈表源碼部分

鏈表的特點是高效的刪除新增節點來靈活地調整鏈表中的元素順序。

由于C語言沒有內置鏈表,所以Redis自己構建 了鏈表的實現

Redis基本數據結構中的REDIS_LIST,底層的實 現之一就采用的鏈表。即:當包含了很多元素, 或者元素中有比較長的字符串時,就會采用鏈 表作為REDIS_LIST的底層實現。

(2)list雙向鏈表數據結構及特點

雙端:具有prev和next指針,獲取某個節點的前置/后置節點的復雜度為O(1)。

無環:頭節點的prev=NULL,尾節點的next=NULL,對鏈表的訪問以NULL為終點。

帶表頭/表尾指針:list結構中包含head指針和tail指針,所以獲得鏈表頭節點/尾節點的復雜 度為O(1)。

多態性:可以通過設置dup、free、match這三個不同類型特定函數,保存各種不同類型的 節點值。

List雙向鏈表數據結構:

Head指向鏈表頭,tail指向鏈表尾,len記錄了鏈表的長度,當鏈表中新增或刪除節點后,len記錄的值會相應變化。如果想要獲得鏈表的長度時,直接返回len記錄的值即可,無需每次都去計算鏈表的長度。

4. 哈希表

(1)哈希表源碼部分

字典又被稱為符號表、關聯數組、 映射(map)。是一種用于保存 鍵值對的抽象數據結構。

C語音并沒有內置這種數據結構, 因此Redis構建了自己的字典實 現。

字典是哈希鍵的底層實現之一, 當一個哈希鍵包含的鍵值對比較 多,又或者鍵值對中的元素都是 比較長的字符串時,Redis就會 使用字典作為哈希鍵的底層實現。

(2)哈希表數據結構

類似于hashtable,數組+鏈表的形式。

5. dict字典

(1)dict字典源碼部分

(2)Dict字典數據結構

更復雜的hashtable

6. skiplist跳躍表

(1)skiplist跳躍表源碼部分

?跳躍表是一種有序數據結構

Redis使用跳躍表作為有序集合鍵的底層實 現之一,如果一個有序集合包含的元素數 量比較多,或者有序集合中元素的成員是 比較長的字符串時,Redis就會使用跳表來 作為有序集合的底層實現。

Redis只在兩個地方用到了跳躍表: ① 實現有序集合鍵。 ② 在集群節點中用作內部數據結構。

(2)跳表的數據結構

空間換時間的解決方案。層數越多,查詢效率越高,類似于查字典。默認有32層。查找的時候是同層查找,span是跨度,也就是同層跨越幾個節點。Forward是向后查找,如果找不到,要backward去一一查找

表結構包含了層級信息和節點信息

(3)skiplist跳躍表的使用

作用:快速查找到要找的元素。

五、Redis持久化

(面)

1. RDB概述

RDB持久化支持手工執行和服務器定期執行,RDB持久化產生的文件是一個經過壓縮的二進 制文件,對應文件為dump.rdb,因為它保存在磁盤上,所以可以用它來還原Redis數據庫中的數據。宕機重啟后,通過讀取二進制文件dump.rdb,將數據還原回來。

保存手工執行RDB保存有兩個命令:SAVE命令和BGSAVE命令。

SAVE命令會阻塞Redis服務器進程,直到RDB文件生成完畢都會一直處于阻塞狀態,不能處理任何的Redis命令請求;BGSAVE命令會fork一個子進程來生成RDB文件,Redis 服務器進程不受影響,可以繼續處理命令請求。

當服務器啟動的時候,RDB自動執行加載,沒有專門的命令來加載RDB文件。只要Redis啟 動時檢測到RDB文件的存在,那么就會自動載入RDB文件。加載過程中,會一直處于阻塞狀 態,直到加載完畢為止。由于AOF文件的更新頻率一般比RDB文件的更新頻率高,所以,如 果服務期開啟了AOF持久化功能,那么就優先加載AOF文件,否則,加載RDB文件。

RDB(Redis database) & AOF(Append Only File):

Redis的數據存儲在內存中,如果宕機了,不作持久化的話,數據就會丟失。

2. RDB的備份與恢復

BGSAVE執行條件檢測器——serverCron

serverCron默認每100毫秒執行一次條 件驗證,如果符合保存條件,則執行 BGSAVE命令。

它會通過dirtylastsave(間隔時間= 當前時間-lastsave時間)這兩個參數, 來判斷是否執行BGSAVE命令。

SAVE和BGSAVE生成RDB文件,隨著服務啟動自動加載進內存中(圖片右上角)。

Cron表達式:定期去執行。

RDB和AOF的區別:

BGSAVE將數據保存到庫里邊,AOF是將對應的指令保存到文件里。

3. AOF概述

AOF(Append Only File)持久化,它是通過保存Redis執行命令來記錄數據庫數據變更。 持久化流程如下所示:

如何開啟AOF和配置AOF路徑——redis.conf文件:

AOF的持久化分為三步:命令追加——>文件寫入——>文件同步,如果打開AOF后,每 次執行完一個寫命令之后,都會把寫命令以請求協議格式保存到aof_buf緩沖區的末尾。

AOF是對指令進行備份,先將數據持久化到數據庫,然后再將改變寫入AOF文件中。

寫入和同步都是OS級別的,調用write函數時,將數據放入操作系統的緩存中,在一定時間范圍內,將緩存中的數據刷到磁盤上,寫入是寫到緩存?緩沖中,同步是將緩存?緩沖中的數據刷到真正的磁盤上。

AOF怎么使用:在一個客戶端輸入操作命令,例如“set name muse”,然后打開AOF文件:“BGREWRITEAOF”,再打開另一個客戶端,cd redis/src? cat appendonly.aof,可以從.aof文件中看到前一個客戶端中所做的Redis操作命令。在讀取.aof文件時,將其中記錄的指令再執行一次,達到恢復數據庫操作的目的。

Redis的服務器進程就是一個事件循環,在這個循環中:

  • 文件事件負責接收客戶端的命令請求和發 送給客戶端執行結果回復。
  • 時間事件負責執行如serverCron這種需要 定時運行的函數。
  • 當每次一個事件循環結束之前,都會調用 flushAppendOnlyFile函數,來判斷是否需要 將aof_buf緩沖區中的內容寫入和同步到 AOF文件中。
  • 其中,flushAppendOnlyFile函數的行為由 appendfsync配置決定(redis.conf文件中)

4. appendfsync配置詳解

5.?什么叫寫入?什么叫同步?有什么區別呢?

為了提高文件的寫入效率,在現代操作系統中,當用戶調用write函數時,將一些數據寫 入到文件的時候,操作系統通常會將寫入數據暫時保存在一個內存緩沖區里面,等到緩沖 區的空間被填滿、或者超過了指定的時限之后,才真正地將緩沖區中的數據寫入到磁盤里 面。

這種做法雖然提高了效率,但也為寫入數據帶來了安全問題,因為如果計算機發生停機, 那么保存在內存緩沖區里面的寫入數據將會丟失。

為此,操作系統提供了fsync和fdatasync兩個同步函數,它們可以強制讓操作系統立即將 緩沖區中的數據寫入到磁盤里,從而確保寫入數據的安全性。

6. AOF加載流程

當Redis服務啟動并讀取AOF,即可恢復關閉前的數據狀態。加載流程如下:

Fack Client(偽客戶端)的執行命令效果與帶網絡的效果完全一樣。由于載入AOF時, 命令來源于AOF文件,而不是網絡連接傳遞過來的命令,所以,建立了一個沒有網絡連接 的偽客戶端。

Redis服務啟動的時候,如果檢測到了AOF,就會先加載AOF,如果AOF是關閉的或者檢測不到,就以RDB為主。

偽客戶端的作用:執行指令,恢復數據。執行完畢,自動關閉偽客戶端。

7. AOF重寫

(面)

AOF重寫:基于數據重新生成一份AOF,實現AOF瘦身(對指令進行備份)。當重寫的時候,Redis不能再做別的操作,防止造成數據不一致的問題,但是當操作數據頻繁時,AOF重寫不方便,于是創建AOF的時候,開啟一個子進程,在子進程中進行重寫操作。

Redis.conf文件中:

Auto-aof-rewrite-percentage 100:比上一次重寫的大小增多了100%時,會自動觸發重寫(體積)

Auto-aof-rewrite-min-size 64mb:AOF文件超過了64M的時候,觸發一次重寫。

流程圖中:

【執行“重寫AOF”】如果不滿足(當不需要重寫的時候),則執行【執行指令寫入AOF操作】,然后進入【AOF緩沖區】步驟,當需要重寫的時候(redis.conf文件中判斷),執行【開啟子進程】,重寫是基于當前的數據快照寫入的,如果在3:00到3:05分執行重寫操作,那么在這5分鐘的時間內對于數據庫進行的新操作,會寫進【AOF重寫緩沖區】,該緩沖區與重寫操作同步開啟。在3:05重寫完成后,精簡后的操作步驟寫入【新的AOF文件】,重寫完成后【向父進程發送信號,父進程調用信號處理函數】,然后【阻塞服務器進程】,該位置的阻塞是為了將【AOF重寫緩沖區】中的數據補充到【新的AOF文件】中,因為時間比較短,【AOF緩沖區】中的指令也不會很多,通過將redis停止掉,將額外的數據補充到【新的AOF文件】,這個過程速度很快,然后用【新的AOF文件】【覆蓋舊的AOF文件】,覆蓋完成后,再將進程放開,就可以正常地對外提供服務了。

六、三種特殊數據類型

1. geospatial地理位置

快遞,外賣等使用場景

可以用于基于地理位置的業務場景。比如:查詢兩地之間的距離,方圓幾里存在的地理 位置等等。經緯度查詢https://jingweidu.bmcx.com。

(1)創建數據集:

GEOADD key(city) 經度 緯度 cityname

(2)查詢兩地之間的距離

GEODIST city beijing shanghai km

(3)GEOHASH:52位長度的編碼,通過hash可以表示經度和緯度

GEOHASH city beijing shanghai haerbin (返回的是三個位置的hash編碼)

(4)獲得某個位置的經緯度:

GEOPOS city Beijing

(5)查看所有的city

ZRANGE city 0 -1

(6)雷達圈尋,查找指定坐標在某個半徑范圍內包含的所有位置

GEORADIUS city 116 40 1500 km WITHCOORD WITHDIST ASC

查詢在以(116,40)為圓心,1500km為半徑的圓圈范圍內的所有地址,以升序返回【地址名稱】【距離圓心的長度】【該位置的經度和緯度】

(7)雷達圈尋,查找指定city在某個半徑范圍內包含的所有位置

GEORADIUSBYMEMBER city beijing 1500 km WITHCOORD WITHDIST ASC

2. hyperloglog預估集合的基數

不精準但是快,適用于量大但是對具體數據要求不敏感的,例如對接口的訪問量級,看柱狀圖的數據

hyperloglog常用的使用場景,一般是非精準性的統計計數。比如:統計訪問網站的UV 數,商品評論數或點擊量等等。

HyperLogLog 是一種用于計算唯一事物的概率數據結構(從技術上講,這稱為預估集合 的基數)

它占用的空間很小,只需要12KB的內存,可以存儲2^64不同的元素數量。但是它的統 計是有小于1%的誤差,所以并不適合精準統計使用場景。

?(1)?? ?新建數據集并向內新增元素
PFADD user muse bob tom tony muse
(2)?? ?計數
PFCOUNT user
返回 4 。有去重的作用
(3)?? ?兩個數據集合并
PFADD vip james muse cartern (創建另一個數據集vip)
PFMERGE alluser user vip ?(合并user和vip數據集)
PFCOUNT alluser ? (去重計數)
返回6

3. bitmap位圖

不占空間,效率較高。Hyperloglog和bitmap適用于大數據量,用來看統計結果,而不是明細的場景。

可以利用bitmap指定其二進制位是0或1,來實現類似“是”or“否”的相關操作。它的 特點也是占用內存空間特別的小。比如,我們要記錄每個用戶當天是否活躍(即:是否 登錄過系統),那么如果我們要記錄他一年的是否登錄的記錄,只需要365個bit即可存 儲。

七、事務管理

半事務,保證語句的原子性,不能保證其他

事務管理:用于保證指令的原子性,功能沒有很強大。

事務的本質,其實就是一組命令的集合。一個事務中的所有命令都會按照命令的順序去 執行,而中間不會被其他命令加塞。沒有隔離性

DISCARD:放棄事務的執行

EXEC:執行事務(提交事務)

MULTI:開啟對應的事務?

UNWATCH:解除監控

WATCH:監控

示例:同一IP和端口開啟兩個客戶端用作測試

客戶端1:set account 1000

客戶端1和2:get account ,返回結果均為1000

客戶端1:開啟對應的事務: MULTI

客戶端1:進行一系列的操作

????????set account 2000

????????set account 800

????????set account 500

以上三條指令將操作加入到隊列,其實還沒有真正執行。在客戶端2查不到這三條指令所做的更改。如果要真正地執行,需要EXEC,這是依次執行以上三條指令,中間不能再插入其他指令(單進程執行)。

客戶端1:EXEC

這時再get account返回的是500

客戶端1:MULTI 開啟事務

????????set account 2000

????????set account 800

客戶端1:DISVARD 放棄執行事務

????????get account

?? 返回的是500,設置為2000和800的兩條指令不會操作。

事務監控功能

客戶端1:WATCH account

客戶端1:MULTI

客戶端1:set account 1000

客戶端1:set account 1500

客戶端1:set account 700

客戶端2:get account 返回5? ? ?00

客戶端2:set account 5000

客戶端2:get account 返回5000

客戶端1:EXEC

客戶端1:get account 返回的不是700,而是5000.

以上結果的原因是:客戶端1開啟事務之前開啟了WATCH監控功能,此時可以發現在客戶端2對account進行了修改,于是在客戶端1隊列中的事務操作就會放棄執行。

如果不開啟WATCH監控功能:(現在賬戶是5000)

客戶端1:MULTI 開啟實物功能

客戶端1:set account 1000

??????????? Set account 700

客戶端2:set account 500

客戶端2:get account 返回500

客戶端1:EXEC 執行成功

客戶端1:get account 返回700

因為沒有開啟WATCH監控功能,所以客戶端2進行了更改之后,再去執行事務操作,依舊可以成功。

事務管理需要注意的兩點:

  1. 每次需要監控,都要在開啟事務之前開啟監控功能
  2. 針對命令語法錯誤,會導致整個事務執行被中斷;針對執行中的運行操作錯誤(異常),只會導致該條指令的執行失敗,不會影響事務中的其他指令。(示例如下)

針對命令語法錯誤

本來account中是700;

客戶端1:MULTI

客戶端1:set account 2000

客戶端1:setaccount 1500? 執行時會報錯(語法錯誤)

客戶端1:set account 1500

客戶端1:EXEC??? 執行時報錯

客戶端1:get account? 返回700,即事務中的指令都不會執行

針對執行中的運行異常

本來address中存的是beijing;

客戶端1:MULTI? 開啟事務

客戶端1:set address liaoning

客戶端1:INCR address

客戶端1:set address shanghai

客戶端1:EXEC? 此時回車顯示語句1和3執行成功,語句2執行失敗

客戶端1:get address? 返回“shanghai”

事務中異常的處理

命令語法錯誤:針對語法錯誤,會導致整個事務 執行被中斷

?運行操作錯誤:針對執行中的異常,只會導致該 條指令的執行失敗,而不會影響事務 中其他的指令

八、發布訂閱

如果熟悉消息中間件,那么對發布訂閱一定不陌生。發布者Publish一條消息,消息發送 到Channel通道中,然后所有訂閱了這個通道的訂閱者Subscriber都會接收到這條消息。 如下圖所示:

1.?Redis針對發布訂閱相關指令?

示例:

(1)基礎

客戶端1:SUBSCRIBE muse

客戶端2:PUBLISH muse hello? 此時客戶端1的控制臺會輸出message:“hello”

(2)匹配模式pattern

客戶端1:PSUBSCRIBE h[ae]llo

客戶端2:PUBLISH hallo 1111? ??客戶端1可以接收到1111

客戶端2:PUBLISH hello 1111? ??客戶端1可以接收到1111

客戶端2:PUBLISH hillo 1111? ???客戶端1接收不到1111

(3)訂閱通道PUBSUB,無法基于pattern

客戶端1:SUBSCRIBE muse???? (這里如果設置的是PSUBSCRIBE m*se,下邊第二條也不能訂閱成功,因為不基于pattern)

客戶端2:PUBSUB CHANNELS muse? 客戶端2可以訂閱成功

客戶端2:PUBSUB CHANNELS m1se? 客戶端2訂閱不成功

(4)查看訂閱數量 PUBSUB NUMPAT

客戶端2:PUBSUB NUMPAT? 返回訂閱者的數量

客戶端2:PUBSUB NUMSUB muse 返回非pattern模式訂閱者的數量。

九、主從復制

主從復制,是指將一臺Redis服務器的數據復制到其他的Redis服務器。前者稱為主節點 (Master/Leader),后者稱為從節點(Slave/Follower);數據是從主節點復制到從節點的。其中,主節點負責寫數據(當然有讀的權限),從節點負責讀數據(它沒有寫數 據的權限)。默認的配置下,每個Redis都是主節點。

一個主節點可以有多個從節點,但是一個從節點只能有一個主節點,即:主從節點是1對N的關系。(問題:不能自動選主)

1. 主從復制的用處?

數據冗余:主從復制實現了數據的備份,實際上提供了數據冗余的實現方式。實現高可用性

故障恢復:當主節點出現異常時,可以由從節點提供服務,實現快速的故障恢復,實際上提供了服 務冗余的實現方式。主節點出現故障,從節點用來提供服務,這時主節點可以用來故障恢復。

負載均衡:在主從復制的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務, 分擔服務器的負載; 在寫少讀多的業務場景下,通過多個從節點分擔讀負載,可以大大提高 Redis服務器是并發量。

高可用:哨兵配合主從復制,可以實現Redis集群的高可用。當主節點掛掉之后,由哨兵從從節點中選擇一個節點作為主節點。

主機宕機之后,從節點依舊無法成為主節點,還是只能提供讀操作。

環境搭建:6380為主節點,6381和6382為從節點。

2. 主從復制實現原理

Redis的主從復制可以分為兩個階段:sync階段和command propagate階段。當從節點啟 動后,會發送sync指令給主節點,要求全量同步數據,此為sync階段;那么,如果后續 Master節點接收到新的增刪改操作,也需要Slave節點接收同步的更新,這就是command propagate階段;

?3. psync指令

當主從節點都正在運行的時候,出現了網絡抖動,造成連接斷開,那么當網絡恢復,兩個 節點再次建立起連接的時候。從節點發送sync指令后,主節點依然需要重新生成RDB,并 對從節點進行全量數據的同步造成。那么這中間的耗時是非常嚴重的,并且傳輸備份文件 也會對網絡帶寬造成很大的消耗。那么為了解決這個問題,從Redis 2.8開始,引入了 psync指令來代替sync指令。psync指令會根據不同的情況,來確定執行全量重同步還是部 分重同步。

全量重同步:當從節點是第一次與主節點建立連接的時候(或者兩次同步之間數據差異量非常大:大的程度由部分重同步判斷),那么就會執行全量重同步,這個同步過程 與上面我們介紹的sync階段+command propagate階段一樣。

部分重同步:從節點的復制偏移量無法在復制積壓緩沖區中找相應待同步的數據 并且 主節點與從節點不是第一次同步(根據判斷)

4. 復制偏移量

Master節點和Slave節點都保存著一份復制偏移量。當Master節點每次向Slave節點發送n 字節數據的時候,就會在Master節點偏移量加上n;而Slave節點每次接收到n個字節的 時候,也會在Slave節點偏移量上加n。在命令傳播階段,Slave節點會定期的發送心跳 REPLCONF ACK{offset}指令,這里的offset就是Slave節點的offset。當Master節點接 收到這個心跳指令后,會對比自己的offset和命令里的offset,如果發現有數據丟失,那 么Master節點就會推送丟失的那段數據給Slave節點。如下圖所示:

5. 復制積壓緩沖區&節點ID

什么是復制積壓緩沖區?

復制積壓緩沖區是由主節點維護的一個固定長度(默認1MB)的隊列。它存儲了每個字節值與對應的復制偏移量。因為復制積壓緩沖區的大小是固定的,所以它保存的是主節點近 期執行的寫命令。當從節點將offset發送給主節點后,主節點便會根據offset與復制積壓緩 沖區的大小來決定是否可以使用部分重同步。如果offset之后的數據仍然在復制積壓緩沖區 內,則執行部分重同步;否則還是執行全量重同步。

節點ID:

Redis節點服務啟動之后,就會產生一個用來唯一標識Redis節點的ID。當Master節點與 Salve節點進行第一次連接同步的時候,Master節點會將ID發送給Slave節點,Slave節點接收 到會對其進行保存。那么當主從服務之間發生了中斷重連的時候,Slave服務器會將這個ID 發送給Master服務器,Master服務器會拿自己的ID進行對比,如果相同,則說明主從之前是 連接過的。否則,則說明是第一次建立的連接。那么,就需要全量去同步數據了。

十、Redis哨兵

我們介紹主從復制的時候發現,主節點掛掉從節點不會自動變為主節點,需要人工的去 配置主節點才可以。但是這種做法費時費力,怎樣能讓Redis在主節點掛掉的情況下,自 己從從節點中選擇新的主節點呢?這時候,就需要使用Sentinel哨兵了。

哨兵本質就是一個Redis實例節點。哨兵模式是一種特殊的模式,它能夠后臺監控主機是 否故障,如果故障了,則根據投票數自動將Slave節點轉換為新的Master節點。 首先 Redis提供了哨兵的命令,哨兵是一個獨立的進程,會獨立的運行。它的原理是:哨兵通過發送命令,等待Redis服務器響應,從而監控運行的多個Redis實例。如下圖所示:

主節點宕機后,推選出新的主節點,這時當重啟后,原來的主節點下沉為從節點。這個過程由Sentinel完成,不需要手動去做。是如何做點:重寫redis.command文件,在該文件中可以指定主節點是哪一個,重啟的時候根據配置文件中設置的主從節點的拓撲圖。

多個Sentinel之間不存在主從的概念,是平行角色,會相互監控,多個Sentinel投票選擇一個slave作為master。如果Sentinel只剩了一個,就沒有了選主的能力。

1. 多哨兵模式

然而一個哨兵進程對Redis服務器進行監控,可能會出現問題。因此,我們可以使用多哨 兵進行監控。各個哨兵之間還會進行監控,這樣就形成了多哨兵模式。

主觀節點下線:SentinelA等待master的相應,在規定時間內沒有響應,則為主觀master下線。

客觀節點下線:多個Sentinel對master節點進行的判斷。半數以上認為下線則認為master下線。再去根據投票結果選擇slave升級為master。

2. 環境搭建(3哨兵 1主2從)

哨兵配置文件sentinel.conf

?Sentinel是redis的一個進程。只剩一個Sentinel之后無法進行master選舉了。

啟動:

3. INFO指令獲得最新節點拓撲圖

每個Sentinel每隔10秒就會向主從節點中發送INFO指令,通過該指令可以獲得整個redis的節 點拓撲圖。那么這時候,如果有新的節點加入或者有節點退出集群,那么Sentinel就可以很 快的感知到拓撲圖的變化。如下圖所示:

4.?哨兵監測集群狀態方法

每個Sentinel每隔2秒會向指定頻道上發布自己 對Master節點是否正常的判斷以及當前 Sentinel節點的信息,并且通過訂閱這個頻道, 可以獲得其他Sentinel節點的信息和對Master 節點是否存活的判斷。如圖所示:

每個Sentinel每隔1秒會向所有節點 (Sentinel節點、Master節點、Slave節點) 發送PING指令來進行心跳檢測。如圖所示:

5. 選舉流程

當一個Sentinel判斷主節點不可用的時候,會首先進行“主觀下線”,此時,這個Sentinel 通過sentinel is-masterdown-by-addr指令獲取其他哨兵節點對主節點的判斷,如果當 前哨兵節點對主節點主觀下線的票數超過了我們定義的quorum值,則主節點被判定為 “客觀下線”。

Leader Sentinel 節點會從原主節點的從節點中選出一個新的主節點,選舉流程如下:

  • ① 首先,過濾掉所有主觀下線的節點。
  • ② 然后,選擇slave-priority最高的 節點,如果有則返回,沒有就繼續下面的流程。
  • ③ 選擇出復制偏移量offset最大的節點,如果有則返回,沒有就繼續下面的流程。
  • ④ 選擇run_id最小的節點,其中,run_id表示服務器運行ID(run_id越小,啟動越早)。
  • ⑤ 在選擇完畢后,Leader Sentinel節點會通過SLAVEOF NO ONE命令讓選擇出來的從節 點成為主節點,然后通過SLAVEOF命令讓其他的節點成為該節點的從節點。

十一、Redis Cluster

Redis3.0開始引入了去中心化(沒有主從)分片集群Redis Cluster。

傳統的Redis集群是基于主從復制+哨兵的方式來實現的。但是集群中都只有一個主節點 提供寫服務。

Redis Cluster則采用多主多從的方式,支持開啟多個主節點,每個主節點上可以掛載多 個從節點。

Cluster會將數據進行分片,將數據分散到多個主節點上,而每個主節點都可以對外提供 讀寫服務。這種做法使得Redis突破了單機內存大小限制,擴展了集群的存儲容量。并且 Redis Cluster也具備高可用性,因為每個主節點上都至少有一個從節點,當主節點掛掉 時,Redis Cluster 的故障轉移機制會將某個從節點切換為主節點

Redis Cluster是一個去中心化的集群,每個節點都會與其他節點保持互連,使用gossip協 議來交換彼此的信息,以及探測新加入的節點信息。并且Redis Cluster無需任何代理, 客戶端會直接與集群中的節點直連。

1. 分片方式

(1)哈希取模

這種方式就類似我們使用HashMap時選址的方式,只要hash計算出來的值夠散列(rehash),那么 每個key都可以均勻的分散到N個節點上。 但是它存在的問題就是,如果要擴容或縮容,會導致key重新計算存儲位置,從而導致緩 存失效。

(2)一致性哈希(面)

一致性哈希算法將整個哈希值空間組織 成一個虛擬的圓環,其范圍為0 ~ 2^32-1, 如圖所示。 我們會先對Key計算它的hash值,從而確 定它在環上的位置。然后從該位置沿著環順指針地走,找到的第一個節點,便是這個 Key應該存放的服務器節點的位置。(容易造成雪崩的問題)

(3)虛擬節點 + 一致性哈希

該方案在一致性哈希的基礎上,引入了虛擬節點這一概念。原本是由實際節點來“搶占” 哈希環的位置,現在則是將虛擬節點分配給實際節點,然后由虛擬節點來搶占。如圖所示:

在引入了虛擬節點這一概念后,數據 到實際節點的映射關系就變成了數據 到虛擬節點,再由虛擬節點到實際節 點了。Redis集群便是采用了這種方 案。一個集群包含16384個哈希槽 (hash slot)也就是16384個虛擬節 點。譬如,我們的集群有三個節點, 那么:

  • Master1節點負責處理0~5460號 slot
  • Master2節點負責處理5461~ 10922號slot
  • Master3節點負責處理10923~ 16383號slot

2. 集群搭建

?由于Redis Cluster要求必須要至少6個節點,所以我們就以配置3主3從為例。修改redis 6390.conf ~ redis-6395.conf配置文件

分配主從(--cluster-replicas 1:表示創建1主1從)

  • ./redis-cli --cluster create 127.0.0.1:6390 127.0.0.1:6391 127.0.0.1:6392 127.0.0.1:6393 127.0.0.1:6394 127.0.0.1:6395 --cluster-replicas 1

配置完集群后,可能會報錯——16384個槽位沒有分配完。我們通過如下指令就可以進行檢查和修復

  • redis-cli --cluster check 172.17.0.2:6379
  • redis-cli --cluster fix 172.17.0.2:6379 #官方修復功能

十二、面試

1. 緩存穿透(查不到數據)

當用戶想要查詢一個數據,發現Redis中不存在,也就是所謂的緩存沒有命中,于是這個 數據請求就會打到數據庫中。結果數據庫中也不存在這條數據,那么結果就是什么都沒 查詢出來。那么當用戶很多時候的查詢,緩存中都沒有數據,請求直接打到數據庫中, 這樣就會給數據庫造成很大的壓力,緩存的作用也就幾近于失效了,那么這種情況就叫 做緩存穿透。

解決方案: ① 當數據庫中也查詢不到數據時,那么將返回的空對象也緩存起來,同時設置一個過期時間,之后再訪問這個數據將會從緩存中獲取, 從而起到保護數據庫的作用。 ② 添加布隆過濾器。如圖所示:

布隆過濾器:如果查不到,是真的查不到,如果查到了,不一定是真的查到了。所以通過布隆過濾器查不到,直接返回即可

緩存穿透:查不到數據,穿透的是redis。因為redis緩存中沒有數據,所以擊穿redis訪問數據庫。

2. 緩存擊穿(高并發查詢某數據,且緩存過期)

指一個非常熱點的key,在不停的高并發請求著,那么當這個key在緩存中失效的一瞬間, 持續對這個key的高并發就擊穿了緩存,直接請求到了數據庫,就像在一個屏障上早開了 一個洞。當熱點key過期失效的一瞬間,高并發突然融入,會對數據庫突然造成巨大的壓 力,嚴重的情況甚至會造成數據庫宕機。

解決方案:

① 方案一:設置熱點數據永不過期 從緩存層面來看,沒有設置過期時間,所以不會出現熱點key過期后所產生的緩存擊穿問題。

② 方案二:加互斥鎖?在數據庫的前面一層加分布式鎖,當緩存數據過期后,保證對每個熱點key同時只有一個線程去查詢后端 服務,并將熱點數據添加到緩存。

3. 緩存雪崩(緩存大批量失效或Redis宕機)

指在某一個時間段,緩存集中過期失效,或Redis宕機,導致針對這批數據的查詢都落到 了數據庫上,對于數據庫而言,就會產生周期性的壓力波峰。于是所有的請求都會達到 存儲層,存儲層的調用量會暴增,造成存儲層也會掛掉的情況。其實緩存集中過期,倒 不是最致命的,比較致命的是Redis發生節點宕機或斷網。因為緩存集中過期后,數據庫 壓力增大,但是隨著緩存的創建,壓力也會逐漸變小。針對Redis服務節點宕機,對數據 庫服務器造成的壓力是不可預知的,很有可能是持續壓力而最終造成數據庫宕機。

解決方案 :

① 方案一:配置Redis集群

通過配置Redis集群,提升高可用性,那么即使掛掉幾個Redis節點,集群內的其他Redis 節點依然可以繼續對外提供服務。

② 方案二:限流降級

緩存失效后,通過加鎖或隊列來控制讀取數據庫且寫入緩存的線程數量。常用的緩存降級是MQ。

③ 方案三:數據預熱分散過期時間

在正式部署之前,先把可能被高頻訪問的數據預先訪問一遍,這樣大部分熱點數據就加 載到緩存中了,并且通過設置不同的過期時間,讓緩存失效的時間盡量均勻,防止同一時刻 大批量緩存失效

4. 布隆過濾器

布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實際上是一個很長的二進制向量 和一系列隨機映射函數。布隆過濾器可以用于檢索一個元素是否在一個集合中。它的優 點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困 難。

布隆過濾器的特征是:它可以判斷某個數據一定不存在,但是無法判斷一定存在。(確實有點拗口,但當我們介紹完它的原理,就很容易明白了)

布隆過濾器:判斷不存在則一定不存在,判斷存在也不一定存在。

  • ?把數據庫中的數據以離線的方式存到redis緩存中。
  • ?Client發請求,首先布隆過濾器判斷,如果不存在,則返回miss ③
  • 如果布隆過濾器判斷存在,則請求redis,再將數據返回給client

刪除困難:不提供刪除能力

數據一致性不能完全被解決。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903356.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903356.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903356.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布式鏈路追蹤理論

基本概念 分布式調用鏈標準-openTracing Span-節點組成跟蹤樹結構 有一些特定的變量&#xff0c;SpanName SpanId traceId spanParentId Trace&#xff08;追蹤&#xff09;&#xff1a;代表一個完整的請求流程&#xff08;如用戶下單&#xff09;&#xff0c;由多個Span組成…

err: Error: Request failed with status code 400

好的&#xff0c;今天學習ai的時候從前端發送請求&#xff0c;實在是想不通為啥會啥是一個壞請求&#xff0c;后來從前端方法一個一個找參數&#xff0c;傳遞的值都有&#xff0c;然后想到我這邊需要傳遞的是一個對象&#xff0c;那么后端使用的RequestParam就接收不到json對象…

開發小程序后端用PHP好還是Java哪個好?

在開發后端時&#xff0c;是選擇PHP還是Java主要取決于你的項目需求、團隊技術棧、性能要求以及維護成本等因素。下面我將從幾個關鍵方面對兩者進行簡要對比&#xff0c;以幫助你做出更明智的選擇。 PHP 優點&#xff1a; 簡單易學&#xff1a;PHP語法簡單&#xff0c;上手快&a…

麒麟V10 aarch64 qt 安裝

在麒麟V10(aarch64架構)中安裝Qt,需根據具體需求選擇合適的方法。以下是綜合多個搜索結果的安裝方案及注意事項: 一、安裝方法 1. 在線安裝默認版本 適用于對Qt版本無特殊要求的情況。通過APT包管理器安裝系統默認提供的Qt版本(如Qt 5.12.12): sudo apt-get update s…

pdf.js移動端預覽PDF文件時,支持雙指縮放

在viewer.html中添加手勢縮放代碼 <script>// alert("Hello World");let agent navigator.userAgent.toLowerCase();// if (!agent.includes("iphone")) {let pinchZoomEnabled false;function enablePinchZoom(pdfViewer) {let startX 0, start…

算法筆記.kruskal算法求最小生成樹

題目&#xff1a;&#xff08;來源&#xff1a;AcWing&#xff09; 給定一個 n 個點 m 條邊的無向圖&#xff0c;圖中可能存在重邊和自環&#xff0c;邊權可能為負數。 求最小生成樹的樹邊權重之和&#xff0c;如果最小生成樹不存在則輸出 impossible。 給定一張邊帶權的無向…

C#開發的自定義Panel滾動分頁控件 - 開源研究系列文章

前些時候因為想擁有一個自己的軟件快捷打開軟件&#xff0c;于是參考Windows 11的開始菜單&#xff0c;進行了編寫這個應用軟件&#xff0c;里面有一個功能就是對顯示的Panel里的應用對象的分頁功能&#xff0c;于是就想寫一個對Panel的自定義滾動條控件。 下面開始介紹此控件的…

【基礎篇】prometheus命令行參數詳解

文章目錄 本篇內容講解命令行參數詳解 本篇內容講解 prometheus高頻修改命令行參數詳解 命令行參數詳解 在頁面的/頁面上能看到所有的命令行參數&#xff0c;如圖所示&#xff1a; 使用shell命令查看 # ./prometheus --help usage: prometheus [<flags>]The Promethe…

深入理解CSS3:Flex/Grid布局、動畫與媒體查詢實戰指南

引言 在現代Web開發中&#xff0c;CSS3已經成為構建響應式、美觀且高性能網站的核心技術。它不僅提供了更強大的布局系統&#xff08;Flexbox和Grid&#xff09;&#xff0c;還引入了令人驚艷的動畫效果和精準的媒體查詢能力。本文將深入探討這些關鍵技術&#xff0c;幫助您提…

從線性到非線性:簡單聊聊神經網絡的常見三大激活函數

大家好&#xff0c;我是沛哥兒&#xff0c;我們今天一起來學習下神經網絡的三個常用的激活函數。 引言&#xff1a;什么是激活函數 激活函數是神經網絡中非常重要的組成部分&#xff0c;它引入了非線性因素&#xff0c;使得神經網絡能夠學習和表示復雜的函數關系。 在神經網絡…

2025上海車展 | 移遠通信重磅發布AR腳踢毫米波雷達,重新定義“無接觸交互”尾門

4月25日&#xff0c;在2025上海國際汽車工業展覽會期間&#xff0c;全球領先的物聯網和車聯網整體解決方案供應商移遠通信宣布&#xff0c;其全新AR腳踢毫米波雷達RD7702AC正式發布。 該產品專為汽車尾門“無接觸交互”設計&#xff0c;基于先進的毫米波技術&#xff0c;融合AR…

深度學習:遷移學習

遷移學習 標題1.什么是遷移學習 遷移學習(Transfer Learning)是一種機器學習方法&#xff0c;就是把為任務 A 開發 的模型作為初始點&#xff0c;重新使用在為任務 B 開發模型的過程中。遷移學習是通過 從已學習的相關任務中轉移知識來改進學習的新任務&#xff0c;雖然大多數…

Rabbitmq下載和安裝(Windows系統,百度網盤)

一.下載安裝Erlang 1.百度云下載 鏈接&#xff1a;https://pan.baidu.com/s/1k_U25KKngEf1iXWD1ANOeg 提取碼&#xff1a;8ilc 2.安裝 傻瓜式安裝 直接下一步 選擇自己要安裝的路徑 3.配置環境變量 增加變量名為&#xff1a;ERLANG_HOME 變量值填寫自己的安裝路徑&#x…

(一)Linux的歷史與環境搭建

【知識預告】 Linux背景介紹Linux操作系統特性Linux的應用場景Linux的發行版本搭建Linux環境 1 Linux背景介紹 1.1 什么是Linux&#xff1f; Linux是一種自由、開源的操作系統。嚴格來說&#xff0c;它是基于類Unix設計思想&#xff0c;旨在為用戶提供穩定、安全、高效的計…

光流法:從傳統方法到深度學習方法

1 光流法簡介 光流&#xff08;Optical Flow&#xff09;是指圖像中像素灰度值隨時間的變化而產生的運動場。 簡單來說&#xff0c;它描述了圖像中每個像素點的運動速度和方向。 光流法是一種通過分析圖像序列中像素灰度值來計算光流的方法。對于圖像數據計算出來的光流是一個二…

解決ssh拉取服務器數據,要多次輸入密碼的問題

問題在于&#xff0c;每次循環調用 rsync 都是新開一個連接&#xff0c;所以每次都需要輸入一次密碼。為了只輸入一次密碼&#xff0c;有以下幾種方式可以解決&#xff1a; ? 推薦方案&#xff1a;設置 SSH 免密登錄 最穩最安全的方式是&#xff1a;配置 SSH 免密登錄&#x…

web技術與Nginx網站服務

目錄 一. web基礎 1. 域名概念 2. Hosts 文件 3. DNS 4. 域名注冊 5. 網頁與 HTML 二. 網頁概述 1. HTML 概述 2. HTML 基本標簽 3. 網站和主頁 三. 靜態網頁與動態網頁 1. 靜態網頁 2. 動態網頁 3. 動態網頁語言 四. HTTP 協議 1. HTTP 協議概述 2. HTTP …

信創系統資產清單采集腳本:主機名+IP+MAC 一鍵生成 CSV

原文鏈接&#xff1a;信創系統資產清單采集腳本&#xff1a;主機名IPMAC 一鍵生成 CSV Hello&#xff0c;大家好啊&#xff01;今天給大家帶來一篇在信創終端操作系統上自動批量采集主機名、IP 和 MAC 并導出為 CSV 表格的實戰文章&#xff01;本方案使用 sshpass 和 Bash 腳本…

【dify+docker安裝教程】

目錄 一、dify安裝包下載 二、運行環境配置 1、下載docker 2、安裝 2.1 新建文件夾 2.2 安裝 2.3 命令安裝 3.下載完成后需要重啟電腦&#xff0c;注意保存文檔&#xff01;&#xff01;注意保存&#xff01;&#xff01;注意&#xff01;&#xff01;&#xff08;血的教…

HTML 地理定位(Geolocation)教程

HTML 地理定位(Geolocation)教程 簡介 HTML5 的 Geolocation API 允許網頁應用獲取用戶的地理位置信息。這個功能可用于提供基于位置的服務&#xff0c;如導航、本地搜索、天氣預報等。本教程將詳細介紹如何在網頁中實現地理定位功能。 工作原理 瀏覽器可以通過多種方式確定…