Java 在分布式缓存l2上使用infinispan和hibernate进行连接锁定

Java 在分布式缓存l2上使用infinispan和hibernate进行连接锁定,java,hibernate,amazon-web-services,infinispan,jgroups,Java,Hibernate,Amazon Web Services,Infinispan,Jgroups,我使用infinispan作为分布式hibernate缓存L2,在AWS上使用jgroups进行配置。 但是,在以下场景中,我在重载时面临一个问题: 最初有2个EC2实例可用 负荷急剧增加 负载平衡启动4个EC2实例 部分减载 负载平衡减少2个EC2实例 剩余的所有实例开始保持数据库连接(Hikari池),直到没有可用的连接为止,执行以下所有请求都会由于等待空闲连接超时而返回错误 其余实例尝试与旧实例通信,但没有得到响应,在等待响应时保持连接 所有实体都使用读写策略 Infinispan配置

我使用infinispan作为分布式hibernate缓存L2,在AWS上使用jgroups进行配置。 但是,在以下场景中,我在重载时面临一个问题:

  • 最初有2个EC2实例可用
  • 负荷急剧增加
  • 负载平衡启动4个EC2实例
  • 部分减载
  • 负载平衡减少2个EC2实例
  • 剩余的所有实例开始保持数据库连接(Hikari池),直到没有可用的连接为止,执行以下所有请求都会由于等待空闲连接超时而返回错误
其余实例尝试与旧实例通信,但没有得到响应,在等待响应时保持连接

所有实体都使用读写策略

Infinispan配置: org/infinispan/hibernate/cache/commons/builder/infinispan-configs.xml

region.factory\u类:org.infinispan.hibernate.cache.commons.InfinispanRegionFactory

以下Jgroups配置编辑自:org/infinispan/infinispan-core/9.2.0.Final/infinispan-core-9.2.0.Final.jar/default-configs/default-Jgroups-tcp.xml

    <config xmlns="urn:org:jgroups"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups-4.0.xsd">
   <TCP bind_port="7800"
        enable_diagnostics="false"
        thread_naming_pattern="pl"
        send_buf_size="640k"
        sock_conn_timeout="300"
        bundler_type="no-bundler"

        thread_pool.min_threads="${jgroups.thread_pool.min_threads:50}"
        thread_pool.max_threads="${jgroups.thread_pool.max_threads:500}"
        thread_pool.keep_alive_time="30000"
   />
   <AWS_ELB_PING
           region="sa-east-1"
           load_balancers_names="elb-name"
   />
   <MERGE3 min_interval="5000"
           max_interval="30000"
   />
   <FD_SOCK />
   <FD_ALL timeout="9000"
           interval="3000"
           timeout_check_interval="1000"
   />
   <VERIFY_SUSPECT timeout="5000" />
   <pbcast.NAKACK2 use_mcast_xmit="false"
                   xmit_interval="100"
                   xmit_table_num_rows="50"
                   xmit_table_msgs_per_row="1024"
                   xmit_table_max_compaction_time="30000"
                   resend_last_seqno="true"
   />
   <UNICAST3 xmit_interval="100"
             xmit_table_num_rows="50"
             xmit_table_msgs_per_row="1024"
             xmit_table_max_compaction_time="30000"
             conn_expiry_timeout="0"
   />
   <pbcast.STABLE stability_delay="500"
                  desired_avg_gossip="5000"
                  max_bytes="1M"
   />
   <pbcast.GMS print_local_addr="false"
               install_view_locally_first="true"
               join_timeout="${jgroups.join_timeout:5000}"
   />
   <MFC max_credits="2m"
        min_threshold="0.40"
   />
   <FRAG3/>
</config>

AWS\u ELB\u PING:该类是发现类的实现,其中使用AWS ELB api发现所有可用的IP

我从下面的代码中删除了日志和一些样板代码:

public class AWS_ELB_PING extends Discovery {

    private static final String LIST_ELEMENT_SEPARATOR = ",";

    static {
        ClassConfigurator.addProtocol((short) 790, AWS_ELB_PING.class); // id must be unique
    }

    private String region;

    private String load_balancers_names;

    private int bind_port = 7800;

    private AmazonElasticLoadBalancing amazonELBClient;
    private AmazonEC2 amazonEC2Client;

    private List<String> getLoadBalancersNamesList() {
        return Arrays.asList(Optional.ofNullable(load_balancers_names).orElse("").split(LIST_ELEMENT_SEPARATOR));
    }

    @Override
    public void init() throws Exception {
        super.init();
        DefaultAWSCredentialsProviderChain awsCredentialsProviderChain = DefaultAWSCredentialsProviderChain.getInstance();
        amazonELBClient = AmazonElasticLoadBalancingClientBuilder.standard()
                .withRegion(region)
                .withCredentials(awsCredentialsProviderChain)
                .build();
        amazonEC2Client = AmazonEC2ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(awsCredentialsProviderChain)
                .build();
    }

    @Override
    public void discoveryRequestReceived(final Address sender, final String logical_name,
                                         final PhysicalAddress physical_addr) {
        super.discoveryRequestReceived(sender, logical_name, physical_addr);
    }

    @Override
    public void findMembers(final List<Address> members, final boolean initialDiscovery, final Responses responses) {
        PhysicalAddress physicalAddress = null;
        PingData data = null;
        if (!use_ip_addrs || !initialDiscovery) {
            physicalAddress = (PhysicalAddress) super.down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr));
            data = new PingData(local_addr, false, NameCache.get(local_addr), physicalAddress);
            if (members != null && members.size() <= max_members_in_discovery_request) {
                data.mbrs(members);
            }
        }

        sendDiscoveryRequests(physicalAddress, data, initialDiscovery, getLoadBalancersInstances());
    }

    private Set<Instance> getLoadBalancersInstances() {
        final List<String> loadBalancerNames = getLoadBalancersNamesList();
        final List<LoadBalancerDescription> loadBalancerDescriptions = amazonELBClient
                .describeLoadBalancers(new DescribeLoadBalancersRequest().withLoadBalancerNames(loadBalancerNames))
                .getLoadBalancerDescriptions();

        checkLoadBalancersExists(loadBalancerNames, loadBalancerDescriptions);

        final List<String> instanceIds = loadBalancerDescriptions.stream()
                .flatMap(loadBalancer -> loadBalancer.getInstances().stream())
                .map(instance -> instance.getInstanceId())
                .collect(toList());

        return amazonEC2Client.describeInstances(new DescribeInstancesRequest().withInstanceIds(instanceIds))
                    .getReservations()
                    .stream()
                    .map(Reservation::getInstances)
                    .flatMap(List::stream)
                    .collect(Collectors.toSet());
    }

    private void checkLoadBalancersExists(final List<String> loadBalancerNames,
                                          final List<LoadBalancerDescription> loadBalancerDescriptions) {
        final Set<String> difference = Sets.difference(new HashSet<>(loadBalancerNames),
            loadBalancerDescriptions
                    .stream()
                    .map(LoadBalancerDescription::getLoadBalancerName)
                    .collect(Collectors.toSet()));
    }

    private PhysicalAddress toPhysicalAddress(final Instance instance) {
        try {
            return new IpAddress(instance.getPrivateIpAddress(), bind_port);
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void sendDiscoveryRequests(@Nullable final PhysicalAddress localAddress, @Nullable final PingData data,
                                       final boolean initialDiscovery, final Set<Instance> instances) {
        final PingHeader header = new PingHeader(PingHeader.GET_MBRS_REQ)
                    .clusterName(cluster_name)
                    .initialDiscovery(initialDiscovery);

        instances.stream()
                .map(this::toPhysicalAddress)
                .filter(physicalAddress -> !physicalAddress.equals(localAddress))
                .forEach(physicalAddress -> sendDiscoveryRequest(data, header, physicalAddress));
    }

    private void sendDiscoveryRequest(@Nullable final PingData data, final PingHeader header,
                      final PhysicalAddress destinationAddress) {
        final Message message = new Message(destinationAddress)
                .setFlag(Message.Flag.INTERNAL, Message.Flag.DONT_BUNDLE, Message.Flag.OOB)
                .putHeader(this.id, header);
        if (data != null) {
            message.setBuffer(marshal(data));
        }

        if (async_discovery_use_separate_thread_per_request) {
            timer.execute(() -> sendDiscoveryRequest(message), sends_can_block);
        } else {
            sendDiscoveryRequest(message);
        }
    }

    protected void sendDiscoveryRequest(final Message message) {
        try {
            super.down(message);
        } catch (final Throwable t) {
        }
    }

    @Override
    public boolean isDynamic() {
        return true;
    }

    @Override
    public void stop() {
        try {
            if (amazonEC2Client != null) {
                amazonEC2Client.shutdown();
            }
            if (amazonELBClient != null) {
                amazonELBClient.shutdown();
            }
        } catch (final Exception e) {
        } finally {
            super.stop();
        }
    }
}
公共类AWS\u ELB\u PING扩展了发现{
私有静态最终字符串列表\元素\分隔符=“,”;
静止的{
ClassConfigurator.addProtocol((short)790,AWS_ELB_PING.class);//id必须是唯一的
}
私有字符串区域;
私有字符串负载均衡器名称;
专用int bind_端口=7800;
私有AmazoneLasticLoadBalking amazonELBClient;
AmazonEC2专用AmazonEC2客户端;
私有列表GetLoadBalancersNameList(){
返回Arrays.asList(可选的.ofNullable(负载平衡器名称).orElse(“”).split(列表元素分隔符));
}
@凌驾
public void init()引发异常{
super.init();
DefaultAWSCredentialsProviderChain awsCredentialsProviderChain=DefaultAWSCredentialsProviderChain.getInstance();
amazonELBClient=AmazonElasticLoadBalancingClientBuilder.standard()
.withRegion(地区)
.具有凭据(awsCredentialsProviderChain)
.build();
amazonEC2Client=AmazonEC2ClientBuilder.standard()
.withRegion(地区)
.具有凭据(awsCredentialsProviderChain)
.build();
}
@凌驾
public void discoveryRequestReceived(最终地址发送者,最终字符串逻辑名称,
最终物理地址(物理地址){
super.discoveryRequestReceived(发送方、逻辑名称、物理地址);
}
@凌驾
public void find成员(最终列表成员、最终布尔初始发现、最终响应){
PhysicalAddress PhysicalAddress=null;
PingData数据=null;
如果(!使用ip地址| | |!初始发现){
physicalAddress=(physicalAddress)super.down(新事件(Event.GET_PHYSICAL_ADDRESS,local_addr));
数据=新的PingData(local\u addr,false,NameCache.get(local\u addr),physicaldaddress);
if(members!=null&&members.size()loadBalancer.getInstances().stream())
.map(实例->实例.getInstanceId())
.collect(toList());
返回amazonEC2Client.describeInstances(新的DescribeInstancesRequest().WithInstanceId(InstanceId))
.getReservations()
.stream()
.map(保留::getInstances)
.flatMap(列表::流)
.collect(收集器.toSet());
}
private void CheckLoadBalancer性别歧视者(最终列表LoadBalancer名称,
最终清单(说明){
最终集差异=集差异(新哈希集(LoadBalancerName),
负载平衡器说明
.stream()
.map(LoadBalancerDescription::getLoadBalancerName)
.collect(Collectors.toSet());
}
私有物理地址到物理地址(最终实例){
试一试{
返回新的IpAddress(instance.getPrivateIpAddress(),bind_port);
}捕获(最终异常e){
抛出新的运行时异常(e);
}
}
private void sendDiscoveryRequests(@Nullable final PhysicalAddress localAddress、@Nullable final PingData、,
最终布尔初始发现,最终集合实例){
最终PingHeader头=新PingHeader(PingHeader.GET\u MBRS\u REQ)
.clusterName(群集名称)
.初始发现(初始发现);
instances.stream()
.map(此::TopPhysicalAddress)
.filter(physicalAddress->!physicalAddress.equals(localAddress))
.forEach(physicalAddress->SendDiscoveryrRequest(数据、标头、physicalAddress));
}
私有void sendDiscoveryRequest(@Nullable final PingData data,final PingHeader,
最终物理地址destinationAddress){
最终消息消息=新消息(destinationAddress)
.setFlag(Message.Flag.INTERNAL,Message.Flag.DONT_BUNDLE,Message.Flag.OOB)
.putHeader(this.id,header);
如果(数据!=null){
message.setBuffer(封送(数据));
}
if(异步发现每请求使用独立线程){
timer.execute(()->sendDiscoveryRequest(消息),发送\u can\u块);
}否则{
sendDiscoveryRequest(消息);
}
}
受保护的无效发送发现请求(最终Me)