redisによるページキャッシュの実装


本文は<>一書第二章の読書ノート
キャッシュするのは次のurlのような形ですhttp://test.com/shwoItem?item=itemX

せっけい案

最初のドメイン、zsetタイプの------keyはviewed:userSessionid
保管されているのは、商品idとユーザーがこの商品を表示するときのtimestampです.
2番目のドメインは、zsetタイプの------viewedであってもよい.
メンバーは商品id(グローバル範囲内)、scoreは商品がユーザ(グローバル範囲内)に閲覧された回数(負数)である
3番目のドメイン、hashタイプの------keyはitem:itemIdです
商品情報をお預かりしております

ユーザーが商品を確認

	public void viewItem(Jedis conn, String token, String user, String item) {
		long timestamp = System.currentTimeMillis() / 1000;


		if (item != null) {
		        //  user          
			conn.zadd("viewed:" + token, timestamp, item);
			//          25   
			conn.zremrangeByRank("viewed:" + token, 0, -26);
			//  set  score        
			conn.zincrby("viewed:", -1, item); //-1  1?
		}
	}

このページをキャッシュしてみます

まずurlがキャッシュできるかどうかを判断します
	/**
	 *   request              false
	 *                      false
	 *                  10000            false
	 *                 10000             true
	 * 
	 * @param conn
	 * @param request
	 * @return
	 */
	public boolean canCache(Jedis conn, String request) {
		//   http://test.com/shwoItem?item=itemX
		//         paramter        
		Map params = getParams(request);
		if (params == null) 
			return false;
		
		//  itemX    
		String itemId = extractItemId(params);
		//params.containsKey("_")         
		//             
		if (itemId == null || params.containsKey("_")) {
			return false;
		}
		// viewed:                  
		Long rank = conn.zrank("viewed:", itemId);
		//               10000 
		//  rank==null            
		return rank != null && rank < 10000;


	}

キャッシュリクエストの実装

public String cacheRequest(Jedis conn, String request, Callback callback) {
		if (!canCache(conn, request)) {
			return callback != null ? callback.call(request) : null;
		}


		String pageKey = "cache:" + hashRequest(request);
		//                                
		String content = conn.get(pageKey);  


		if (content == null && callback != null) {
			content = callback.call(request);
			//        content  html
			//           5  
			conn.setex(pageKey, 300, content);
		}


		return content;
	}
から入力されたcallbackは次のとおりです.
		Callback callback = new Callback() {
			public String call(String request) {
				return "content for " + request;
			}
		};

テストコードを見てみましょう

package redisinaction;


import org.junit.BeforeClass;
import org.junit.Test;


import redis.clients.jedis.Jedis;
import redisinaction.Chapter02.Callback;


/**   
 * This class is used for ...   
 * @author  dlf([email protected])
 * @version 1.0, 2016 10 18    9:34:27   
 */
public class Chapter02Test {
	
	
	static Jedis conn = null;
	static Chapter02 ch2=null;
	
	@BeforeClass        
	public static void initConn(){
		System.out.println("test before");
		ch2=new Chapter02();		
		conn = new Jedis("10.150.0.80");
		conn.auth("dlf123123");
	}	 
	
	@Test
	public void testCacheRequest() {
		
		Callback callback = new Callback() {
			public String call(String request) {
				return "content for " + request;
			}
		};
		//   viewItem         cacheRequest      
		//   ?    
		ch2.viewItem(conn, "dlf_session_id", "dlf", "itemX");


		String url = "http://test.com/?item=itemX";
		String result = ch2.cacheRequest(conn, url, callback);
		System.out.println( result);
		
		String result3 = ch2.cacheRequest(conn, url, null);
		System.out.println(result3);
		
		String result4 = ch2.cacheRequest(conn, url, null);
		System.out.println(result4);
	}
}

グローバル範囲でユーザーに最も多く表示されたn件の製品(前章の文章と並べ替えられたものは多くない)
    private static final int ARTICLES_PER_PAGE = 25;
    public List>  getMostPopulate(Jedis conn, int page) {
    	int start = (page - 1) * ARTICLES_PER_PAGE;
        int end = start + ARTICLES_PER_PAGE - 1;
        Set ids = conn.zrevrange("viewed:", start, end);
        
        
        List> items = new ArrayList>();
        for (String id : ids){
            Map itemData = conn.hgetAll(id);
            itemData.put("id", id);
            items.add(itemData);
        }
        return items;
    }

viewItemでは、すべての商品の閲覧回数(負数)を記録しています
conn.zincrby("viewed:", -1, item);
では、n日後になると、このviewedのデータ項目が多くなり、すべての商品の閲覧回数を常に保存する必要はありません.
だから
public class RescaleViewedThread implements  Runnable{
		private Jedis conn;
		private boolean quit;


		public RescaleViewedThread(int limit) {			
			conn = new Jedis("10.150.0.80");
	        conn.auth("dlf123123");
		}
		public void shutDown(){
			quit=true;
		}
		
		@Override
		public void run() {
			while (!quit) {
				try {
					//    20000         
					conn.zremrangeByRank("viewed:", 0, -20001);
					//              
					conn.zinterstore("viewed","viewed:0.5");
					Thread.sleep(300);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			
		}
		
	}
システムが起動すると、このスレッドはずっと実行されます.
では、どうすればいいのでしょうか.どうやって私のプロジェクトに統合しますか?私のプロジェクトはstruts 2を使って開発されました.
お兄さん、遮断器というものがあるのを知らないのですか.interceptor?
これを見てください.http://www.2cto.com/kf/201506/408009.html
これはspringmvcですか?strutsはどうやって使いますか?
ばかだ!
struts 2のブロッキングでrequestとresponseを手に入れないの?