dubbo 结果缓存


dubbo 结果缓存

           

官网:https://dubbo.apache.org/zh/docs/advanced/result-cache/

                

               

                                     

结果缓存

           

应用:加速热门数据访问速度,避免额外加缓存的工作量(如redis缓存)

           

配置

# 接口级别缓存
<dubbo:reference interface="com.foo.BarService" cache="lru" />

# 方法级别缓存
<dubbo:reference interface="com.foo.BarService">
    <dubbo:method name="findBar" cache="lru" />
</dubbo:reference>


# cache可选值:
lru:默认每个线程存储1000个缓存,缓存满后,删除最长时间没有使用的缓存
lfu:默认每个线程存储1000个缓存,缓存满后,删除一段时间使用次数最少的缓存
threadlocal:threadlocal使用jvm内存存储缓存,无过期和删除策略,应该给jvm设置合适的内存避免内存溢出
jcache:与jsr107集成,使用jcache在内存中存储缓存
expiring:使用map在内存中存储缓存,设置过期时间,默认为180s,每隔10s检查一次缓存是否过期

             

CacheFactory:默认为lru缓存

@SPI("lru")
public interface CacheFactory {

    /**
     * CacheFactory implementation class needs to implement this return underlying cache instance for method against
     * url and invocation.
     * @param url
     * @param invocation
     * @return Instance of Cache containing cached value against method url and invocation.
     */
    @Adaptive("cache")
    Cache getCache(URL url, Invocation invocation);

}

              

             

META-INF/dubbo/internal/org.apache.dubbo.cache.CacheFactory

threadlocal=org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory
lru=org.apache.dubbo.cache.support.lru.LruCacheFactory
jcache=org.apache.dubbo.cache.support.jcache.JCacheFactory
expiring=org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory
lfu=org.apache.dubbo.cache.support.lfu.LfuCacheFactory

                          

LruCacheFactory

public class LruCacheFactory extends AbstractCacheFactory {

    /**
     * Takes url as an method argument and return new instance of cache store implemented by LruCache.
     * @param url url of the method
     * @return ThreadLocalCache instance of cache
     */
    @Override
    protected Cache createCache(URL url) {
        return new LruCache(url);
    }   //创建LruCache

}

            

LruCache

/**
 * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
 * with value <b>lru</b>, dubbo initialize the instance of this class using {@link LruCacheFactory} to store method's returns value
 * to server from store without making method call.
   //为每个线程存储缓存,service、method、consumer、provider需要配置cache=lru
   //如果缓存了值,就可使用缓存里面的数据,不触发方法调用

 * <pre>
 *     e.g. 1) &lt;dubbo:service cache="lru" cache.size="5000"/&gt;
 *          2) &lt;dubbo:consumer cache="lru" /&gt;
 * </pre>
 * <pre>
 * LruCache uses url's <b>cache.size</b> value for its max store size, if nothing is provided then
 * default value will be 1000
 * </pre>  //cache.size配置缓存个数,默认1000
 *
 * @see Cache
 * @see LruCacheFactory
 * @see org.apache.dubbo.cache.support.AbstractCacheFactory
 * @see org.apache.dubbo.cache.filter.CacheFilter
 */
public class LruCache implements Cache {

    /**
     * This is used to store cache records
     */
    private final Map<Object, Object> store;

    /**
     * Initialize LruCache, it uses constructor argument <b>cache.size</b> value as its storage max size.
     *  If nothing is provided then it will use 1000 as default value.
     * @param url A valid URL instance
     */
    public LruCache(URL url) {
        final int max = url.getParameter("cache.size", 1000);
        this.store = new LRUCache<>(max);
    }

    /**
     * API to store value against a key in the calling thread scope.
     * @param key  Unique identifier for the object being store.
     * @param value Value getting store
     */
    @Override
    public void put(Object key, Object value) {
        store.put(key, value);
    }

    /**
     * API to return stored value using a key against the calling thread specific store.
     * @param key Unique identifier for cache lookup
     * @return Return stored object against key
     */
    @Override
    public Object get(Object key) {
        return store.get(key);
    }

}

              

                  

LfuCacheFactory

public class LfuCacheFactory extends AbstractCacheFactory {

    /**
     * Takes url as an method argument and return new instance of cache store implemented by LfuCache.
     * @param url url of the method
     * @return ThreadLocalCache instance of cache
     */
    @Override
    protected Cache createCache(URL url) {
        return new LfuCache(url);
    }   //创建LfuCache缓存

}

           

LfuCache

/**
 * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
 * with value <b>lfu</b>, dubbo initialize the instance of this class using {@link LfuCacheFactory} to store method's returns value
 * to server from store without making method call.
   //为每个线程存储缓存,如果service、method、consumer、provider配置cache=lfu
   //如果缓存命中,就不会触发方法调用,直接返回缓存值

 * <pre>
 *     e.g. 1) &lt;dubbo:service cache="lfu" cache.size="5000" cache.evictionFactor="0.3"/&gt;
 *          2) &lt;dubbo:consumer cache="lfu" /&gt;
 * </pre>
 * <pre>
 * LfuCache uses url's <b>cache.size</b> value for its max store size, url's <b>cache.evictionFactor</b> value for its eviction factor,
 * default store size value will be 1000, default eviction factor will be 0.3
 * </pre>  //可用cache.size设置缓存个数,默认1000
 *
 * @see Cache
 * @see LfuCacheFactory
 * @see org.apache.dubbo.cache.support.AbstractCacheFactory
 * @see org.apache.dubbo.cache.filter.CacheFilter
 */
public class LfuCache implements Cache {

    /**
     * This is used to store cache records
     */
    private final LFUCache store;

    /**
     *  Initialize LfuCache, it uses constructor argument <b>cache.size</b> value as its storage max size.
     *  If nothing is provided then it will use 1000 as default size value. <b>cache.evictionFactor</b> value as its eviction factor.
     *  If nothing is provided then it will use 0.3 as default value.
     * @param url A valid URL instance
     */
    public LfuCache (URL url) {
        final int max = url.getParameter("cache.size", 1000);
        final float factor = url.getParameter("cache.evictionFactor", 0.75f);
        this.store = new LFUCache(max, factor);
    }

    /**
     * API to store value against a key in the calling thread scope.
     * @param key  Unique identifier for the object being store.
     * @param value Value getting store
     */
    @Override
    public void put(Object key, Object value) {
        store.put(key, value);
    }

    /**
     * API to return stored value using a key against the calling thread specific store.
     * @param key Unique identifier for cache lookup
     * @return Return stored object against key
     */
    @Override
    public Object get(Object key) {
        return store.get(key);
    }

}

           

             

JCacheFactory

/**
 * JCacheFactory is factory class to provide instance of javax spi cache.Implement {@link org.apache.dubbo.cache.CacheFactory} by
 * extending {@link AbstractCacheFactory} and provide
 * @see AbstractCacheFactory
 * @see JCache
 * @see org.apache.dubbo.cache.filter.CacheFilter
 * @see Cache
 * @see CachingProvider
 * @see javax.cache.Cache
 * @see javax.cache.CacheManager
 */
public class JCacheFactory extends AbstractCacheFactory {

    /**
     * Takes url as an method argument and return new instance of cache store implemented by JCache.
     * @param url url of the method
     * @return JCache instance of cache
     */
    @Override
    protected Cache createCache(URL url) {
        return new JCache(url);
    }

}

           

JCache

/**
 * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
 * with value <b>jcache</b>, dubbo initialize the instance of this class using {@link JCacheFactory} to store method's returns value
 * to server from store without making method call.
 *
 * @see Cache
 * @see JCacheFactory
 * @see org.apache.dubbo.cache.support.AbstractCacheFactory
 * @see org.apache.dubbo.cache.filter.CacheFilter
 */
public class JCache implements org.apache.dubbo.cache.Cache {

    private final Cache<Object, Object> store;

    public JCache(URL url) {
        String method = url.getParameter(METHOD_KEY, "");
        String key = url.getAddress() + "." + url.getServiceKey() + "." + method;
        // jcache parameter is the full-qualified class name of SPI implementation
        String type = url.getParameter("jcache");

        CachingProvider provider = StringUtils.isEmpty(type) ? Caching.getCachingProvider() : Caching.getCachingProvider(type);
        CacheManager cacheManager = provider.getCacheManager();
        Cache<Object, Object> cache = cacheManager.getCache(key);
        if (cache == null) {
            try {
                //configure the cache
                MutableConfiguration config =
                        new MutableConfiguration<>()
                                .setTypes(Object.class, Object.class)
                                .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MILLISECONDS, url.getMethodParameter(method, "cache.write.expire", 60 * 1000))))
                                .setStoreByValue(false)
                                .setManagementEnabled(true)
                                .setStatisticsEnabled(true);
                cache = cacheManager.createCache(key, config);
            } catch (CacheException e) {
                // concurrent cache initialization
                cache = cacheManager.getCache(key);
            }
        }

        this.store = cache;
    }

    @Override
    public void put(Object key, Object value) {
        store.put(key, value);
    }

    @Override
    public Object get(Object key) {
        return store.get(key);
    }

}

           

             

ExpiringCacheFactory

public class ExpiringCacheFactory extends AbstractCacheFactory {

    /**
     * Takes url as an method argument and return new instance of cache store implemented by JCache.
     * @param url url of the method
     * @return ExpiringCache instance of cache
     */
    @Override
    protected Cache createCache(URL url) {
        return new ExpiringCache(url);
    }   //创建ExpiringCache
}

            

ExpiringCache

/**
 * This class store the cache value with the characteristic of expiration time. If a service,method,consumer or provided is configured with key <b>cache</b>
 * with value <b>expiring</b>, dubbo initialize the instance of this class using {@link ExpiringCacheFactory} to store method's returns value
 * to server from store without making method call.
 * <pre>
 *     e.g. 1) &lt;dubbo:service cache="expiring" cache.seconds="60" cache.interval="10"/&gt;
 *          2) &lt;dubbo:consumer cache="expiring" /&gt;
 * </pre>
   //使用cache="expiring"配置expiring缓存

 * <li>It used constructor argument url instance <b>cache.seconds</b> value to decide time to live of cached object.Default value of it is 180 second.</li>
 * <li>It used constructor argument url instance <b>cache.interval</b> value for cache value expiration interval.Default value of this is 4 second</li>
      //cache.seconds:缓存过期时间,默认180s
      //cache.interval:缓存过期时间检查间隔,默认为4s

 * @see Cache
 * @see ExpiringCacheFactory
 * @see org.apache.dubbo.cache.support.AbstractCacheFactory
 * @see org.apache.dubbo.cache.filter.CacheFilter
 */
public class ExpiringCache implements Cache {
    private final Map<Object, Object> store;    //使用map存储缓存

    public ExpiringCache(URL url) {
        // cache time (second)
        final int secondsToLive = url.getParameter("cache.seconds", 180);
        // Cache check interval (second)
        final int intervalSeconds = url.getParameter("cache.interval", 4);
        ExpiringMap<Object, Object> expiringMap = new ExpiringMap<>(secondsToLive, intervalSeconds);
        expiringMap.getExpireThread().startExpiryIfNotStarted();
        this.store = expiringMap;
    }

    /**
     * API to store value against a key in the calling thread scope.
     * @param key  Unique identifier for the object being store.
     * @param value Value getting store
     */
    @Override
    public void put(Object key, Object value) {
        store.put(key, value);
    }

    /**
     * API to return stored value using a key against the calling thread specific store.
     * @param key Unique identifier for cache lookup
     * @return Return stored object against key
     */

    @Override
    public Object get(Object key) {
        return store.get(key);
    }

}

             

              

ThreadLocalCacheFactory

public class ThreadLocalCacheFactory extends AbstractCacheFactory {

    /**
     * Takes url as an method argument and return new instance of cache store implemented by ThreadLocalCache.
     * @param url url of the method
     * @return ThreadLocalCache instance of cache
     */
    @Override
    protected Cache createCache(URL url) {
        return new ThreadLocalCache(url);
    }   //创建ThreadLocalCache

}

          

ThreadLocalCache

/**
 * This class store the cache value per thread. If a service,method,consumer or provided is configured with key <b>cache</b>
 * with value <b>threadlocal</b>, dubbo initialize the instance of this class using {@link ThreadLocalCacheFactory} to store method's returns value
 * to server from store without making method call.
 *  <pre>
 *      e.g. &lt;dubbo:service cache="threadlocal" /&gt;
 *  </pre>  //使用cache="threadlocal"配置使用threadlocal缓存

 * <pre>
 * As this ThreadLocalCache stores key-value in memory without any expiry or delete support per thread wise, if number threads and number of key-value are high then jvm should be
 * configured with appropriate memory.
 * </pre>
   //threadlocal在内存中存储缓存,没有过期和删除策略,
   //如果线程数很大、或者缓存数据很多,应该设置一个合适的jvm内存

 *
 * @see org.apache.dubbo.cache.support.AbstractCacheFactory
 * @see org.apache.dubbo.cache.filter.CacheFilter
 * @see Cache
 */
public class ThreadLocalCache implements Cache {

    /**
     * Thread local variable to store cached data.
     */
    private final ThreadLocal<Map<Object, Object>> store;  //每个线程使用map存储缓存

    /**
     * Taken URL as an argument to create an instance of ThreadLocalCache. In this version of implementation constructor
     * argument is not getting used in the scope of this class.
     * @param url
     */
    public ThreadLocalCache(URL url) {
        this.store = ThreadLocal.withInitial(HashMap::new);
    }

    /**
     * API to store value against a key in the calling thread scope.
     * @param key  Unique identifier for the object being store.
     * @param value Value getting store
     */
    @Override
    public void put(Object key, Object value) {
        store.get().put(key, value);
    }

    /**
     * API to return stored value using a key against the calling thread specific store.
     * @param key Unique identifier for cache lookup
     * @return Return stored object against key
     */
    @Override
    public Object get(Object key) {
        return store.get().get(key);
    }

}

            

                   

                                     

实现原理

      

CacheFilter:服务端、消费端均可设置缓存

@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
public class CacheFilter implements Filter {

    private CacheFactory cacheFactory;

    /**
     * Dubbo will populate and set the cache factory instance based on service/method/consumer/provider configured
     * cache attribute value. Dubbo will search for the class name implementing configured <b>cache</b> in file org.apache.dubbo.cache.CacheFactory
     * under META-INF sub folders.
     *
     * @param cacheFactory instance of CacheFactory based on <b>cache</b> type
     */
    public void setCacheFactory(CacheFactory cacheFactory) {
        this.cacheFactory = cacheFactory;
    }

    /**
     * If cache is configured, dubbo will invoke method on each method call. If cache value is returned by cache store
     * then it will return otherwise call the remote method and return value. If remote method's return value has error
     * then it will not cache the value.
     * @param invoker    service
     * @param invocation invocation.
     * @return Cache returned value if found by the underlying cache store. If cache miss it will call target method.
     * @throws RpcException
     */
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), CACHE_KEY))) {
            Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);
                                       //获取缓存
            if (cache != null) {       //如果缓存不为null,查找缓存中是否有对应的值
                String key = StringUtils.toArgumentString(invocation.getArguments()); //用方法参数创建key
                Object value = cache.get(key);  
                if (value != null) {   
                    if (value instanceof ValueWrapper) {
                        return AsyncRpcResult.newDefaultAsyncResult(((ValueWrapper) value).get(), invocation);
                    } else {
                        return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
                    }  //如果有对应的value,直接返回value,不发起方法调用
                }
                Result result = invoker.invoke(invocation);  //如果缓存中没有对应的value,发起远程调用
                if (!result.hasException()) {
                    cache.put(key, new ValueWrapper(result.getValue()));
                }
                return result;
            }
        }
        return invoker.invoke(invocation);  //如果没有设置缓存,直接发起方法调用
    }

    /**
     * Cache value wrapper.
     */
    static class ValueWrapper implements Serializable {

        private static final long serialVersionUID = -1777337318019193256L;

        private final Object value;

        public ValueWrapper (Object value) {
            this.value = value;
        }

        public Object get() {
            return this.value;
        }
    }
}

              

               

                                     

使用示例

        

*************

服务端

       

                   

          

application.yml

dubbo:
  application:
    name: dubbo-provider
    #register-mode: instance
  registry:
    address: localhost:2181
    protocol: zookeeper
    group: dubbo
  protocol:
    name: dubbo
    #port: 20880

          

HelloService

public interface HelloService {

    String get(Integer id);
}

         

HelloServiceImpl

@DubboService
public class HelloServiceImpl implements HelloService {

    @Override
    public String get(Integer id) {
        System.out.println("hello");

        return "hello";
    }
}

          

*************

消费端

     

                   

          

application.yml

dubbo:
  application:
    name: dubbo-consumer
  registry:
    protocol: zookeeper
    address: localhost:2181
    group: dubbo
    #register-mode: instance
  protocol:
    name: dubbo
    #port: 20880

server:
  port: 8081

            

HelloService

public interface HelloService {

    String get(Integer id);
}

            

HelloController

@RestController
public class HelloController {

    @DubboReference(cache = "lru")
    private HelloService helloService;

    @RequestMapping("/hello")
    public String hello(){
        helloService.get(1);
        helloService.get(1);
        helloService.get(1);
        helloService.get(1);
        helloService.get(1);
        helloService.get(1);

        return "hello";
    }
}

                      

*************

使用测试

     

localhost:8081/hello:cacheFilter缓存的key为1,value包含查询结果

              

                

                    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Dubbo缓存可以帮助加快应用程序的性能,可以将数据存储在本地缓存中,以减少数据访问的次数,从而提高性能。可以通过配置Dubbo缓存服务来使用缓存,例如使用Ehcache、Redis或Memcache。 ### 回答2: Dubbo是一款分布式框架,它支持缓存来提高系统的性能和响应速度。在Dubbo中,可以通过配置和编程的方式来使用缓存。 在配置上,可以通过在服务提供者的配置文件中为服务方法开启缓存。可以指定缓存策略、缓存类型、缓存的有效时间等参数。在Dubbo缓存策略中,可以分为:设置缓存粒度为方法级别和接口级别。方法级别的缓存可以针对具体的方法进行缓存,而接口级别的缓存可以对整个接口进行缓存。可以根据具体的业务需求来选择合适的缓存策略。 在编程上,可以在服务提供者的实现类中手动添加缓存的逻辑。可以使用Dubbo提供的缓存API,在方法调用的前后来获取和设置缓存的数据。通过在方法的实现中先判断缓存中是否存在数据,如果存在则直接返回缓存数据,如果不存在则进行业务逻辑处理,并将结果存入缓存中。这样可以避免重复计算,提高系统的性能和响应速度。 在使用Dubbo缓存时,需要注意以下几点: 1. 需要根据具体的业务场景来选择合适的缓存策略和缓存类型。 2. 需要设置合理的缓存有效时间,避免数据过期或者缓存数据过多导致内存溢出。 3. 需要保证缓存的一致性,即在数据发生变化时及时更新缓存。 4. 需要合理配置缓存的大小和存储位置,以充分利用系统资源。 总之,Dubbo提供了灵活且易用的缓存机制,可以根据实际需要来使用和配置,从而提高系统的性能和响应速度。 ### 回答3: Dubbo是一款高性能的Java开源分布式服务框架,它提供了缓存功能来加速远程服务的访问速度。在Dubbo中,我们可以使用以下两种方式来使用缓存。 1. 服务提供方缓存: 在Dubbo服务提供方,我们可以通过在服务接口的方法上添加`cache`注解来启用缓存功能。例如: ```java @Service public class UserServiceImpl implements UserService { @Override @Cacheable(cache = "userCache") public User getUserById(int userId) { // 从数据库或其他数据源中获取用户信息 // ... } } ``` 在上述代码中,我们在`getUserById`方法上添加了`Cacheable`注解,并指定了缓存名称为`userCache`。这样在调用该方法时,Dubbo会自动将返回结果缓存起来,下次再次调用时直接从缓存中获取结果,避免了重复的查询操作,提高了性能。 2. 服务消费方缓存: 在Dubbo服务消费方,我们可以通过在`reference`元素中配置`cache`元素来启用缓存功能。例如: ```xml <dubbo:reference id="userService" interface="com.example.UserService"> <dubbo:method name="getUserById" cache="userCache" /> </dubbo:reference> ``` 在上述代码中,我们通过配置`cache`属性并指定缓存名称为`userCache`,来开启缓存功能。这样在调用`userService`的`getUserById`方法时,Dubbo会自动将返回结果缓存起来,下次再次调用时直接从缓存中获取结果。 无论是服务提供方缓存还是服务消费方缓存,我们都需要借助缓存框架来实现具体的缓存功能,Dubbo本身并不提供具体的缓存实现。在实际使用中,可以选择使用一些常见的缓存框架,例如Ehcache、Redis等来实现Dubbo缓存

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值