You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Infinispan缓存序列化Bucket4j的LockFreeBucket?

解决Bucket4j LockFreeBucket存入Infinispan RemoteCache的序列化问题

问题重现

尝试将Bucket4j的LockFreeBucket对象存入Infinispan远程缓存时,执行cache.put(key, bucket)抛出序列化异常:

org.infinispan.client.hotrod.exceptions.HotRodClientException:: Unable to marshall object of type [io.github.bucket4j.local.LockFreeBucket]

根因是LockFreeBucket未实现java.io.Serializable接口,即便配置了Java序列化白名单也无法解决。

相关代码:

限流器逻辑

public boolean isRateLimited(String key) {
    Bucket bucket = cacheManager.getCache("rate-limiter").get(key, Bucket.class);
    if (bucket == null) {
        bucket = bucketSupplier.get();
        Cache<String, Bucket> cache = cacheManager.getCache("rate-limiter");
        cache.put(key, bucket);
    }
    return !bucket.tryConsume(1);
}

RemoteCacheManager配置

@Bean
public RemoteCacheManager getRemoteCacheManager() {
    ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
    configurationBuilder
        .addServer()
        .host("somehost")
        .port(11222)
        .marshaller(new JavaSerializationMarshaller())
        .addJavaSerialWhiteList("io.github.bucket4j.*")
        .security()
        .ssl()
        .sniHostName("infinispan")
        .trustStoreFileName("./cacerts 2")
        .trustStorePassword("changeit".toCharArray())
        .authentication()
        .username("some")
        .password("somepassword")
        .addContextInitializer(new CreateProtoImpl())
        .clientIntelligence(ClientIntelligence.BASIC);
    return new RemoteCacheManager(configurationBuilder.build());
}

解决方案

方案1:使用Bucket4j官方Infinispan扩展(推荐)

Bucket4j提供了专门适配Infinispan的模块,无需手动处理LockFreeBucket的序列化,直接基于缓存状态构建Bucket。

  1. 添加依赖
    引入Bucket4j的Infinispan扩展包(版本请匹配你的Bucket4j和Infinispan版本):

    <dependency>
        <groupId>com.github.vladimir-bukhtoyarov</groupId>
        <artifactId>bucket4j-infinispan</artifactId>
        <version>4.10.0</version>
    </dependency>
    
  2. 修改限流器代码
    改用Bucket4j的Infinispan扩展创建Bucket,直接复用远程缓存存储Bucket状态:

    import io.github.bucket4j.Bucket;
    import io.github.bucket4j.Bucket4j;
    import io.github.bucket4j.Bandwidth;
    import io.github.bucket4j.infinispan.Infinispan;
    import org.infinispan.client.hotrod.RemoteCache;
    
    public boolean isRateLimited(String key) {
        // 获取远程缓存实例
        RemoteCache<String, GridBucketState> cache = cacheManager.getCache("rate-limiter");
        
        // 基于Infinispan缓存构建Bucket
        Bucket bucket = Bucket4j.extension(Infinispan.class)
                .builder()
                // 替换为你的限流规则(示例:1分钟10次请求)
                .addLimit(Bandwidth.simple(10, java.time.Duration.ofMinutes(1)))
                // 从缓存加载或创建Bucket状态,不存在则重建
                .build(cache, key, RecoveryStrategy.RECONSTRUCT);
        
        return !bucket.tryConsume(1);
    }
    
  3. 调整序列化白名单
    由于存储的是GridBucketState(Bucket4j的分布式状态对象),需将其包路径加入白名单:

    configurationBuilder.addJavaSerialWhiteList("com.github.vladimir_bukhtoyarov.bucket4j.grid.*");
    

方案2:自定义序列化(不推荐)

若无法使用官方扩展,需为LockFreeBucket实现自定义序列化逻辑,比如通过Infinispan的AdvancedExternalizer接口解析其内部状态。但此方法依赖LockFreeBucket的私有字段,后续版本可能失效,维护成本高,不建议采用。

内容的提问来源于stack exchange,提问作者Tirumalesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:43:24