您的位置:首頁 >  新聞中心 > 行業(yè)動(dòng)態(tài)
  行業(yè)動(dòng)態(tài)
 

Redis:快速提高系統(tǒng)性能的銀彈

來源:原創(chuàng)    時(shí)間:2017-11-20    瀏覽:0 次

現(xiàn)代高并發(fā)雜亂體系面臨的應(yīng)戰(zhàn)
現(xiàn)代體系跟著功用的雜亂化,各式各樣需求層出不窮,面臨愈加雜亂話的事務(wù)體系、越來越巨大的用戶集體,以及用戶對(duì)體會(huì)的要求越來越高,功用就變得愈加重要。

拋開代碼邏輯、效勞器功用的相關(guān)問題外,進(jìn)步功用的辦法有以下幾種:
動(dòng)態(tài)別離

負(fù)載均衡

分布式

集群化

緩存

限流處理

數(shù)據(jù)壓縮

其他

我們來剖析一下負(fù)載均衡、分布式、集群化觸及的問題:
裝備辦理變得雜亂,因而需求設(shè)置裝備中心來處理該問題。

同一個(gè)用戶的懇求會(huì)轉(zhuǎn)發(fā)至不同的 Web 效勞器,然后導(dǎo)致 Session 丟掉等問題。

同一個(gè)懇求在分布式環(huán)境中需求不同效勞來供給不同處理,然后需求分布式事務(wù)來確保數(shù)據(jù)的一致性。

分布式僅有 ID 問題。

別的針對(duì)不同部分體系中的一些特定問題又有其他的一些特別事務(wù)需求:
IP核算

用戶登錄記載核算

實(shí)時(shí)的排行榜

原子計(jì)數(shù)

最新談?wù)?/span>

固然,以上各種問題都有花樣繁多的處理辦法,例如:

裝備中心能夠運(yùn)用 Zookpeer、Redis 等完成。

Session 丟掉能夠運(yùn)用 Session 同步、客戶端 token、Session 同享等處理,其間 Session 同享又能夠細(xì)分不同完成辦法。

面臨層出不窮的概念,以及各種新式的技能,我們往往會(huì)顯得無能為力,那么有沒有一個(gè)銀彈能夠處理這些問題呢?

Redis 非銀彈卻無比挨近
我這兒為我們引薦的就是 Redis ,盡管它離真實(shí)含義的銀彈仍是有些間隔,可是他是為數(shù)不多的挨近銀彈的處理方案:
Redis 運(yùn)用 C 開發(fā),是一款內(nèi)存 K/V 數(shù)據(jù)庫,架構(gòu)規(guī)劃極簡(jiǎn),功用卓著。

Redis 選用 單線程 多路復(fù)用的規(guī)劃,防止了并發(fā)帶來的鎖功用損耗等問題。

Redis 裝置、測(cè)驗(yàn)、裝備、運(yùn)維較其他產(chǎn)品更為簡(jiǎn)略。

Redis 是現(xiàn)在為止最受歡迎的 K/V 數(shù)據(jù)庫,支撐耐久化,value 支撐多種數(shù)據(jù)結(jié)構(gòu)。

Redis 指令語法簡(jiǎn)略,極易把握。

Redis 供給了一種通用的協(xié)議,使得各種編程言語都能很便利的開宣布與其交互的客戶端。

Redis 開放源碼,我們能夠?qū)ζ溥M(jìn)行二次開發(fā)來定制優(yōu)化。

Redis 現(xiàn)在有較好的社區(qū)保護(hù),版別迭代有所確保,新的功用也在有條有理的添加完善。

Redis 有較好的主從復(fù)制、集群相關(guān)支撐。

最新版別供給模塊化功用,能夠便利的擴(kuò)展功用。

接下來我們就來說說怎樣運(yùn)用 Redis 處理之前說到的問題:
裝備中心

Redis 自身就是內(nèi)存 K/V 數(shù)據(jù)庫,支撐 哈希、調(diào)集、列表等五種數(shù)據(jù)結(jié)構(gòu),然后裝備信息的存儲(chǔ)、讀取速度都能夠得到滿意,Redis 還供給訂閱/發(fā)布功用然后能夠在裝備發(fā)作改動(dòng)時(shí)告訴不同效勞器來進(jìn)行更新相關(guān)裝備。

分布式鎖

運(yùn)用 Redis 的 SETNX 指令或許 SET 指令合作 NX 選項(xiàng)的辦法以及過期時(shí)刻等功用能夠很便利的完成一個(gè)功用優(yōu)越的分布式鎖。

緩存

Redis 支撐多種過期篩選機(jī)制,自身功用的優(yōu)勢(shì)也使 Redis 在緩存方面得到廣泛運(yùn)用。

Lua 腳本

Lua 是一種輕量細(xì)巧的腳本言語,用規(guī)范C言語編寫并開放源代碼。Redis 支撐 Lua 腳本的運(yùn)轉(zhuǎn),然后能夠擴(kuò)展 Redis 中的指令完成許多雜亂功用。

Redis 支撐運(yùn)用 Lua 腳正本完成一些組合指令邏輯處理,然后能夠運(yùn)用 Redis 做為限流、分布式僅有 ID 相關(guān)技能的完成。

Redis 支撐 BitMaps

位圖(bitmap)是一種十分常用的結(jié)構(gòu),在索引,數(shù)據(jù)壓縮等方面有廣泛應(yīng)用,能一起確保存儲(chǔ)空間和速度最優(yōu)化(而不用空間換時(shí)刻)。

運(yùn)用 Redis 的 BitMaps 做為用戶登錄記載核算,不只核算速度極快,而且內(nèi)存占用極低。

Redis 支撐 HyperLogLog 算法

Redis HyperLogLog是一種運(yùn)用隨機(jī)化的算法,以少數(shù)內(nèi)存供給調(diào)集中僅有元素?cái)?shù)量的近似值。

HyperLogLog 能夠承受多個(gè)元素作為輸入,并給出輸入元素的基數(shù)預(yù)算值:
HyperLogLog 的長(zhǎng)處是,即便輸入元素的數(shù)量或許體積十分十分大,核算基數(shù)所需的空間總是固定的、而且是很小的。

在 Redis 里邊,每個(gè) HyperLogLog 鍵只需求花費(fèi) 12 KB 內(nèi)存,就能夠核算挨近 2^64 個(gè)不同元素的基數(shù)。這和核算基數(shù)時(shí),元素越多消耗內(nèi)存就越多的調(diào)集構(gòu)成鮮明對(duì)比。運(yùn)用 HyperLogLog 算法,我們能夠垂手可得的完成 IP 核算等對(duì)數(shù)據(jù)容許少許差錯(cuò)的核算功用。

基數(shù):調(diào)集中不同元素的數(shù)量。比方 {‘apple’, ‘banana’, ‘cherry’, ‘banana’, ‘apple’} 的基數(shù)就是3。

預(yù)算值:算法給出的基數(shù)并不是準(zhǔn)確的,可能會(huì)比實(shí)踐略微多一些或許略微少一些,但會(huì)控制在合理的規(guī)模之內(nèi)。

Redis 支撐 Geo 功用

我們能夠運(yùn)用根據(jù) Redis 來完成地理位置相關(guān)辦理,鄰近的人、兩地理位置間間隔核算等功用變得極為簡(jiǎn)略完成。

簡(jiǎn)略音訊行列

Redis 列表 + 發(fā)布/訂閱功用能夠很便利的完成一個(gè)簡(jiǎn)略的音訊行列,將音訊存入 Redis 列表中,經(jīng)過 發(fā)布/訂閱功用告訴指定成員,成員獲取到告訴后能夠根據(jù)告訴內(nèi)容進(jìn)行對(duì)應(yīng)處理。

全文檢索

Redis 官方團(tuán)隊(duì)開發(fā)了 RediSearch 模塊,能夠完成運(yùn)用 Redis 來做全文檢索的功用。

分布式僅有ID

Redis 的規(guī)劃使其能夠防止并發(fā)的多種問題,使其指令都是原子履行,這些特性都天然生成匹配分布式僅有ID生成器的要求。

而且經(jīng)過與 Lua 腳本的結(jié)合運(yùn)用更是能生成雜亂的有某些規(guī)則的僅有ID。

部分代碼完成
下面我們以 Java代碼作為演示(編程言語完成辦法原理相似僅僅詳細(xì)完成辦法有少許不同罷了)解說幾個(gè)功用的完成:

Session 同享

原理:將不同 Web 效勞器的 Session 信息一致存儲(chǔ)在 Redis 中,而且獲取 Session 也是從 Redis 中獲取

完成辦法:

辦法一:根據(jù) Tomcat 完成 Sessioin 同享:

Tomcat 裝備過程(相關(guān)代碼資源能夠從https://gitee.com/coderknock/Tomcat-Redis-Session-Manager-Demo 獲?。?/span>
將 commons-pool2-2.4.2.jar、jedis-2.9.0.jar、commons-pool2-2.4.2.jar 三個(gè) jar 包放到 Tomcat 下的 lib 目錄下(留意:不是項(xiàng)目的 lib 目錄)。

修正 Tomcat conf 下 context.xml:

   XML
   
       ......
        
       
            host="127.0.0.1"  
           port="6379"  
           database="0"  
           maxInactiveInterval="60"
           password="admin123" />
         ......
   
辦法二:根據(jù) Fileter 、 自行完成 HttpServletRequestWrapper 、 HttpSession :

要害代碼:

HttpSessionWrapper.java

java
   import com.alibaba.fastjson.JSON;
   import com.alibaba.fastjson.JSONException;
   import com.coderknock.jedis.executor.JedisExecutor;
   import com.coderknock.pojo.User;
   import org.apache.commons.lang3.StringUtils;
   import org.apache.logging.log4j.LogManager;
   import org.apache.logging.log4j.Logger;

   import javax.servlet.ServletContext;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import javax.servlet.http.HttpSession;
   import javax.servlet.http.HttpSessionContext;
   import java.util.Enumeration;

   /**
    * 
    *
    * @author 三產(chǎn)
    * @version 1.0
    * @date 2017-08-26
    * @QQGroup 213732117
    * @website http://www.coderknock.com
    * @copyright Copyright 2017 拿客 coderknock.com  All rights reserved.
    * @since JDK 1.8
    */
   public class HttpSessionWrapper implements HttpSession {
       protected final Logger logger = LogManager.getLogger(HttpSessionWrapper.class);
       private String sid = "";
       private HttpServletRequest request;
       private HttpServletResponse response;
       private final long creationTime = System.currentTimeMillis();
       private final long lastAccessedTime = System.currentTimeMillis();
       //過期時(shí)刻單位秒
       private int expire_time = 60;

       public HttpSessionWrapper() {
       }

       public HttpSessionWrapper(String sid, HttpServletRequest request,
                                 HttpServletResponse response) {
           this.sid = sid;
           this.request = request;
           this.response = response;
       }

       public Object getAttribute(String name) {
           logger.info(getClass() + "getAttribute(),name:" + name);
           try {
               Object obj = JedisExecutor.execute(jedis -> {
                   String jsonStr = jedis.get(sid + ":" + name);
                   if (jsonStr != null || StringUtils.isNotEmpty(jsonStr)) {
                       jedis.expire(sid + ":" + name, expire_time);// 重置過期時(shí)刻
                   }
                   return jsonStr;
               });
               return obj;
           } catch (JSONException je) {
               logger.error(je);
           } catch (Exception e) {
               logger.error(e.getMessage());
           }
           return null;
       }

       public void setAttribute(String name, Object value) {
           logger.info(getClass() + "setAttribute(),name:" + name);
           try {
               JedisExecutor.executeNR(jedis -> {
                   if (value instanceof String) {
                       String value_ = (String) value;
                       jedis.set(sid + ":" + name, value_);//一般字符串目標(biāo)
                   } else {
                       jedis.set(sid + ":" + name, JSON.toJSONString(value));//序列化目標(biāo)
                   }

                   jedis.expire(sid + ":" + name, expire_time);// 重置過期時(shí)刻
               });
           } catch (Exception e) {
               logger.error(e);
           }

       }


       public void removeAttribute(String name) {
           logger.info(getClass() + "removeAttribute(),name:" + name);
           if (StringUtils.isNotEmpty(name)) {
               try {
                   JedisExecutor.executeNR(jedis -> {
                       jedis.del(sid + ":" + name);
                   });
               } catch (Exception e) {
                   logger.error(e);
               }
           }

       }
       //...... 省掉部分代碼
   }
SessionFilter.java

java
   import com.coderknock.wrapper.DefinedHttpServletRequestWrapper;
   import org.apache.commons.lang3.StringUtils;
   import org.apache.logging.log4j.LogManager;
   import org.apache.logging.log4j.Logger;

   import javax.servlet.*;
   import javax.servlet.http.Cookie;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import java.io.IOException;
   import java.util.UUID;

   /**

    * 

    *

    * @author 三產(chǎn)

    * @version 1.0

    * @date 2017-08-26

    * @QQGroup 213732117

    * @website http://www.coderknock.com

    * @copyright Copyright 2017 拿客 coderknock.com  All rights reserved.

    * @since JDK 1.8

    */
   public class SessionFilter implements Filter {
       protected final Logger logger = LogManager.getLogger(getClass());
       private static final String host = "host";
       private static final String port = "port";
       private static final String seconds = "seconds";

       public void init(FilterConfig filterConfig) throws ServletException {
           logger.debug("init filterConfig info");
       }

       public void doFilter(ServletRequest request, ServletResponse response,
                            FilterChain chain) throws IOException, ServletException {
           //從cookie中獲取sessionId,如果此次懇求沒有sessionId,重寫為這次懇求設(shè)置一個(gè)sessionId

           HttpServletRequest httpRequest = (HttpServletRequest) request;
           HttpServletResponse httpResponse = (HttpServletResponse) response;
           String sid = null;
           if (httpRequest.getCookies() != null) {
               for (Cookie cookie : httpRequest.getCookies()) {
                   if (cookie.getName().equals("JSESSIONID")) {
                       sid = cookie.getValue();
                       break;
                   }
               }
           }
           if (StringUtils.isEmpty(sid)) {
               try {
                   Cookie cookie = new Cookie("JSESSIONID", httpRequest.getLocalAddr() + ":" + request.getLocalPort() + ":" + UUID.randomUUID().toString().replaceAll("-", ""));
                   httpResponse.addCookie(cookie);
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }

           logger.info("JSESSIONID:" + sid);
           chain.doFilter(new DefinedHttpServletRequestWrapper(sid, httpRequest, httpResponse), response);
       }

       public void destroy() {
       }

   }
排行榜

原理:經(jīng)過 Redis 有序調(diào)集能夠很快捷的完成該功用

要害指令:

ZADD key [NX|XX][CH][INCR] score member [score member ...]: 初始化排行榜中成員及其分?jǐn)?shù)。

ZINCRBY key increment member:為某個(gè)成員添加分?jǐn)?shù),如果該成員不存在則會(huì)添加該成員并設(shè)定分?jǐn)?shù)為 increment 。

ZUNIONSTORE destination numkeys key [key ...][WEIGHTS weight [weight ...]][AGGREGATE SUM|MIN|MAX]: 能夠兼并多個(gè)排行榜,該操作會(huì)將幾個(gè)調(diào)集的并集存儲(chǔ)到 destination 中,其間各個(gè)調(diào)集相同成員分?jǐn)?shù)會(huì)疊加或許取最大、最小、平均值等(根據(jù) [AGGREGATE SUM|MIN|MAX] 參數(shù)決議,默許是疊加),然后能夠完成根據(jù)多個(gè)分排行榜來核算總榜排行的功用。

ZREVRANGE key start stop [WITHSCORES]:該指令就是最要害的獲取排行信息的指令,能夠獲取從高到低的成員。

Redis 指令演示(“#”之后為闡明):

   # 1、存儲(chǔ)幾個(gè)排行榜成員數(shù)據(jù)(這兒能夠理解為把自己體系已有數(shù)據(jù)加載到 Redis 中)
   ZADD testTop 23 member1 25 member2
   # 2、添加某個(gè)人的分?jǐn)?shù)(這兒的分?jǐn)?shù)就是排行的根據(jù)能夠是浮點(diǎn)類型)
   ZINCRBY  testTop 20 member1   # 此刻 testTop 中 member1 的分?jǐn)?shù)就編程了 43
   ZINCRBY  testTop -10 member2  # 此刻 testTop 中 member2 的分?jǐn)?shù)就編程了 15
   ZINCRBY  testTop 20 member3   # 此刻向 testTop 中添加了 member3 成員,分?jǐn)?shù)為 20
   # 3、查詢排行榜前兩名,而且查詢出其分?jǐn)?shù)【W(wǎng)ITHSCORES 選項(xiàng)用于顯現(xiàn)分?jǐn)?shù),不帶該參數(shù)則只會(huì)查出成員稱號(hào)】
   ZREVRANGE testTop 0 1 WITHSCORES
   #成果:
   # 1) "member1"
   # 2) "43"
   # 3) "member3"
   # 4) "20"
   # 假定此刻還有一個(gè) 排行榜
   ZADD testTop2  100 member2 200 member3 123 member4
   # 將 testTop testTop2 組成一個(gè)總榜 top
   ZUNIONSTORE  top 2 testTop testTop2
   # 查詢總榜一切成員排行狀況
   ZREVRANGE top 0 -1 WITHSCORES
   1) "member3"
   2) "220"
   3) "member4"
   4) "123"
   5) "member2"
   6) "115"
   7) "member1"
   8) "43"


免费视频观无码一区,国内精品一区二区无码,99精品无码视频在线播放,ā片国产在线播放