⑴ redis資料庫如何存取
簡而言之,Redis是一種強大的key-value資料庫,之所以強大有兩點:響應速度快(所以數據內存存儲,只在必要時寫入磁碟),特性豐富(支持多種數據類型,以及各類型上的復雜操作)。
事實上,Redis的一個重要特性就是它並非通常意義上的資料庫,雖然稱之為資料庫是因為它可以為你存儲和維護數據,但它並不像關系資料庫那樣提供任何的sql方言。不過不用擔心,Redis並不是吞噬數據的黑洞,它只是不支持SQL及相關功能,但卻提供了穩健的協議用於與之交互。
在Redis中,沒有數據表的概念,也無須關心select、join、view等操作或功能,同時也不提供類似於int或varchar的數據欄位。你面對的將是相對原始的數據集合及數據類型。
探索之二:Available datatypes
下面我們深入看下這個奇怪的資料庫是如何工作的。如上所見,Redis是基於key-value範式存儲數據,所以先來重點看下"key"的概念。
key本質上就是簡單的字元串,諸如"username"、"password"等。在定義key時,除了不能使用空格,你可以隨意的使用普通的字元、數字等,像".",":","_"等在定義key時都能正常使用,所以像"user_name", "user:123:age", "user:123:username"都是不錯的key的定義方式。
不像RDBMS中的欄位名稱,這里的key是Redis中的重要組成部分,所以我們必須在處理key時多加小心。在下面的講述中,Redis並沒有table的概念,所以像"SELECT username from users WHERE user_id=123;"這種簡單任務都只能換種方式實現,為了達到這種目的,在Redis上,一種方式是通過key "user:123:username"來獲取結果value。如你所見,key的定義中攜帶了神秘信息(像user ids)。在Redis中,key的重要性可見一斑。(其他key-value資料庫中key的地位也是如此。)
⑵ Redis百億級Key存儲設計方案
該應用場景為DMP緩存存儲需求,DMP需要管理非常多的第三方id數據,其中包括各媒體cookie與自身cookie(以下統稱supperid)的mapping關系,還包括了supperid的人口標簽、移動端id(主要是idfa和imei)的人口標簽,以及一些黑名單id、ip等數據。
在hdfs的幫助下離線存儲千億記錄並不困難,然而DMP還需要提供毫秒級的實時查詢。由於cookie這種id本身具有不穩定性,所以很多的真實用戶的瀏覽行為會導致大量的新cookie生成,只有及時同步mapping的數據才能命中DMP的人口標簽,無法通過預熱來獲取較高的命中,這就跟緩存存儲帶來了極大的挑戰。
經過實際測試,對於上述數據,常規存儲超過五十億的kv記錄就需要1T多的內存,如果需要做高可用多副本那帶來的消耗是巨大的,另外kv的長短不齊也會帶來很多內存碎片,這就需要超大規模的存儲方案來解決上述問題。
人⼝標簽主要是cookie、imei、idfa以及其對應的gender(性別)、age(年齡段)、geo(地域)等;mapping關系主要是媒體cookie對supperid的映射。以下是數據存儲⽰示例:
媒體編號-媒體cookie=>supperid
supperid => { age=>年齡段編碼,gender=>性別編碼,geo=>地理位置編碼 }
imei or idfa => { age=>年齡段編碼,gender=>性別編碼,geo=>地理位置編碼 }
顯然PC數據需要存儲兩種key=>value還有key=>hashmap,⽽而Device數據需要存儲⼀一種
key=>hashmap即可。
存儲吃緊的一個重要原因在於每天會有很多新數據入庫,所以及時清理數據尤為重要。主要方法就是發現和保留熱數據淘汰冷數據。
網民的量級遠遠達不到幾十億的規模,id有一定的生命周期,會不斷的變化。所以很大程度上我們存儲的id實際上是無效的。而查詢其實前端的邏輯就是廣告曝光,跟人的行為有關,所以一個id在某個時間窗口的(可能是一個campaign,半個月、幾個月)訪問行為上會有一定的重復性。
數據初始化之前,我們先利用hbase將日誌的id聚合去重,劃定TTL的范圍,一般是35天,這樣可以砍掉近35天未出現的id。另外在Redis中設置過期時間是35天,當有訪問並命中時,對key進行續命,延長過期時間,未在35天出現的自然淘汰。這樣可以針對穩定cookie或id有效,實際證明,續命的方法對idfa和imei比較實用,長期積累可達到非常理想的命中。
Hash表空間大小和Key的個數決定了沖突率(或者用負載因子衡量),再合理的范圍內,key越多自然hash表空間越大,消耗的內存自然也會很大。再加上大量指針本身是長整型,所以內存存儲的膨脹十分可觀。先來談談如何把key的個數減少。
大家先來了解一種存儲結構。我們期望將key1=>value1存儲在redis中,那麼可以按照如下過程去存儲。先用固定長度的隨機散列md5(key)值作為redis的key,我們稱之為BucketId,而將key1=>value1存儲在hashmap結構中,這樣在查詢的時候就可以讓client按照上面的過程計算出散列,從而查詢到value1。
過程變化簡單描述為:get(key1) -> hget(md5(key1), key1) 從而得到value1。
如果我們通過預先計算,讓很多key可以在BucketId空間里碰撞,那麼可以認為一個BucketId下面掛了多個key。比如平均每個BucketId下面掛10個key,那麼理論上我們將會減少超過90%的redis key的個數。
具體實現起來有一些麻煩,而且用這個方法之前你要想好容量規模。我們通常使用的md5是32位的hexString(16進制字元),它的空間是128bit,這個量級太大了,我們需要存儲的是百億級,大約是33bit,所以我們需要有一種機制計算出合適位數的散列,而且為了節約內存,我們需要利用全部字元類型(ASCII碼在0~127之間)來填充,而不用HexString,這樣Key的長度可以縮短到一半。
下面是具體的實現方式
參數bit決定了最終BucketId空間的大小,空間大小集合是2的整數冪次的離散值。這里解釋一下為何一個位元組中只有7位可用,是因為redis存儲key時需要是ASCII(0~127),而不是byte array。如果規劃百億級存儲,計劃每個桶分擔10個kv,那麼我們只需2^30=1073741824的桶個數即可,也就是最終key的個數。
碎片主要原因在於內存無法對齊、過期刪除後,內存無法重新分配。通過上文描述的方式,我們可以將人口標簽和mapping數據按照上面的方式去存儲,這樣的好處就是redis key是等長的。另外對於hashmap中的key我們也做了相關優化,截取cookie或者deviceid的後六位作為key,這樣也可以保證內存對齊,理論上會有沖突的可能性,但在同一個桶內後綴相同的概率極低(試想id幾乎是隨機的字元串,隨意10個由較長字元組成的id後綴相同的概率*桶樣本數=發生沖突的期望值<<0.05,也就是說出現一個沖突樣本則是極小概率事件,而且這個概率可以通過調整後綴保留長度控制期望值)。而value只存儲age、gender、geo的編碼,用三個位元組去存儲。
另外提一下,減少碎片還有個很low但是有效的方法,將slave重啟,然後強制的failover切換主從,這樣相當於給master整理的內存的碎片。
推薦Google-tcmalloc, facebook-jemalloc內存分配,可以在value不大時減少內存碎片和內存消耗。有人測過大value情況下反而libc更節約。
1)kv存儲的量級必須事先規劃好,浮動的范圍大概在桶個數的十到十五倍,比如我就想存儲百億左右的kv,那麼最好選擇30bit 31bit作為桶的個數。也就是說業務增長在一個合理的范圍(10 15倍的增長)是沒問題的,如果業務太多倍數的增長,會導致hashset增長過快導致查詢時間增加,甚至觸發zip-list閾值,導致內存急劇上升。
2)適合短小value,如果value太大或欄位太多並不適合,因為這種方式必須要求把value一次性取出,比如人口標簽是非常小的編碼,甚至只需要3、4個bit(位)就能裝下。
3)典型的時間換空間的做法,由於我們的業務場景並不是要求在極高的qps之下,一般每天億到十億級別的量,所以合理利用CPU租值,也是十分經濟的。
4)由於使用了信息摘要降低了key的大小以及約定長度,所以無法從redis裡面random出key。如果需要導出,必須在冷數據中導出。
5)expire需要自己實現,目前的演算法很簡單,由於只有在寫操作時才會增加消耗,所以在寫操作時按照一定的比例抽樣,用HLEN命中判斷是否超過15個entry,超過才將過期的key刪除,TTL的時間戳存儲在value的前32bit中。
6)桶的消耗統計是需要做的。需要定期清理過期的key,保證redis的查詢不會變慢。
人口標簽和mapping的數據100億條記錄。
優化前用2.3T,碎片率在2左右;優化後500g,而單個桶的平均消耗在4左右。碎片率在1.02左右。查詢時這對於cpu的耗損微乎其微。
另外需要提一下的是,每個桶的消耗實際上並不是均勻的,而是符合多項式分布的。
上面的公式可以計算桶消耗的概率分布。公式是唬人用的,只是為了提醒大家不要想當然的認為桶消耗是完全均勻的,有可能有的桶會有上百個key。但事實並不沒有那麼誇張。試想一下投硬幣,結果只有兩種正反面。相當於只有兩個桶,如果你投上無限多次,每一次相當於一次伯努利實驗,那麼兩個桶必然會十分的均勻。概率分布就像上帝施的魔咒一樣,當你面對大量的桶進行很多的廣義的伯努利實驗。桶的消耗分布就會趨於一種穩定的值。接下來我們就了解一下桶消耗分布具體什麼情況:
通過采樣統計
31bit(20多億)的桶,平均4.18消耗
100億節約了1.8T內存。相當於節約了原先的78%內存,而且桶消耗指標遠沒有達到預計的底線值15。
對於未出現的桶也是存在一定量的,如果過多會導致規劃不準確,其實數量是符合二項分布的,對於2 30桶存儲2 32kv,不存在的桶大概有(百萬級別,影響不大):
Math.pow((1 - 1.0 / Math.pow(2, 30)), Math.pow(2, 32)) * Math.pow(2, 30);
對於桶消耗不均衡的問題不必太擔心,隨著時間的推移,寫入時會對HLEN超過15的桶進行削減,根據多項式分布的原理,當實驗次數多到一定程度時,桶的分布就會趨於均勻(硬幣投擲無數次,那麼正反面出現次數應該是一致的),只不過我們通過expire策略削減了桶消耗,實際上對於每個桶已經經歷了很多的實驗發生。
總結:信息摘要在這種場景下不僅能節約key存儲,對齊了內存,還能讓Key按照多項式分布均勻的散列在更少量的key下面從而減少膨脹,另外無需在給key設置expire,也很大程度上節約了空間。
這也印證了時間換空間的基本理論,合理利用CPU租值也是需要考慮的。
關注分布式存儲技術以及分布式計算方法
⑶ 通過Redis消息隊列實現大文件處理
一、故事背景
1、讀取離線文件數據,再通過【離線數據】作為條件,查詢第三方介面,返回最終的結果,再入庫。
2、 業務邏輯是很簡單, 讀取文件、查詢介面、返回數據集、入庫 四步。
3、業務特性:第三方介面調用400毫秒(ms) 。
如果用普通單線程去跑算500毫秒一個請求,一天也就跑8W多數據量,20多億的數據不知道跑到猴年馬月了。
二、處理方案
A) 初步方案採用ganymed-ssh2(文件都存儲在Linux伺服器上) 來讀文件,Redis來存儲消息、多線程來提升處理能力。
B) 流程圖:
三、呈現問題
四、優化問題
最終流程圖:
1、 通過Redis做一個計數器 每讀取一行記錄數值,即使服務終止後,先從Redis讀取這個數值
再通過cat指定行數開始讀數據即可。
2、 通過取模拆Key 分片到不同小Key存儲 ,降低單個節點存儲壓力,也充分利用了存儲資源。
3、Redis Push 提供了批量方式(leftPushAll) ,可以指定讀取行數再批量入庫,而pop並沒有提供批量 只能一個一個pop。
4、消費者通過多線程pop、再分發到線程去處理。
五、總結問題
⑷ 數據多的時候為什麼要使用redis而不用mysql
通常來說,當數據多、並發量大的時候,架構中可以引入Redis,幫助提升架構的整體性能,減少Mysql(或其他資料庫)的壓力,但不是使用Redis,就不用MySQL。
因為Redis的性能十分優越,可以支持每秒十幾萬此的讀/寫操作,並且它還支持持久化、集群部署、分布式、主從同步等,Redis在高並發的場景下數據的安全和一致性,所以它經常用於兩個場景:
緩存
判斷數據是否適合緩存到Redis中,可以從幾個方面考慮: 會經常查詢么?命中率如何?寫操作多麼?數據大小?
我們經常採用這樣的方式將數據刷到Redis中:查詢的請求過來,現在Redis中查詢,如果查詢不到,就查詢資料庫拿到數據,再放到緩存中,這樣第二次相同的查詢請求過來,就可以直接在Redis中拿到數據;不過要注意【緩存穿透】的問題。
緩存的刷新會比較復雜,通常是修改完資料庫之後,還需要對Redis中的數據進行操作;代碼很簡單,但是需要保證這兩步為同一事務,或最終的事務一致性。
高速讀寫
常見的就是計數器,比如一篇文章的閱讀量,不可能每一次閱讀就在資料庫裡面update一次。
高並發的場景很適合使用Redis,比如雙11秒殺,庫存一共就一千件,到了秒殺的時間,通常會在極為短暫的時間內,有數萬級的請求達到伺服器,如果使用資料庫的話,很可能在這一瞬間造成資料庫的崩潰,所以通常會使用Redis(秒殺的場景會比較復雜,Redis只是其中之一,例如如果請求超過某個數量的時候,多餘的請求就會被限流)。
這種高並發的場景,是當請求達到伺服器的時候,直接在Redis上讀寫,請求不會訪問到資料庫;程序會在合適的時間,比如一千件庫存都被秒殺,再將數據批量寫到資料庫中。
所以通常來說,在必要的時候引入Redis,可以減少MySQL(或其他)資料庫的壓力,兩者不是替代的關系 。
我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。
Redis和MySQL的應用場景是不同的。
通常來說,沒有說用Redis就不用MySQL的這種情況。
因為Redis是一種非關系型資料庫(NoSQL),而MySQL是一種關系型資料庫。
和Redis同類的資料庫還有MongoDB和Memchache(其實並沒有持久化數據)
那關系型資料庫現在常用的一般有MySQL,SQL Server,Oracle。
我們先來了解一下關系型資料庫和非關系型資料庫的區別吧。
1.存儲方式關系型資料庫是表格式的,因此存儲在表的行和列中。他們之間很容易關聯協作存儲,提取數據很方便。而Nosql資料庫則與其相反,他是大塊的組合在一起。通常存儲在數據集中,就像文檔、鍵值對或者圖結構。
2.存儲結構關系型資料庫對應的是結構化數據,數據表都預先定義了結構(列的定義),結構描述了數據的形式和內容。這一點對數據建模至關重要,雖然預定義結構帶來了可靠性和穩定性,但是修改這些數據比較困難。而Nosql資料庫基於動態結構,使用與非結構化數據。因為Nosql資料庫是動態結構,可以很容易適應數據類型和結構的變化。
3.存儲規范關系型資料庫的數據存儲為了更高的規范性,把數據分割為最小的關系表以避免重復,獲得精簡的空間利用。雖然管理起來很清晰,但是單個操作設計到多張表的時候,數據管理就顯得有點麻煩。而Nosql數據存儲在平面數據集中,數據經常可能會重復。單個資料庫很少被分隔開,而是存儲成了一個整體,這樣整塊數據更加便於讀寫
4.存儲擴展這可能是兩者之間最大的區別,關系型資料庫是縱向擴展,也就是說想要提高處理能力,要使用速度更快的計算機。因為數據存儲在關系表中,操作的性能瓶頸可能涉及到多個表,需要通過提升計算機性能來克服。雖然有很大的擴展空間,但是最終會達到縱向擴展的上限。而Nosql資料庫是橫向擴展的,它的存儲天然就是分布式的,可以通過給資源池添加更多的普通資料庫伺服器來分擔負載。
5.查詢方式關系型資料庫通過結構化查詢語言來操作資料庫(就是我們通常說的SQL)。SQL支持資料庫CURD操作的功能非常強大,是業界的標准用法。而Nosql查詢以塊為單元操作數據,使用的是非結構化查詢語言(UnQl),它是沒有標準的。關系型資料庫表中主鍵的概念對應Nosql中存儲文檔的ID。關系型資料庫使用預定義優化方式(比如索引)來加快查詢操作,而Nosql更簡單更精確的數據訪問模式。
6.事務關系型資料庫遵循ACID規則(原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)),而Nosql資料庫遵循BASE原則(基本可用(Basically Availble)、軟/柔性事務(Soft-state )、最終一致性(Eventual Consistency))。由於關系型資料庫的數據強一致性,所以對事務的支持很好。關系型資料庫支持對事務原子性細粒度控制,並且易於回滾事務。而Nosql資料庫是在CAP(一致性、可用性、分區容忍度)中任選兩項,因為基於節點的分布式系統中,很難全部滿足,所以對事務的支持不是很好,雖然也可以使用事務,但是並不是Nosql的閃光點。
7.性能關系型資料庫為了維護數據的一致性付出了巨大的代價,讀寫性能比較差。在面對高並發讀寫性能非常差,面對海量數據的時候效率非常低。而Nosql存儲的格式都是key-value類型的,並且存儲在內存中,非常容易存儲,而且對於數據的 一致性是 弱要求。Nosql無需sql的解析,提高了讀寫性能。
8.授權方式大多數的關系型資料庫都是付費的並且價格昂貴,成本較大(MySQL是開源的,所以應用的場景最多),而Nosql資料庫通常都是開源的。
所以,在實際的應用環境中,我們一般會使用MySQL存儲我們的業務過程中的數據,因為這些數據之間的關系比較復雜,我們常常會需要在查詢一個表的數據時候,將其他關系表的數據查詢出來,例如,查詢某個用戶的訂單,那至少是需要用戶表和訂單表的數據。
查詢某個商品的銷售數據,那可能就會需要用戶表,訂單表,訂單明細表,商品表等等。
而在這樣的使用場景中,我們使用Redis來存儲的話,也就是KeyValue形式存儲的話,其實並不能滿足我們的需要。
即使Redis的讀取效率再高,我們也沒法用。
但,對於某些沒有關聯少,且需要高頻率讀寫,我們使用Redis就能夠很好的提高整個體統的並發能力。
例如商品的庫存信息,我們雖然在MySQL中會有這樣的欄位,但是我們並不想MySQL的資料庫被高頻的讀寫,因為使用這樣會導致我的商品表或者庫存表IO非常高,從而影響整個體統的效率。
所以,對於這樣的數據,且有沒有什麼復雜邏輯關系(就只是隸屬於SKU)的數據,我們就可以放在Redis裡面,下單直接在Redis中減掉庫存,這樣,我們的訂單的並發能力就能夠提高了。
個人覺得應該站出來更正一下,相反的數據量大,更不應該用redis。
因為redis是內存型資料庫啊,是放在內存里的。
設想一下,假如你的電腦100G的資料,都用redis來存儲,那麼你需要100G以上的內存!
使用場景Redis最明顯的用例之一是將其用作緩存。只是保存熱數據,或者具有過期的cache。
例如facebook,使用Memcached來作為其會話緩存。
總之,沒有見過哪個大公司數據量大了,換掉mysql用redis的。
題主你錯了,不是用redis代替MySQL,而是引入redis來優化。
BAT里越來越多的項目組已經採用了redis+MySQL的架構來開發平台工具。
如題主所說,當數據多的時候,MySQL的查詢效率會大打折扣。我們通常默認如果查詢的欄位包含索引的話,返回是毫秒級別的。但是在實際工作中,我曾經遇到過一張包含10個欄位的表,1800萬+條數據,當某種場景下,我們不得不根據一個未加索引的欄位進行精確查詢的時候,單條sql語句的執行時長有時能夠達到2min以上,就更別提如果用like這種模糊查詢的話,其效率將會多麼低下。
我們最開始是希望能夠通過增加索引的方式解決,但是面對千萬級別的數據量,我們也不敢貿然加索引,因為一旦資料庫hang住,期間的所有資料庫寫入請求都會被放到等待隊列中,如果請求是通過http請求發過來的,很有可能導致服務發生分鍾級別的超時不響應。
經過一番調研,最終敲定的解決方案是引入redis作為緩存。redis具有運行效率高,數據查詢速度快,支持多種存儲類型以及事務等優勢,我們把經常讀取,而不經常改動的數據放入redis中,伺服器讀取這類數據的時候時候,直接與redis通信,極大的緩解了MySQL的壓力。
然而,我在上面也說了,是redis+MySQL結合的方式,而不是替代。原因就是redis雖然讀寫很快,但是不適合做數據持久層,主要原因是使用redis做數據落盤是要以效率作為代價的,即每隔制定的時間,redis就要去進行數據備份/落盤,這對於單線程的它來說,勢必會因「分心」而影響效率,結果得不償失。
樓主你好,首先糾正下,數據多並不是一定就用Redis,Redis歸屬於NoSQL資料庫中,其特點擁有高性能讀寫數據速度,主要解決業務效率瓶頸。下面就詳細說下Redis的相比MySQL優點。( 關於Redis詳細了解參見我近期文章:https://www.toutiao.com/i6543810796214813187/ )
讀寫異常快
Redis非常快,每秒可執行大約10萬次的讀寫速度。
Redis支持豐富的數據類型,有二進制字元串、列表、集合、排序集和散列等等。這使得Redis很容易被用來解決各種問題,因為我們知道哪些問題可以更好使用地哪些數據類型來處理解決。
原子性Redis的所有操作都是原子操作,這確保如果兩個客戶端並發訪問,Redis伺服器能接收更新的值。
豐富實用工具 支持異機主從復制Redis支持主從復制的配置,它可以實現主伺服器的完全拷貝。
以上為開發者青睞Redis的主要幾個可取之處。但是,請注意實際生產環境中企業都是結合Redis和MySQL的特定進行不同應用場景的取捨。 如緩存——熱數據、計數器、消息隊列(與ActiveMQ,RocketMQ等工具類似)、位操作(大數據處理)、分布式鎖與單線程機制、最新列表(如新聞列表頁面最新的新聞列表)以及排行榜等等 可以看見Redis大顯身手的場景。可是對於嚴謹的數據准確度和復雜的關系型應用MySQL等關系型資料庫依然不可替。
web應用中一般採用MySQL+Redis的方式,web應用每次先訪問Redis,如果沒有找到數據,才去訪問MySQL。
本質區別1、mysql:數據放在磁碟 redis:數據放在內存。
首先要知道mysql存儲在磁碟里,redis存儲在內存里,redis既可以用來做持久存儲,也可以做緩存,而目前大多數公司的存儲都是mysql + redis,mysql作為主存儲,redis作為輔助存儲被用作緩存,加快訪問讀取的速度,提高性能。
使用場景區別1、mysql支持sql查詢,可以實現一些關聯的查詢以及統計;
2、redis對內存要求比較高,在有限的條件下不能把所有數據都放在redis;
3、mysql偏向於存數據,redis偏向於快速取數據,但redis查詢復雜的表關系時不如mysql,所以可以把熱門的數據放redis,mysql存基本數據。
mysql的運行機制mysql作為持久化存儲的關系型資料庫,相對薄弱的地方在於每次請求訪問資料庫時,都存在著I/O操作,如果反復頻繁的訪問資料庫。第一:會在反復鏈接資料庫上花費大量時間,從而導致運行效率過慢;第二:反復地訪問資料庫也會導致資料庫的負載過高,那麼此時緩存的概念就衍生了出來。
Redis持久化由於Redis的數據都存放在內存中,如果沒有配置持久化,redis重啟後數據就全丟失了,於是需要開啟redis的持久化功能,將數據保存到磁碟上,當redis重啟後,可以從磁碟中恢復數據。redis提供兩種方式進行持久化,一種是RDB持久化(原理是將Reids在內存中的資料庫記錄定時mp到磁碟上的RDB持久化),另外一種是AOF(append only file)持久化(原理是將Reids的操作日誌以追加的方式寫入文件)。
redis是放在內存的~!
數據量多少絕對不是選擇redis和mysql的准則,因為無論是mysql和redis都可以集群擴展,約束它們的只是硬體(即你有沒有那麼多錢搭建上千個組成的集群),我個人覺得數據讀取的快慢可能是選擇的標准之一,另外工作中往往是兩者同是使用,因為mysql存儲在硬碟,做持久化存儲,而redis存儲在內存中做緩存提升效率。
關系型資料庫是必不可少的,因為只有關系型資料庫才能提供給你各種各樣的查詢方式。如果有一系列的數據會頻繁的查詢,那麼就用redis進行非持久化的存儲,以供查詢使用,是解決並發性能問題的其中一個手段
⑸ Redis適合存儲海量小文件嗎
最近學習下redis,作為一個高性能的k/v資料庫,如果數據不用swap的話,redis的性能是無以倫比的。最近在做一個系統附件的緩存,試著把附件放到redis試試,寫了個保存文件的方法。public class TestRedis{ Jedis redis = new Jedis("localhost");...
⑹ 誰有關於redis 存儲海量數據高性能的demo,請上傳一下
1. Redis使用場景
Redis是一個開源的使用ANSI c語言編寫、支持網路、可基於內存亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。
我們都知道,在日常的應用中,資料庫瓶頸是最容易出現的。數據量太大和頻繁的查詢,由於磁碟IO性能的局限性,導致項目的性能越來越低。
這時候,基於內存的緩存框架,就能解決我們很多問題。例如Memcache,Redis等。將一些頻繁使用的數據放入緩存讀取,大大降低了資料庫的負擔。提升了系統的性能。
其實,對於hibernate的二級緩存,是同樣的道理。利用內存高速的讀寫速度,來解決硬碟的瓶頸。
2. 配置使用redis
首先,我們需要引入基本的jar包。maven中的基本引用如下:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.2</version>
</dependency>
然後,在applicationContext中配置如下:
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"
p:pool-config-ref="poolConfig" />
<bean id="stringSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<!-- 開啟事務,可以通過transcational註解控制 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer" ref="stringSerializer" />
<property name="enableTransactionSupport" value="true" />
</bean>
對於hibernate的配置可知,第一個poolconfig是對連接池的配置。包括最大連接數,隊列數,存活時間,最大等待時間等等,還有一些額外的配置,請直接點擊JedisPoolConfig類源碼,進行查看。
這些配置的意思如果不明白的話,一定要去把線程池好好學習下。
第一個配置是連接工廠,顧名思義,最基本的使用一定是對連接的打開和關閉。我們需要為其配置redis伺服器的賬戶密碼,埠號。(這里還可以配置資料庫的index,但是我使用時候一直使用redis的默認資料庫,也就是第0個)
最後一個配置特別重要。這個類似於spring提供的HibernateDaoSupport。
接下來,全部講解都將圍繞這個類展開。
3. RedisTemplate的使用
這個類作為一個模版類,提供了很多快速使用redis的api,而不需要自己來維護連接,事務。
最初的時候,我創建的BaseRedisDao是繼承自這個類的。繼承的好處是我的每個Dao中,都可以自由的控制序列化器,自由的控制自己是否需要事務,這個先不需要了解,跟著我目前的這種配置方法來即可。
template提供了一系列的operation,比如valueOperation,HashOperation,ListOperation,SetOperation等,用來操作不同數據類型的Redis。
並且,RedisTemplate還提供了對應的*OperationsEditor,用來通過RedisTemplate直接注入對應的Operation。我們暫時不講這個。
對於下面的test1方法,我們暫時不用考慮,先了解通過RedisTemplate來使用connection操作Redis。
Test代碼如下:
package cn.test.spjedis;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework..DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.cn.redis2..IncrDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestRedis {
@Resource(name = "redisTemplate")
private RedisTemplate<String, String> template; // inject the template as ListOperations
//至於這個為什麼可以注入。需要參考AbstractBeanFactory doGetBean
//super.setValue(((RedisOperations) value).opsForValue());就這一行代碼 依靠一個editor
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> vOps;
public void testSet(){
template.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
byte [] key = "tempkey".getBytes();
byte[] value = "tempvalue".getBytes();
connection.set(key, value);
return true;
}
});
}
public void testSet1(){
vOps.set("tempkey", "tempvalue");
}
@Autowired
private IncrDao incr;
@Test
public void addLink() {
System.out.println(incr.incr(13));
System.out.println(incr.get(13));
}
}
⑺ Redis 存儲壓縮實戰
xx的模型分計算,由於客戶對響應要求比較高,要求在20ms內就需要返回, 同時QPS要求為60W .
所以存儲這一塊的選則就是使用的Redis的集群(無主從,更多資源用來存儲,同時高可用要求不高)
一開始使用最直接使用了String的Key-Value入庫 ; 結果,才入了八億的數據,內存就去到了140g .對單點分析之後得出對象數量3000w, 數據內存消耗:2.72g,大約一條記錄數據大小是97位元組,但實際節點佔用內存:5.13g . 運維給出來的答復是 :
數據量: 50億+
數據格式: MD5(imei) :Score1(double),Score2(double)
單條純數據量: 32位元組
首先ZipList是作為Redis的一種底層數據結構, 在一定條件下可作用於HashTable,List,Set的底層實現,
由於其設定是使用一整塊的連續內存 (可看似數組結構) ,減少了內存碎片的產生,同時在提供了較高的效率 .
由於ZipList的初始是申請一個連續的長度為zlbytes的內存 , 所以正常情況下對ZipList的修改都會觸發內存的重分配, 同時有可能發生數據的復制開銷比較大.
這也是ZipList不適合用於存放過大量數據.
以下是HashTable底層使用ZipList的相關配置:
要使用ZipList作為存儲結構,所以使用HashTable的時候要將entry的數量控制在ZipList的hash-max-ziplist-entries閾值內 ( 極光這里配置的是256 先不做修改,按這個條件來 )
根據上面的需要將entry數量控制再256以內 , 所以按照50億的總數量計算的話那麼, Redis Key 的KeyNum應該是:
這里的KeyNum根據實際情況可以預估大一點以備數據量增加
通過上一步我們確定了KeyNum的范圍 ,那麼這一步就要考慮如何將要做的就是找到一個確定的數量使得我們50億的數據可以均勻的分布再這 KeyNum 個HashTable里
如下圖所示,我們的Key是32位的MD5(imei), 為了達到更好的內存合理使用,所以這里考慮將這32位的十六進制拆分成兩部分, 一部分作為Redis的Key,一部分作為HashTable的field.
如果 使用六位的 十六進製作為Redis Key那麼他的KeyNum為:
2^24 = 16,777,216
同理 七位 :
2^28 = 268,435,456
同理 八位 :
2^32 = 4,294,967,296
與上面 計算出來的 19,531,250比較, 使用七位的十六進製作為Key 的話,那麼理論上他的每個HashTable的Entries數量就是大概20個左右. 所以直接選擇了7位的十六進制
這里六位的十六進制也可以選擇的,只需要將上述的hash-max-ziplist-entries 配置的稍微大一點,但是帶來的就是hget的時候會比七位十六進制的慢. 由於沒有做過hget差異實驗 ,所以就保險的先選擇7位.
如下圖所示,進行拆分,由於七位的十六進制 只有3.5個位元組,所以這里需要補一個十六進制的 Ɔ' 湊整4個位元組.
為了使切分七位十六進制後的數據更均勻分布,應該對選擇的目標七位十六進制進行groupBy,然後看看,數據分布的是不是足夠的均勻. 假設,如果有大量MD5(imei) 的前七位都是零,那麼就會造成 key為00000000的這個HashTable 過於龐大,而沒法使用ZipList . 經過對玖富的數據進行分析,最終選取後七位
1.可以通過減少RedisKey的數量, 達到增加每個HashTable的Entry的數量,達到內存縮減
⑻ redis存儲和雲存儲
雲資料庫Redis版是完全兼容Redis協議的雲原生高性能內存資料庫。
任何兼容Redis的客戶端都可以與雲資料庫Redis版建立連接進行數據存儲及相應操作。
⑼ redis數據類型和應用場景
Redis是當前比較熱門的NOSQL系統之一,它是一個開源的使用ANSI c語言編寫的key-value存儲系統(區別於MySQL的二維表格的形式存儲。),Redis數據都是緩存在計算機內存中並且它會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件,實現數據的持久化。談到存儲數據,那麼必然要涉及到相關的數據類型,redis主要有以下數據類型:
描述:string 是 redis 最基本的類型,你可以理解成與 Memcached 一模一樣的類型,一個 key 對應一個 value。value其實不僅是String,也可以是數字。string 類型是二進制安全的。意思是 redis 的 string 可以包含任何數據。比如jpg圖片或者序列化的對象。string 類型是 Redis 最基本的數據類型,string 類型的值最大能存儲 512MB。
常用命令:get、set、incr、decr、mget等。
應用場景:規key-value緩存應用。常規計數: 點贊數, 粉絲數。
描述: hash 是一個鍵值(key => value)對集合。Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用於存儲對象。
常用命令:hget,hset,hgetall 等。
應用場景:存儲部分變更數據,如商品信息等。
描述:list 列表是簡單的字元串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。列表最多可存儲 232 - 1 元素 (4294967295, 每個列表可存儲40多億)。
常用命令:lpush(添加左邊元素),rpush,lpop(移除左邊第一個元素),rpop,lrange(獲取列表片段,LRANGE key start stop)等。
應用場景:消息隊列,關注列表,粉絲列表等都可以用Redis的list結構來實現。
描述: set是string類型的無序集合。集合是通過hashtable實現的,概念和數學中個的集合基本類似,可以交集,並集,差集等等,set中的元素是沒有順序的。所以添加,刪除,查找的復雜度都是O(1)。
常用命令:sadd,spop,smembers,sunion 等。
應用場景:交集,並集,差集(微博中,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合。Redis還為集合提供了求交集、並集、差集等操作,可以非常方便的實現如共同關注、共同喜好、二度好友等功能,對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中)
描述:zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。不同是可以打分(排序)
常用命令:zadd,zrange,zrem,zcard等
應用場景:排行榜,帶權重的消息隊列
描述:Bitmaps這個「數據結構」可以實現對位的操作。 把數據結構加上引號主要因為:
Bitmaps本身不是一種數據結構, 實際上它就是字元串 , 但是它可以對字元串的位進行操作。
Bitmaps單獨提供了一套命令, 所以在Redis中使用Bitmaps和使用字元串的方法不太相同。 可以把Bitmaps想像成一個以位為單位的數組, 數組的每個單元只能存儲0和1, 數組的下標在Bitmaps中叫做偏移量。其實大多數Bitmaps的應用場景可以用其他數據類型來實現,用Bitmaps主要是存儲空間佔用特別少
常用命令:getbit key offset;setbit key offset value
應用場景:統計用戶訪問,統計電影某天的的播放量
描述:Redis 在 2.8.9 版本添加了 HyperLogLog 結構。Redis HyperLogLog 是用來做基數統計的演算法,HyperLogLog 的優點是,在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定 的、並且是很小的。在 Redis 裡面,每個 HyperLogLog 鍵只需要花費 12 KB 內存,就可以計算接近 2^64 個不同元素的基 數。這和計算基數時,元素越多耗費內存就越多的集合形成鮮明對比。但是,因為 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素本身,所以 HyperLogLog 不能像集合那樣,返回輸入的各個元素。這類數據結構的基本大的思路就是使用統計概率上的演算法,犧牲數據的精準性來節省內存的佔用空間及提升相關操作的性能
常用命令:pfadd, pfcount,pfmerge
應用場景:統計網站的每日UV
描述:GEO功能在Redis3.2版本提供,支持存儲地理位置信息用來實現諸如附近位置、搖一搖這類依賴於地理位置信息的功能.geo的數據類型為zset.
常用命令:geoadd,geopos, geodist
應用場景:附近位置、搖一搖
參考列表:
Redis五種數據類型及應用場景
⑽ redis 存儲什麼數據
redis開創了一種新的數據存儲思路,使用redis,我們不用在面對功能單調的資料庫時,把精力放在如何把大象放進冰箱這樣的問題上,而是利用redis靈活多變的數據結構和數據操作,為不同的大象構建不同的冰箱。
redis常用數據類型
redis最為常用的數據類型主要有以下五種:string、hash、list、set、sorted set