① redis最大支持多少行
redis最大支持2行。根據相關信息資料的枝搏頌帶查詢,猛櫻祥redis支持最大的2–32鍵位key,最大支持2行。
② Redis源碼分析之事件循環
本篇我們來講Redis的事件循環,Redis的事件循環會根據系統選擇evport、epoll、kqueue或select來進行IO多路復用,我們這里只分析epoll。
首先我們來看一下Redis的IO多路復用對事件循環(aeEventLoop)提供的介面。
以epoll(ae_epoll.c)為例,先來看一下Redis的IO多路復用的使用過程:
首先需要創建,即調用aeApiCreate:
aeApiState結構體有兩個成員,events和epfd。events用於存儲就緒的epoll事件,epfd存儲epoll的文件描述符。aeApiCreate的主要邏輯是為aeApiState分配存儲空間,調用epoll_create系統調用創建epoll並獲取描述符,最後將aeApiState賦值給aeEventLoop的apidata。
然後在有新的文件描述符(比如接受了一個新連接)需要加入到epoll中時,調用aeApiAddEvent:
參數fd是需要監視的文件描述符,mask標明是需要監視可讀還是可寫事件。aeApiAddEvent的主要邏輯是調用系統調用epoll_ctl注冊或修改添加事件的監聽類型到epoll。
然後在有文件描述符失效或者需要修改監聽類型時,調用aeApiDelEvent:
參數fd是需要刪除的文件描述符,mask標明是需要刪除可讀還是可寫事件。aeApiDelEvent主要邏輯是調用系統調用epoll_ctl刪除或修改刪除事件的監聽類型到epoll。
然後需要檢查是否有就緒的事件,調用aeApiPoll:
tvp是等待時間,一般而言,這個值是0(不是NULL)代表沒有就緒事件立即返回。主要邏輯是調用系統調用epoll_wait拿到就緒事件保存到events中,然後將events中的就緒事件復制到事件循環aeEventLoop的fired中,最後返回就緒事件的數量。
我們來分析一下Redis的事件循環(ae.c)。
先看主要介面:
創建過程:
初始化aeEventLoop和aeApiState並返回aeEventLoop。
注冊文件事件:
存儲到events中並調用aeApiAddEvent注冊到epoll中。
注冊定時事件:
創建aeTimeEvent並將其插入到定時事件鏈表的頭部。
主循環:
不停的調用aeProcessEvents拉取並處理事件。
接下來看aeProcessEvents的邏輯:
再看一下定時事件的觸發,也就是processTimeEvents的邏輯:
遍歷注冊的定時事件,找出到期的事件並調用處理函數,如果處理函數返回了下次執行的時間,則更新下次觸發的時間,否則刪除該事件。
③ Spring整合Lettuce Redis
以關鍵詞【 spring lettuce 】搜索,大部分博文都是基於配置文件配置的,不太符合某些定製化需求。
所以本文提供兩種配置方式。一種基於配置文件,一種基於蘆滑猛Java Config。
單機redis配置
哨兵模式redis配置
參考源碼: :119 行
lettuce 是基於 netty 的,所以有下面的坑陪橋點
https://github.com/lettuce-io/lettuce-core/wiki/Native-Transports
如果項目中依賴的netty低於 4.0.26.Final ,在linux環境下會導致無法運行。
建議項目中設置netty依賴版本大於等於 4.1.11.Final 。
本人項目依賴了 com.dianping.cat:cat ,從而間接依賴了 compile ('io.netty:netty-all:4.0.24.Final') ,
導致在linux環境運行一直報錯,而macOS開讓春發環境正常,因為macOS和windows環境都是不支持 epoll 的。
④ redis maxclients可以改到多大
可以設置無限大:redis.conf中maxclients 設置為0表示不作限制.
但是redis maxclients 會受到到其他影響,影響最大連接數.
1、其實你是滑缺絕受到了redis的file descriptor數目限制,這個需要更改redis的源碼,在ae.h的36行(2.2.4版本):
#defineAE_SETSIZE(1024*10)/*Maxnumberoffdsupported*/
2、另外需要注意的是,如信姿扮伍果你需要支持更高的連接數,還需要更改系統的相關配置,比如ulimit數目:
ulimit-nxxx(你需要的數目)
以及網路的並發連接數等限制:
net.ipv4.netfilter.ip_conntrack_max
net.nf_conntrack_max
net.netfilter.nf_conntrack_max
⑤ redis之管道應用場景及源碼分析
我們都知道,redis的通信是建立在tcp基礎上的,也就是說每一次命令(get、set)都需要經過tcp三次握手,而且redis一般都是部署在區域網內,網路開銷非常小,針對頻次較低的操作,網路開銷都是可以忽略的。
在redis通信基礎中 我已經講到了。每一次操作redis的時候我們都需要和服務端建立連接,針對量小的情況下網路延遲都是可以忽略的,但是針對大批量的業務,就會產生雪崩效應。假如一次操作耗時2ms,理論上100萬次操作就會有2ms*100萬ms延遲,中間加上伺服器處理開銷,耗時可能更多.對應客戶端來講,這種長時間的耗時是不能接受的。所以為了解決這個問題,redis的管道pipeline就派上用場了。 恰好公司的對賬業務使用了redis的sdiff功能,數據量比較大,剛開始沒有pipeline導致延遲非常嚴重。後來wireshark抓包分析原因確實發現不停的建立tcp連接(發送數據,接收數據)。使用pipeline後性能大幅度提升。
可想而知,使用pipeline的性能要比不使用管道快很多倍。
本文就先到這里了。。。
⑥ 【Redis】基礎數據結構-ziplist壓縮列表
壓縮列表是列表和哈希表的底層實現之一:
Redis壓縮列表是由連續的內存塊組成的列表,主要包含以下內容:
列表在初始化的時候會計算需要分配的內存空間大小,然後進行內存分配,之後將內存空間的最後一個位元組標記為列表結尾,內存空間的大小計算方式如下:
所以在創建之後,內存布局如下,此時壓縮列表中還沒有節點:
之後如果如果需要添加節點,會進行移動,為新節點的插入騰出空間,所以還是斗彎余佔用的連續的空間:
壓縮列表的節點可以存儲字元串或者整數類型的值,為了節省內存,它採用了變長的編碼方式,壓縮列表的節點的結構定義如下:
prevrawlen :存儲前一個節點的長度(佔用的位元組數),這樣如果從後向前遍歷,只需要當前節點的起始地址減去長度的偏移量prevrawlen就可以定位到上一個節點的位置,prevrawlen的長度可以是1位元組或者5位元組:
encoding :記錄了節點的數據類型和內容的長度,因為壓縮列表可以存儲字元串或者整型,所以有以下兩種情況:
存儲內容為整數時,encoding佔用1個位元組,最高位是11開頭,後六位代表整數值的長度,其中當編碼為1111xxxx時情況比較特殊,
後四位的值在0001和1101之間, 此時直接代表數據的內容,是0到12之間的一個數字 ,並不是數據長度,因為它代表了數據內容,所以也不需要額外的空間存儲數據內容。
zipStoreEntryEncoding
因為壓縮列表中每個節點記錄了前一個節點的長度:
假設有一種情況,一個壓縮列表中,存儲了多個長度是253位元組的節點,因為節點的長度都在254位元組以內,所以每個節點的prevrawlen只需要1個位元組去存儲長度的值:
此時在列表的頭部需要新增加一個節點,並且節點的長度大於254,這個時候原先的頭結點entry1 prevrawlen使用1位元組已經不能滿足當前的情況了,必須要使用5位元組存儲,因此entry1的prevrawlen變成了5位元組,entry1的長度也會跟著增加4個位元組,已經超過了254位元組,因為大於254就需要使用5個位元組存儲,所以entry2的prevrawlen也鬧李需要改變為5位元組,後面的以此類推,引發了連鎖更新,這種情況稱之為連鎖更新:
總結空滾
(1)Redis壓縮列表使用了一塊連續的內存,來節約內存空間。
(2)壓縮列表的節點可以存儲字元串或者整數類型的值,它採用了變長的編碼方式,根據數據類型的不同以及數據長度的不同,選擇不同的編碼方式,每種編碼佔用的位元組大小不同,以此來節約內存。
(3)壓縮列表的每個節點中存儲了前一個節點的位元組長度,如果知道某個節點的地址,可以使用地址減去位元組長度定位到上一個節點,不過新增節點的時候,由於前一個節點的長度大於254使用5個位元組,小於254使用1個位元組存儲,在一些極端的情況下由於長度的變化會引起連鎖更新。
參考
黃健宏《Redis設計與實現》
極客時間 - Redis源碼剖析與實戰(蔣德鈞)
【張鐵蕾】Redis內部數據結構詳解(4)——ziplist
【_HelloBug】Redis-壓縮表-__ziplistInsert詳解
圖解Redis之數據結構篇——壓縮列表
Redis版本:redis-6.2.5
⑦ MySQL與Redis資料庫連接池介紹(圖示+源碼+代碼演示)
資料庫連接池(Connection pooling)是程序啟動時建立足夠的資料庫連接,並將這些連接組成一個連接池,由程序動態地對池中的連接進行申請,使用,釋放。
簡單的說:創建資料庫連接是一個很耗時的操作,也容易對資料庫造成安全隱患。所以,在程序初始化的時候,集中創建多個資料庫連接,並把他們集中管理,供程序使用,可以保證較快的資料庫讀寫速度,還更加安全可靠。
不使用資料庫連接池
如果不使用資料庫連接池,對於每一次SQL操作,都要走一遍下面完整的流程:
1.TCP建立連接的三次握手(客戶端與 MySQL伺服器的連接基於TCP協議)
2.MySQL認證的三次我收
3.真正的SQL執行
4.MySQL的關閉
5.TCP的四次握手關閉
可以看出來,為了執行一條SQL,需要進行大量的初始化與關閉操作
使用資料庫連接池
如果使用資料庫連接池,那麼會 事先申請(初始化)好 相關的資料庫連接,然後在之後的SQL操作中會復用這些資料庫連接,操作結束之後資料庫也不會斷開連接,而是將資料庫對象放回到資料庫連接池中
資源重用:由於資料庫連接得到重用,避免了頻繁的創建、釋放連接引起的性能開銷,在減少系統消耗的基礎上,另一方面也增進了系統運行環境的平穩性(減少內存碎片以及資料庫臨時進程/線程的數量)。
更快的系統響應速度:資料庫連接池在初始化過程中,往往已經創建了若干資料庫連接置於池中備用。 此時連接的初始化工作均已完成。對於業務請求處理而言,直接利用現有可用連接,避免了從資料庫連接初始化和釋放過程的開銷,從而縮減了系統整體響應時間。
統一的連接管理,避免資料庫連接泄露:在較為完備的資料庫連接池實現中,可根據預先的連接佔用超時設定,強制收回被佔用連接。從而避免了常規資料庫連接操作中可能出現的資源泄露。
如果說你的伺服器CPU是4核i7的,連接池大小應該為((4*2)+1)=9
相關視頻推薦
90分鍾搞懂資料庫連接池技術|linux後台開發
《tcp/ip詳解卷一》: 150行代碼拉開協議棧實現的篇章
學習地址:C/C++Linux伺服器開發/後台架構師【零聲教育】-學習視頻教程-騰訊課堂
需要C/C++ Linux伺服器架構師學習資料加qun 812855908 獲取(資料包括 C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg 等),免費分享
源碼下載
下載方式:https://github.com/dongyusheng/csdn-code/tree/master/db_pool(Github中下載)
db_pool目錄下有兩個目錄,mysql_pool目錄為MySQL連接池代碼,redis_pool為redis連接池代碼
下面介紹mysql_pool
CDBConn解析
概念: 代表一個數據連接對象實例
相關成員:
m_pDBPool:該資料庫連接對象所屬的資料庫連接池
構造函數: 綁定自己所屬於哪個資料庫連接池
Init()函數: 創建資料庫連接句柄
CDBPool解析
概念:代表一個資料庫連接池
相關成員:
Init()函數:常見指定數量的資料庫實例句柄,然後添加到m_free_list中,供後面使用
GetDBConn()函數: 用於從空閑隊列中返回可以使用的資料庫連接句柄
RelDBConn()函數: 程序使用完該資料庫句柄之後,將句柄放回到空閑隊列中
測試之前,將代碼中的資料庫地址、埠、賬號密碼等改為自己的(代碼中有好幾處)
進入MySQL, 創建mysql_pool_test資料庫
進入到mysql_pool目錄下, 創建一個build目錄並進入 :
然後輸入如下的命令進行編譯
之後就會在目錄下生成如下的可執行文件
輸入如下兩條命令進行測試: 可以看到不使用資料庫連接池,整個操作耗時4秒左右;使用連接池之後,整個操作耗時2秒左右,提升了一倍
源碼下載
下面介紹redis_pool
測試
進入到redis_pool目錄下, 創建一個build目錄並進入 :
然後輸入如下的命令進行編譯
之後就會在目錄下生成如下的可執行文件
輸入如下的命令進行測試: 可以看到不使用資料庫連接池,整個操作耗時182ms;使用連接池之後,整個操作耗時21ms,提升了很多
進入redis,可以看到我們新建的key:
⑧ redis源碼解讀:單線程的redis是如何實現高速緩存的
redis可能是最近幾年最火的緩存資料庫方案了,在各個高並發領域都有應用。
這篇文章,我們將從源代碼的角度來分析一下,為何如此一個高性能,高應用的緩存,會是單線程的方案,當然一個方案的高性能,高並發是多方面的綜合因素,其它的因素我們將在後續解讀。後續分析主要以LINUX操作系統為基礎,這也是redis應用最廣的平台。
單線程最大的受限是什麼?就是CPU,現在伺服器一般已經是多CPU,而單線程只能使用到其中的一個核。
redis作為一個網路內存緩存資料庫,在實現高性能時,主要有4個點。
1.網路高並發,高流量的數據處理。
一個非同步,高效,且對CPU要求不高的網路模型,這個模型主要是由OS來提供的,目前在LINUX最主流使用的是EPOLL,這個網上介紹很多,主要是基於事件驅動的一個非同步模型。
2.程序內部的合理構架,調用邏輯,內存管理。
redis在採用純C實現時,整體調用邏輯很短,但在內存方面,適當的合並了一些對象和對齊,比如sds等,在底層使用了內存池,在不同情況下使用的不太一樣。
但整體處理上沒有NGINX的內池設計巧妙,當然二者不太一樣,NGINX是基於請求釋放的邏輯來設計的,因此針對請求,可以一次申請大塊,分量使用,再最後統一釋放。
3.數據復制的代價,不管是讀取數據或是寫入數據,一般都是需要有數據復制的過程。
數據復制其實就是一次內存,真正的代價是在於存在大VALUE,當value值長度超過16KB時,性能會開始下降。因為單線程的原因,如果存在一個超大VALUE,比如20MB,則會因為這個請求卡住整個線程,導致後續的請求進不來,雖然後面的請求是能快速處理的小請求。
4.redis中數據結構中演算法的代價,有些結構在大數據量時,代價是很高的。
很多時間,大家忽略了演算法的運算代碼,因為像memcached等這類是完全的KV緩存,不存在什麼演算法,除了一個KEY的查找定位HASH演算法。
而redis不一樣,提供了不少高階的數據對象,這些對象具有上層的一些演算法能力,而這些能力是需要比如GEO模塊。
⑨ RedisTokenStore 源碼解析 以及內存泄漏問題
前端時間,正好在做公司許可權相關的架構問題,然後選擇了Spring OAuth2來作為公司許可權框架,先記錄下目前遇到原生問題吧,後續有時間再來整理這個框架的整體脈絡;
RedisTokenStore 主要是來做token持久化到redis的工具類
我們先來看下緩存到redis中有哪些key
ACCESS :用來存放 AccessToken 對象(登錄的token值,還有登錄過期時間,token刷新值)
AUTH_TO_ACCESS :緩存的也是AccessToken 對象,是可以根據用戶名和client_id來查找當前用戶的AccessToken
AUTH :用來存放用戶信息(OAuth2Authentication),有許可權信息,用戶信息等
ACCESS_TO_REFRESH :可以根據該值,通過AccessToken找到refreshToken
REFRESH :用來存放refreshToken
REFRESH_TO_ACCESS :根據refreshToken來找到AccessToken
CLIENT_ID_TO_ACCESS :存放當前client_id有多少AccessToken
UNAME_TO_ACCESS :當沒有做單點登錄的話,可以使用該key,根據用戶名查找當前用戶有多少AccessToken可以使用
根據client_id和用戶名,來獲取當前用戶的accessToken,如果緩存中的OAuth2Authentication已經過期,或者雷勇有變化,則會重新更新緩存;
緩存OAuth2AccessToken 和 OAuth2Authentication 對象,該方法主要在登錄時調用,會把上面說的所有key值都緩存起來;
再看下,移除accessToken時
目前主要是看這幾個方法,其他方法也挺簡單的,主要是一些redis緩存操作的;
client_id_to_access 和 uname_to_access 使用的是set集合,眾所周知redis的set集合的過期時間是按照整個key來設置的;
每次登陸時,會先根據client_id和用戶名去緩存中查找是否有可使用的AccessToken,如果有則返回緩存中的值,沒有則生成新的;
所以每次登陸都會往這兩個集合中放入新的accessToken,如果當某個用戶在AccessToken有效期內沒有操作,則當前用戶的登陸信息會被動下線,access 和 auth 中緩存的值都會過期,再次登陸時就查找不到了;
但是如果當前平台用戶量不小,那麼一直都會有人操作,client_id_to_access 這個集合就會一直續期,那麼過期了的accessToken就會一直存在該集合中,且不會減少,造成內存泄漏;
1.自己實現TokenStore,修改client_id_to_access 數據結構
2.寫個定時任務,定期掃描client_id_to_access ,清除掉已經過期的token
3.如果不需要知道當前有哪些用戶登錄,或者該功能已經用了其他方式實現的,可以直接去掉這兩個redis key
⑩ redis hashtag一文搞懂,源碼解析
僅僅花括弧中間的部分參與hash,hash結果為slot編號。
強制多個key寫入同一個slot,也就是同一個節點(假設沒有正在進行分片)。
在redis cluster中有16384個slot。
slot編號:0~16383。
cluster中存儲每個節點負責哪些slot。
cluster中存儲每個slot對應哪一個節神余點。
源碼有2處。
第一處:
https://github.com/redis/redis/blob/6.2.6/src/redis-cli.c
line:3282
方法:clusterManagetKeyHashSlot
第二處:
https://github.com/redis/redis/blob/6.2.6/src/cluster.c
line:749
方法:keyHashSlot
僅{...}里的部分參與hash。
如果有多個花括弧,從左向右,取第一個花括弧中的內容進行hash。
若第一個花括弧中內容為空如:a{}c{d},則整個key參與hash。
相同的hashtag被分配到相同的節點,相同的槽。
hash演算法採用crc16。crc16演算法為游隱滾redis自己封裝攜態的,源碼位置: https://github.com/redis/redis/blob/6.2.6/src/crc16.c 。