码迷,mamicode.com
首页 > 其他好文 > 详细

【转载】redis优化

时间:2018-02-28 23:05:42      阅读:1894      评论:0      收藏:0      [点我收藏+]

标签:toe   ring   socket   current   实现   sync   进入   cal   template   

原文链接

批量操作优化:

  • 在使用redis的时候,客户端通过socket向redis服务端发起请求后,等待服务端的返回结果。
  • 客户端请求服务器一次就发送一个报文 -> 等待服务端的返回 -> 关闭连接
  • 如果是100个请求、1000个请求,那就得请求100次、1000次
  • 所以使用多个请求的时候使用管道来操作(如果管道打包的命令太多占用的内存也会越大,适量)
  • 以下是使用3种方式进行的测试(循环写入1000次):

    public static void main(String[] args) {
    
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            template.opsForHash().put("user1", "status" + i, "value" + i);
        }
        System.out.println(System.currentTimeMillis() - start);
    
        start = System.currentTimeMillis();
        final byte[] rawKey = rawKey("user2");
        template.execute(new RedisCallback<Object>() {
    
            @Override
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                for (int i = 0; i < 1000; i++) {
                    final byte[] rawHashKey = rawHashKey("status" + i);
                    final byte[] rawHashValue = rawHashValue("value" + i);
    
                    connection.hSet(rawKey, rawHashKey, rawHashValue);
                }
                return null;
            }
        });
        System.out.println(System.currentTimeMillis() - start);
    
        start = System.currentTimeMillis();
        final byte[] rawKey2 = rawKey("user3");
        template.execute(new RedisCallback<Object>() {
    
            @Override
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                connection.openPipeline();
                for (int i = 0; i < 1000; i++) {
                    final byte[] rawHashKey = rawHashKey("status" + i);
                    final byte[] rawHashValue = rawHashValue("value" + i);
    
                    connection.hSet(rawKey2, rawHashKey, rawHashValue);
                }
                return connection.closePipeline();
            }
        });
        System.out.println(System.currentTimeMillis() - start);
    }
  • 请求结果

    20:54:51.653 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Opening RedisConnection
    20:54:51.693 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Closing Redis Connection
    42283
    20:54:51.695 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Opening RedisConnection
    20:55:33.922 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Closing Redis Connection
    42228
    20:55:33.923 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Opening RedisConnection
    20:55:34.058 [main] DEBUG o.s.d.r.core.RedisConnectionUtils - Closing Redis Connection
    136
  • 可以看出在使用管道打包发送请求所用的时间不到1s。而发送1000次请求所用的时间达到了42s。

从请求结果看到多次 Opening RedisConnection 和 Closing Redis Connection 的日志.

阅读源代码我们可以发现我们对redis的所有操作都是通过回调execute函数执行的,其代码如下:

public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {  
    return execute(action, exposeConnection, false);  
}  
// execute实现如下:  
// org.springframework.data.redis.core.RedisTemplate<K, V> --- 最终实现  
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {  
    Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");  
    Assert.notNull(action, "Callback object must not be null");  
    RedisConnectionFactory factory = getConnectionFactory();  
    RedisConnection conn = null;  
    try {  
        if (enableTransactionSupport) {  
            // only bind resources in case of potential transaction synchronization  
            conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);  
        } else {  
            conn = RedisConnectionUtils.getConnection(factory);  
        }  
        boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);  
        RedisConnection connToUse = preProcessConnection(conn, existingConnection);  
        boolean pipelineStatus = connToUse.isPipelined();  
        if (pipeline && !pipelineStatus) {  
            connToUse.openPipeline();  
        }  
        RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));  
        T result = action.doInRedis(connToExpose);  
        // close pipeline  
        if (pipeline && !pipelineStatus) {  
            connToUse.closePipeline();  
        }  
        // TODO: any other connection processing?  
        return postProcessResult(result, connToUse, existingConnection);  
    } finally {  
        if (!enableTransactionSupport) {  
            RedisConnectionUtils.releaseConnection(conn, factory);  
        }  
    }  
}  

这里面每次执行action.doInRedis(connToExpose)前都要调用RedisConnectionUtils.getConnection(factory);获得一个连接,进入RedisConnnectionUtils类中,getConnection(factory)最终调用的是doGetConnection(factory, true, false, enableTranactionSupport)这个函数。这个函数我们可以看下api文档,发现实际上并不是真的创建一个新的redis连接,它只是在connectFactory中获取一个连接,也就是从连接池中取出一个连接。当然如果connectFactory没有连接可用,此时如果allowCreate=true便会创建出一个新的连接,并且加入到connectFactory中。

基本上可以确定真实的情况是spring-data-redis已经帮我们封装了连接池管理,我们只需要调用一系列操作函数即可,这给操作redis带来了极大的方便。

【转载】redis优化

标签:toe   ring   socket   current   实现   sync   进入   cal   template   

原文地址:https://www.cnblogs.com/mr-yang-localhost/p/8461289.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!