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

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

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

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

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

負載均衡

分布式

集群化

緩存

限流處理

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

其他

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

同一個用戶的懇求會轉發(fā)至不同的 Web 效勞器,然后導致 Session 丟掉等問題。

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

分布式僅有 ID 問題。

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

用戶登錄記載核算

實時的排行榜

原子計數(shù)

最新談論

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

裝備中心能夠運用 Zookpeer、Redis 等完成。

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

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

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

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

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

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

Redis 指令語法簡略,極易把握。

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

Redis 開放源碼,我們能夠對其進行二次開發(fā)來定制優(yōu)化。

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

Redis 有較好的主從復制、集群相關支撐。

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

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

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

分布式鎖

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

緩存

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

Lua 腳本

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

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

Redis 支撐 BitMaps

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

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

Redis 支撐 HyperLogLog 算法

Redis HyperLogLog是一種運用隨機化的算法,以少數(shù)內存供給調集中僅有元素數(shù)量的近似值。

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

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

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

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

Redis 支撐 Geo 功用

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

簡略音訊行列

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

全文檢索

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

分布式僅有ID

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

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

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

Session 同享

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

完成辦法:

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

Tomcat 裝備過程(相關代碼資源能夠從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 三個 jar 包放到 Tomcat 下的 lib 目錄下(留意:不是項目的 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();
       //過期時刻單位秒
       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);// 重置過期時刻
                   }
                   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_);//一般字符串目標
                   } else {
                       jedis.set(sid + ":" + name, JSON.toJSONString(value));//序列化目標
                   }

                   jedis.expire(sid + ":" + name, expire_time);// 重置過期時刻
               });
           } 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,重寫為這次懇求設置一個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 有序調集能夠很快捷的完成該功用

要害指令:

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

ZINCRBY key increment member:為某個成員添加分數(shù),如果該成員不存在則會添加該成員并設定分數(shù)為 increment 。

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

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

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

   # 1、存儲幾個排行榜成員數(shù)據(jù)(這兒能夠理解為把自己體系已有數(shù)據(jù)加載到 Redis 中)
   ZADD testTop 23 member1 25 member2
   # 2、添加某個人的分數(shù)(這兒的分數(shù)就是排行的根據(jù)能夠是浮點類型)
   ZINCRBY  testTop 20 member1   # 此刻 testTop 中 member1 的分數(shù)就編程了 43
   ZINCRBY  testTop -10 member2  # 此刻 testTop 中 member2 的分數(shù)就編程了 15
   ZINCRBY  testTop 20 member3   # 此刻向 testTop 中添加了 member3 成員,分數(shù)為 20
   # 3、查詢排行榜前兩名,而且查詢出其分數(shù)【W(wǎng)ITHSCORES 選項用于顯現(xiàn)分數(shù),不帶該參數(shù)則只會查出成員稱號】
   ZREVRANGE testTop 0 1 WITHSCORES
   #成果:
   # 1) "member1"
   # 2) "43"
   # 3) "member3"
   # 4) "20"
   # 假定此刻還有一個 排行榜
   ZADD testTop2  100 member2 200 member3 123 member4
   # 將 testTop testTop2 組成一個總榜 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精品无码视频在线播放,ā片国产在线播放