redis簡(jiǎn)介
1. 支持5種數(shù)據(jù)結(jié)構(gòu)
支持strings, hashes, lists, sets, sorted sets
string是很好的存儲(chǔ)方式,用來(lái)做計(jì)數(shù)存儲(chǔ)。sets用于建立索引庫(kù)非常棒;
2. K-V 存儲(chǔ) vs K-V 緩存
新浪微博目前使用的98%都是持久化的應(yīng)用,2%的是緩存,用到了600+服務(wù)器
Redis中持久化的應(yīng)用和非持久化的方式不會(huì)差別很大:
非持久化的為8-9萬(wàn)tps,那么持久化在7-8萬(wàn)tps左右;
當(dāng)使用持久化時(shí),需要考慮到持久化和寫(xiě)性能的配比,也就是要考慮redis使用的內(nèi)存大小和硬盤(pán)寫(xiě)的速率的比例計(jì)算;
3. 社區(qū)活躍
Redis目前有3萬(wàn)多行代碼, 代碼寫(xiě)的精簡(jiǎn),有很多巧妙的實(shí)現(xiàn),作者有技術(shù)潔癖
Redis的社區(qū)活躍度很高,這是衡量開(kāi)源軟件質(zhì)量的重要指標(biāo),開(kāi)源軟件的初期一般都沒(méi)有商業(yè)技術(shù)服務(wù)支持,如果沒(méi)有活躍社區(qū)做支撐,一旦發(fā)生問(wèn)題都無(wú)處求救;
Redis基本原理
redis持久化(aof) Append online file:
寫(xiě)log(aof), 到一定程度再和內(nèi)存合并. 追加再追加, 順序?qū)懘疟P(pán), 對(duì)性能影響非常小
1. 單實(shí)例單進(jìn)程
Redis使用的是單進(jìn)程,所以在配置時(shí),一個(gè)實(shí)例只會(huì)用到一個(gè)CPU;
在配置時(shí),如果需要讓CPU使用率最大化,可以配置Redis實(shí)例數(shù)對(duì)應(yīng)CPU數(shù), Redis實(shí)例數(shù)對(duì)應(yīng)端口數(shù)(8核Cpu, 8個(gè)實(shí)例, 8個(gè)端口), 以提高并發(fā):
單機(jī)測(cè)試時(shí), 單條數(shù)據(jù)在200字節(jié), 測(cè)試的結(jié)果為8~9萬(wàn)tps;
2. Replication
過(guò)程: 數(shù)據(jù)寫(xiě)到master-->master存儲(chǔ)到slave的rdb中-->slave加載rdb到內(nèi)存。
存儲(chǔ)點(diǎn)(save point): 當(dāng)網(wǎng)絡(luò)中斷了, 連上之后, 繼續(xù)傳.
Master-slave下第一次同步是全傳,后面是增量同步;、
3. 數(shù)據(jù)一致性
長(zhǎng)期運(yùn)行后多個(gè)結(jié)點(diǎn)之間存在不一致的可能性;
開(kāi)發(fā)兩個(gè)工具程序:
1.對(duì)于數(shù)據(jù)量大的數(shù)據(jù),會(huì)周期性的全量檢查;
2.實(shí)時(shí)的檢查增量數(shù)據(jù),是否具有一致性;
對(duì)于主庫(kù)未及時(shí)同步從庫(kù)導(dǎo)致的不一致,稱(chēng)之為延時(shí)問(wèn)題;
對(duì)于一致性要求不是那么嚴(yán)格的場(chǎng)景,我們只需要要保證最終一致性即可;
對(duì)于延時(shí)問(wèn)題,需要根據(jù)業(yè)務(wù)場(chǎng)景特點(diǎn)分析,從應(yīng)用層面增加策略來(lái)解決這個(gè)問(wèn)題;
例如:
1.新注冊(cè)的用戶(hù),必須先查詢(xún)主庫(kù);
2.注冊(cè)成功之后,需要等待3s之后跳轉(zhuǎn),后臺(tái)此時(shí)就是在做數(shù)據(jù)同步。
新浪Redis使用歷程
2009年, 使用memcache(用于非持久化內(nèi)容), memcacheDB(用于持久化+計(jì)數(shù)),
memcacheDB是新浪在memcache的基礎(chǔ)上,使用BerkeleyDB作為數(shù)據(jù)持久化的存儲(chǔ)實(shí)現(xiàn);
1. 面臨的問(wèn)題
- 數(shù)據(jù)結(jié)構(gòu)(Data Structure)需求越來(lái)越多, 但memcache中沒(méi)有, 影響開(kāi)發(fā)效率
- 性能需求, 隨著讀操作的量的上升需要解決,經(jīng)歷的過(guò)程有:
- 數(shù)據(jù)庫(kù)讀寫(xiě)分離(M/S)-->數(shù)據(jù)庫(kù)使用多個(gè)Slave-->增加Cache (memcache)-->轉(zhuǎn)到Redis
- 解決寫(xiě)的問(wèn)題:
- 水平拆分,對(duì)表的拆分,將有的用戶(hù)放在這個(gè)表,有的用戶(hù)放在另外一個(gè)表;
- 可靠性需求
- Cache的"雪崩"問(wèn)題讓人糾結(jié)
- Cache面臨著快速恢復(fù)的挑戰(zhàn)
- 開(kāi)發(fā)成本需求
- Cache和DB的一致性維護(hù)成本越來(lái)越高(先清理DB, 再清理緩存, 不行啊, 太慢了!)
- 開(kāi)發(fā)需要跟上不斷涌入的產(chǎn)品需求
- 硬件成本最貴的就是數(shù)據(jù)庫(kù)層面的機(jī)器,基本上比前端的機(jī)器要貴幾倍,主要是IO密集型,很耗硬件;
- 維護(hù)性復(fù)雜
- 一致性維護(hù)成本越來(lái)越高;
- BerkeleyDB使用B樹(shù),會(huì)一直寫(xiě)新的,內(nèi)部不會(huì)有文件重新組織;這樣會(huì)導(dǎo)致文件越來(lái)越大;大的時(shí)候需要進(jìn)行文件歸檔,歸檔的操作要定期做;
- 這樣,就需要有一定的down time;
基于以上考慮, 選擇了Redis
2. 尋找開(kāi)源軟件的方式及評(píng)判標(biāo)準(zhǔn)
- 對(duì)于開(kāi)源軟件,首先看其能做什么,但更多的需要關(guān)注它不能做什么,它會(huì)有什么問(wèn)題?
- 上升到一定規(guī)模后,可能會(huì)出現(xiàn)什么問(wèn)題,是否能接受?
- google code上, 國(guó)外論壇找材料(國(guó)內(nèi)比國(guó)外技術(shù)水平滯后5年)
- 觀察作者個(gè)人的代碼水平
Redis應(yīng)用場(chǎng)景
1. 業(yè)務(wù)使用方式
- hash sets: 關(guān)注列表, 粉絲列表, 雙向關(guān)注列表(key-value(field), 排序)
- string(counter): 微博數(shù), 粉絲數(shù), ...(避免了select count(*) from ...)
- sort sets(自動(dòng)排序): TopN, 熱門(mén)微博等, 自動(dòng)排序
- lists(queue): push/sub提醒,...
上述四種, 從精細(xì)化控制方面,hash sets和string(counter)推薦使用, sort sets和lists(queue)不推薦使用
還可通過(guò)二次開(kāi)發(fā),進(jìn)行精簡(jiǎn)。比如: 存儲(chǔ)字符改為存儲(chǔ)整形, 16億數(shù)據(jù), 只需要16G內(nèi)存
存儲(chǔ)類(lèi)型保存在3種以?xún)?nèi),建議不要超過(guò)3種;
將memcache +myaql 替換為Redis:
Redis作為存儲(chǔ)并提供查詢(xún),后臺(tái)不再使用MySQL,解決數(shù)據(jù)多份之間的一致性問(wèn)題;
2. 對(duì)大數(shù)據(jù)表的存儲(chǔ)
(eg:140字微博的存儲(chǔ))
一個(gè)庫(kù)就存唯一性id和140個(gè)字;
另一個(gè)庫(kù)存id和用戶(hù)名,發(fā)布日期、點(diǎn)擊數(shù)等信息,用來(lái)計(jì)算、排序等,等計(jì)算出最后需要展示的數(shù)據(jù)時(shí)再到第一個(gè)庫(kù)中提取微博內(nèi)容;
改進(jìn)的3個(gè)步驟:
1)發(fā)現(xiàn)現(xiàn)有系統(tǒng)存在問(wèn)題;
2)發(fā)現(xiàn)了新東西, 怎么看怎么好, 全面轉(zhuǎn)向新東西;
3)理性回歸, 判斷哪些適合新東西, 哪些不適合, 不合適的回遷到老系統(tǒng)
3. 一些技巧
- 很多應(yīng)用, 可以承受數(shù)據(jù)庫(kù)連接失敗, 但不能承受處理慢
- 一份數(shù)據(jù), 多份索引(針對(duì)不同的查詢(xún)場(chǎng)景)
- 解決IO瓶頸的唯一途徑: 用內(nèi)存
- 在數(shù)據(jù)量變化不大的情況下,優(yōu)先選用Redis
遇到的問(wèn)題及解決辦法
(注意: 都是量特別大時(shí)候會(huì)出現(xiàn)的, 量小了怎么都好說(shuō))
1.Problem: Replication中斷后, 重發(fā)-->網(wǎng)絡(luò)突發(fā)流量
Solution: 重寫(xiě)Replication代碼, rdb+aof(滾動(dòng))
2.Problem: 容量問(wèn)題
Solution: 容量規(guī)劃和M/S的sharding功能(share nothing, 抽象出來(lái)的數(shù)據(jù)對(duì)象之間的關(guān)聯(lián)數(shù)據(jù)很小)
增加一些配置, 分流, 比如: 1,2,3,4, 機(jī)器1處理%2=1的, 機(jī)器2處理%2=0的.
低于內(nèi)存的1/2使用量, 否則就擴(kuò)容(建議Redis實(shí)例使用的數(shù)據(jù),最大不要超過(guò)內(nèi)存的80%)
我們線(xiàn)上96G/128G內(nèi)存服務(wù)器不建議單實(shí)例容量大于20/30G。
微博應(yīng)用中單表數(shù)據(jù)最高的有2T的數(shù)據(jù),不過(guò)應(yīng)用起來(lái)已經(jīng)有些力不從心;
每個(gè)的端口不要超過(guò)20G;測(cè)試磁盤(pán)做save所需要的時(shí)間,需要多長(zhǎng)時(shí)間能夠全部寫(xiě)入;內(nèi)存越大,寫(xiě)的時(shí)間也就越長(zhǎng);
單實(shí)例內(nèi)存容量較大后,直接帶來(lái)的問(wèn)題就是故障恢復(fù)或者Rebuild從庫(kù)的時(shí)候時(shí)間較長(zhǎng),對(duì)于普通硬盤(pán)的加載速度而言,我們的經(jīng)驗(yàn)一般是redis加載1G需要1分鐘;(加載的速度依賴(lài)于數(shù)據(jù)量的大小和數(shù)據(jù)的復(fù)雜度)
Redis rewrite aof和save rdb時(shí),將會(huì)帶來(lái)非常大且長(zhǎng)的系統(tǒng)壓力,并占用額外內(nèi)存,很可能導(dǎo)致系統(tǒng)內(nèi)存不足等嚴(yán)重影響性能的線(xiàn)上故障。
reblance: 現(xiàn)有數(shù)據(jù)按照上述配置重新分發(fā)。
后面使用中間層,路由HA;
注:目前官方也正在做這個(gè)事,Redis Cluster,解決HA問(wèn)題;
3. Problem: bgsave or bgwriteaof的冰晶問(wèn)題
Solution: 磁盤(pán)性能規(guī)劃和限制寫(xiě)入的速度, 比如: 規(guī)定磁盤(pán)以200M/s的速度寫(xiě)入, 細(xì)水長(zhǎng)流, 即使到來(lái)大量數(shù)據(jù). 但是要注意寫(xiě)入速度要滿(mǎn)足兩個(gè)客觀限制:
符合磁盤(pán)速度
符合時(shí)間限制(保證在高峰到來(lái)之前, 就得寫(xiě)完)
4.Problem: 運(yùn)維問(wèn)題
1)Inner Crontab: 把Crontab遷移到Redis內(nèi)部, 減少遷移時(shí)候的壓力
本機(jī)多端口避免同時(shí)做 - 能做到
同一業(yè)務(wù)多端口(分布在多機(jī)上), 避免同時(shí)做 - 做不到
2)動(dòng)態(tài)升級(jí): 先加載.so文件, 再管理配置, 切換到新代碼上(Config set命令)
把對(duì)redis改進(jìn)的東西都打包成lib.so文件,這樣能夠支持動(dòng)態(tài)升級(jí)
自己改的時(shí)候要考慮社區(qū)的升級(jí)。當(dāng)社區(qū)有新的版本,有很好用的新功能時(shí),要能很容易的與我們改進(jìn)后的版本很好的merge;
升級(jí)的前提條件: 模塊化, 以模塊為單位升級(jí)
加載時(shí)間取決于兩個(gè)方面: 數(shù)據(jù)大小, 數(shù)據(jù)結(jié)構(gòu)復(fù)雜度. 一般, 40G數(shù)據(jù)耗時(shí)40分鐘
分布式系統(tǒng)的兩個(gè)核心問(wèn)題: A.路由問(wèn)題 B.HA問(wèn)題
3)危險(xiǎn)命令的處理: 比如: fresh all刪除全部數(shù)據(jù), 得進(jìn)行控制
運(yùn)維不能只講數(shù)據(jù)備份,還得考慮數(shù)據(jù)恢復(fù)所需要的時(shí)間;
增加權(quán)限認(rèn)證(管理員才有權(quán)限)eg:flashall 權(quán)限認(rèn)證,得有密碼才能做;
當(dāng)然,高速數(shù)據(jù)交互一般都不會(huì)在每次都進(jìn)行權(quán)限認(rèn)證,通用的處理策略是第一次認(rèn)證,后期都不用再認(rèn)證;
控制hash策略(沒(méi)有key, 就找不到value; 不知道hash策略, 就無(wú)法得到key)
4)Config Dump:
內(nèi)存中的配置項(xiàng)動(dòng)態(tài)修改過(guò), 按照一定策略寫(xiě)入到磁盤(pán)中(Redis已支持)
5)bgsave帶來(lái)aof寫(xiě)入很慢:
fdatasync在做bgsave時(shí), 不做sync aof(會(huì)有數(shù)據(jù)出入)
6)成本問(wèn)題: (22T內(nèi)存, 有10T用來(lái)計(jì)數(shù))
Redisscounter(16億數(shù)據(jù)占用16G內(nèi)存) - 全部變?yōu)檎痛鎯?chǔ), 其余(字符串等)全不要
Redis+SSD(counterService計(jì)數(shù)服務(wù))
順序自增, table按照順序?qū)? 寫(xiě)滿(mǎn)10個(gè)table就自動(dòng)落地(到SSD)
存儲(chǔ)分級(jí): 內(nèi)存分配問(wèn)題, 10K和100K寫(xiě)到一塊, 會(huì)有碎片. Sina已經(jīng)優(yōu)化到浪費(fèi)只占5%以?xún)?nèi)(已經(jīng)很好了!)
5.Problem: 分布式問(wèn)題
1.Config Server: 命名空間, 特別大的告訴訪(fǎng)問(wèn), 都不適合用代理, 因?yàn)榇斫档退俣? 但是, Sina用了(單機(jī)多端口, Redis Cluster, sentinel)
Config Server放到Zookeeper上
最前面是命名服務(wù),后面跟的是無(wú)狀態(tài)的twmemproxy(twitter的改進(jìn)的,用C寫(xiě)的) ,后面才是redis;
2.twmemproxy
應(yīng)用不必關(guān)心連接失敗, 由代理負(fù)責(zé)重連
把Hash算法放到代理商
代理后邊的升級(jí), 前端不關(guān)心, 解決了HA的問(wèn)題
無(wú)狀態(tài), 多臺(tái)代理無(wú)所謂
3.AS --> Proxy -->Redis
4.Sina的Redis都是單機(jī)版, 而Redis-Cluster交互過(guò)于復(fù)雜,沒(méi)有使用
做HA的話(huà),一定要配合監(jiān)控來(lái)做,如果掛了之后,后續(xù)該如何做;
并不是追求單機(jī)性能,而是集群的吞吐量,從而可以支持無(wú)線(xiàn)擴(kuò)展;
經(jīng)驗(yàn)總結(jié)
- 提前做好數(shù)據(jù)量的規(guī)劃, 減少sharding(互聯(lián)網(wǎng)公司一般以年為單位)
- 只存精細(xì)化數(shù)據(jù)(內(nèi)存很金貴!)
- 存儲(chǔ)用戶(hù)維度的數(shù)據(jù)
- 對(duì)象維度的數(shù)據(jù)要有生命周期
- 特別是數(shù)據(jù)量特別大的時(shí)候,就很有必要來(lái)進(jìn)行劃分了;
- 暴露服務(wù)的常見(jiàn)過(guò)程: IP-->負(fù)載均衡-->域名-->命名服務(wù)(一張表: 名字+資源(IP+端口))
- 對(duì)于硬件消耗,IO、網(wǎng)絡(luò)和CPU相比,Redis最消耗的是CPU,復(fù)雜的數(shù)據(jù)類(lèi)型必定帶來(lái)CPU消耗;
- 新浪微博響應(yīng)時(shí)間超時(shí)目前設(shè)置為5s;(返回很慢的記錄key,需記錄下來(lái)分析,慢日志);
- 備份的數(shù)據(jù)要定期要跑一下生產(chǎn)的數(shù)據(jù);用來(lái)檢查備份數(shù)據(jù)的有效性;
- slave掛多了肯定會(huì)對(duì)master造成比較的影響;新浪微博目前使用的M/S是一拖一,主要用來(lái)做容災(zāi);
- 同步時(shí),是fork出一個(gè)單獨(dú)進(jìn)程來(lái)和slave進(jìn)行同步;不會(huì)占用查詢(xún)的進(jìn)程;
- 升級(jí)到2.6.30以后的linux內(nèi)核;
- 在2.6.30以上對(duì)軟中斷的問(wèn)題處理的很好,性能提升效果明顯,差不多有15%到30%的差距;
- redis不用讀寫(xiě)分離,每個(gè)請(qǐng)求都是單線(xiàn)程,為什么要進(jìn)行讀寫(xiě)分離。
原文地址:https://www.cnblogs.com/me115/p/3482783.html
JAVA編程技術(shù)樂(lè)園:一個(gè)分享編程知識(shí)。跟著老司機(jī)一起學(xué)習(xí)干貨技術(shù)知識(shí),每天進(jìn)步一點(diǎn)點(diǎn),讓小的積累,帶來(lái)大的改變!
歡迎關(guān)注!持續(xù)推送有趣有料的技術(shù)文章~