高效Redis Client多線程操作的并發(fā)吞吐設(shè)計
Redis是一個非常高效的基于內(nèi)存的NOSQL數(shù)據(jù)庫,它提供非常高效的數(shù)據(jù)讀寫效能.在實際應(yīng)用中往往是帶寬和CLIENT庫讀寫損耗過高導(dǎo)致無法更好地發(fā)揮出Redis更出色的能力.下面結(jié)合一些redis本身的特性和一些client操作上的改變來提高整個redis操作的效能.
上圖是反映平常操作redis的情況,每個線程都獨立的發(fā)起相應(yīng)連接對redis的網(wǎng)絡(luò)讀寫.雖然我們可以通過批操作的方式來把當前多個操作合并成一個, 但這種方式只能針對當單線程,而多線程相互合并則設(shè)計上很少關(guān)注.從redis的協(xié)議來說其實并沒有限制,只是在client庫的設(shè)計一般沒有考慮進去.
如果在多線程操作REDIS的同時如果能夠合并網(wǎng)絡(luò)操作,那意味著可以減少操作網(wǎng)絡(luò)讀寫的情況把處理能力提升到***化.這樣Client總體的性能都會有所提升,而REDIS也因表層的網(wǎng)絡(luò)讀取減少而達到更好的利用率.
以上是設(shè)計圖,原理并不復(fù)雜,其實就是把每個請求的操作放到一個隊列中,后面開啟一個線程來把前面的指令進行一個合并操操作.一個線程在高并發(fā)下可以無法更快速地合并起來,可以根據(jù)需要進行合理的操作線程應(yīng)用.
這種設(shè)計的效果是否真的比較理想呢,以下是一個簡單的測試
- public void AnycSet()
- {
- CodeTimer.Time("beetle.redis asynset", () =>
- {
- Parallel.For(0, Count, x =>
- {
- ProtobufKey key = x.ToString();
- key.AsynSet(new User() { UserId = x, NickName = "sdffffffffffffffffffffffffffffffffffffffffsdffffffffffffffffffffffffffffffffffffffffbeetlesdffffffffffffffffffffffffffffffffffffffffsdffffffffffffffffffffffffffffffffffffffff" + x });
- });
- });
- }
- public void Set()
- {
- CodeTimer.Time("beetle.redis set", () =>
- {
- Parallel.For(0, Count, x =>
- {
- ProtobufKey key = x.ToString();
- key.Set(new User() { UserId = x, NickName = "sdffffffffffffffffffffffffffffffffffffffffsdffffffffffffffffffffffffffffffffffffffffbeetlesdffffffffffffffffffffffffffffffffffffffffsdffffffffffffffffffffffffffffffffffffffff" + x });
- });
- });
- }
測試結(jié)果如下
以上是10W次的操作測試結(jié)果,由于redis在本機所以交互非常可觀.
雖然在多線程高并發(fā)下這樣的設(shè)計可以把吞吐能力和效能有一個非常不錯的效果,但其也存在缺陷因為每次操作都經(jīng)過不同線程的調(diào)處理,如果并發(fā)線程不多操作密集度不高.那效果并不理想;因為網(wǎng)絡(luò)操作密集度不高,可得到并合的數(shù)量不多,這方面的損耗有可能低于操作跨線程調(diào)度所帶來的損耗。
博文出處:http://www.open-open.com/lib/view/open1431181329085.html