Я пытаюсь настроить небольшое приложение Springboot, используя ehcache с репликацией jgroups в kubernetes, но каким-то образом не могу обнаружить других участников для формирования кластера. Запрос начальной загрузки для поиска других узлов не работает, поскольку сообщение отправляется синхронно, но не принимается другим модулем, находящимся на другом узле.
maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test.k8s</groupId>
<artifactId>ehcache-jgroups-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ehcache-jgroups-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-jgroupsreplication</artifactId>
<version>1.7</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.jgroups</groupId>
<artifactId>jgroups</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jgroups</groupId>
<artifactId>jgroups</artifactId>
<version>3.6.17.Final</version>
</dependency>
<dependency>
<groupId>org.jgroups.kubernetes</groupId>
<artifactId>kubernetes</artifactId>
<version>0.9.2</version>
<exclusions>
<exclusion>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Приложение Springboot
@SpringBootApplication
public class EhcacheJgroupsDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EhcacheJgroupsDemoApplication.class, args);
}
}
@EnableCaching
@Configuration
class EHCacheConfig {
@Bean
public CacheManager cacheManager(){
return new EhCacheCacheManager(ehCacheManagerFactory().getObject());
}
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactory(){
EhCacheManagerFactoryBean ehCacheBean = new EhCacheManagerFactoryBean();
ehCacheBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
ehCacheBean.setShared(true);
return ehCacheBean;
}
}
@Component
@Slf4j
class CacheManagerCheck implements CommandLineRunner {
private final CacheManager cacheManager;
public CacheManagerCheck(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public void run(String... strings) {
log.info("\n\n" + "=========================================================\n"
+ "Using cache manager: " + this.cacheManager.getClass().getName() + "\n"
+ "=========================================================\n\n");
}
}
@RestController
class CountryController {
@Autowired
CountryRepository countryRepository;
@GetMapping(value = "/country/{code}")
public ResponseEntity<Country> getCountryByCode(@PathVariable("code") String code) {
Country country = countryRepository.findByCode(code);
return ResponseEntity.ok(country);
}
@DeleteMapping(value = "/country/{code}")
public ResponseEntity deleteCountryByCode(@PathVariable("code") String code) {
countryRepository.deleteCode(code);
return ResponseEntity.ok().build();
}
}
@Slf4j
@Component
class CountryRepository {
@Cacheable(value="countries", key="#code")
public Country findByCode(String code) {
log.info("---> Loading country with code={}", code);
return new Country(code);
}
@CacheEvict(value="countries",key = "#code")
public int deleteCode(String code){
log.info("---> Deleting country with code={}", code);
return 0;
}
}
@Data
class Country implements Serializable {
private final String code;
}
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<cacheManagerPeerProviderFactory
class="x.x.x.x.JGroupsCacheManagerPeerProviderFactory"
properties="file=jgroups/tcp.xml" />
<defaultCache maxElementsInMemory="50" eternal="false"
overflowToDisk="false" memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false"/>
</defaultCache>
<cache name="countries" eternal="false" maxElementsInMemory="100"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="60" memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=false"/>
</cache>
</ehcache>
tcp.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:org:jgroups"
xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">
<TCP
bind_addr="${jgroups.tcp.address:match-interface:en.*}"
bind_port="7800"
recv_buf_size="5M"
send_buf_size="1M"
max_bundle_size="64K"
enable_diagnostics="true"
thread_naming_pattern="cl"
thread_pool.min_threads="0"
thread_pool.max_threads="500"
thread_pool.keep_alive_time="30000" />
<org.jgroups.protocols.kubernetes.KUBE_PING
namespace="${KUBE_NAMESPACE:ehcache-demo}"/>
<MERGE3 max_interval="30000"
min_interval="10000"/>
<VERIFY_SUSPECT timeout="1500"/>
<BARRIER />
<pbcast.NAKACK2 xmit_interval="500"
xmit_table_num_rows="100"
xmit_table_msgs_per_row="2000"
xmit_table_max_compaction_time="30000"
use_mcast_xmit="false"
discard_delivered_msgs="true" />
<UNICAST3
xmit_table_num_rows="100"
xmit_table_msgs_per_row="1000"
xmit_table_max_compaction_time="30000"/>
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
max_bytes="8m"/>
<pbcast.GMS print_local_addr="true" join_timeout="3000"
view_bundling="true"/>
<MFC max_credits="2M"
min_threshold="0.4"/>
<FRAG2 frag_size="60K" />
<pbcast.STATE_TRANSFER />
<CENTRAL_LOCK />
<COUNTER/>
</config>