最近,我花了一些时间围绕Neo4j版本之间的滚动升级构建了一组测试,作为其中的一部分,我想记录升级发生时的群集状态。
测试的主线程会等待升级完成,因此我想每隔几秒钟登录另一个线程。 Alistair向我指出了ScheduledExecutorService ,该服务效果很好。
我结束了一个大致如下的测试:
public class MyUpgradeTest {
@Test
public void shouldUpgradeFromOneVersionToAnother() throws InterruptedException
{
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate( new LogAllTheThings(), 0, 1, TimeUnit.SECONDS );
Thread.sleep(10000);
// do upgrade of cluster
scheduledExecutorService.shutdown();
}
static class LogAllTheThings implements Runnable
{
@Override
public void run()
{
Date time = new Date( System.currentTimeMillis() );
try
{
Map<String, Object> masterProperties = selectedProperties( client(), URI.create( "http://localhost:7474/" ) );
System.out.println( String.format( "%s: %s", time, masterProperties ) );
}
catch ( Exception ignored )
{
ignored.printStackTrace();
}
}
private static Client client()
{
DefaultClientConfig defaultClientConfig = new DefaultClientConfig();
defaultClientConfig.getClasses().add( JacksonJsonProvider.class );
return Client.create( defaultClientConfig );
}
public static Map<String, Object> selectedProperties( Client client, URI uri )
{
Map<String, Object> jmxProperties = new HashMap<String, Object>();
ArrayNode transactionsProperties = jmxBean( client, uri, "org.neo4j/instance%3Dkernel%230%2Cname%3DTransactions" );
addProperty( jmxProperties, transactionsProperties, "LastCommittedTxId" );
ArrayNode kernelProperties = jmxBean( client, uri, "org.neo4j/instance%3Dkernel%230%2Cname%3DKernel" );
addProperty( jmxProperties, kernelProperties, "KernelVersion" );
ArrayNode haProperties = jmxBean( client, uri, "org.neo4j/instance%3Dkernel%230%2Cname%3DHigh+Availability" );
addProperty( jmxProperties, haProperties, "Role" );
addProperty( jmxProperties, haProperties, "InstanceId" );
return jmxProperties;
}
private static void addProperty( Map<String, Object> jmxProperties, ArrayNode properties, String propertyName )
{
jmxProperties.put( propertyName, getProperty( properties, propertyName ) );
}
private static String getProperty( ArrayNode properties, String propertyName )
{
for ( JsonNode property : properties )
{
if ( property.get( "name" ).asText().equals( propertyName ) )
{
return property.get( "value" ).asText();
}
}
throw new RuntimeException( "Could not find requested property: " + propertyName );
}
private static ArrayNode jmxBean( Client client, URI uri, String beanExtension )
{
ClientResponse clientResponse = client
.resource( uri + "db/manage/server/jmx/domain/" + beanExtension )
.accept( MediaType.APPLICATION_JSON )
.get( ClientResponse.class );
JsonNode transactionsBean = clientResponse.getEntity( JsonNode.class );
return (ArrayNode) transactionsBean.get( 0 ).get( "attributes" );
}
}
}
LogAllTheThings每秒被调用一次,它记录Neo4j服务器作为JMX属性公开的KernelVersion,InstanceId,LastCommittedTxId和Role。
如果我们对本地Neo4j集群运行它,我们将看到以下内容:
Sun Nov 17 22:31:55 GMT 2013: {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
Sun Nov 17 22:31:56 GMT 2013: {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
Sun Nov 17 22:31:57 GMT 2013: {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
Sun Nov 17 22:31:58 GMT 2013: {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
Sun Nov 17 22:31:59 GMT 2013: {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
...
removed for brevity
下一步是同时获取集群所有成员的属性,然后我们可以引入另一个ExecutorService ,该线程的线程池为3,以便它将同时评估(至少接近)每台计算机:
static class LogAllTheThings implements Runnable
{
private ExecutorService executorService = Executors.newFixedThreadPool( 3 );
@Override
public void run()
{
List<URI> machines = new ArrayList<>( );
machines.add(URI.create( "http://localhost:7474/" ));
machines.add(URI.create( "http://localhost:7484/" ));
machines.add(URI.create( "http://localhost:7494/" ));
Map<URI, Future<Map<String, Object>>> futureJmxProperties = new HashMap<>( );
for ( final URI machine : machines )
{
Future<Map<String, Object>> futureProperties = executorService.submit( new Callable<Map<String, Object>>()
{
@Override
public Map<String, Object> call() throws Exception
{
try
{
return selectedProperties( client(), machine );
}
catch ( Exception ignored )
{
ignored.printStackTrace();
return new HashMap<>();
}
}
} );
futureJmxProperties.put( machine, futureProperties );
}
Date time = new Date( System.currentTimeMillis() );
System.out.println( time );
for ( Map.Entry<URI, Future<Map<String, Object>>> uriFutureEntry : futureJmxProperties.entrySet() )
{
try
{
System.out.println( "==> " + uriFutureEntry.getValue().get() );
}
catch ( Exception ignored )
{
}
}
}
// other methods the same as above
}
我们将每个作业提交给ExecutorService,并返回一个Future ,并将其存储在地图中,然后再检索其结果。 如果运行该命令,将看到以下输出:
Sun Nov 17 22:49:58 GMT 2013
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=2, LastCommittedTxId=18, Role=slave}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=3, LastCommittedTxId=18, Role=slave}
Sun Nov 17 22:49:59 GMT 2013
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=2, LastCommittedTxId=18, Role=slave}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=3, LastCommittedTxId=18, Role=slave}
Sun Nov 17 22:50:00 GMT 2013
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=1, LastCommittedTxId=18, Role=master}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=2, LastCommittedTxId=18, Role=slave}
==> {KernelVersion=Neo4j - Graph Database Kernel 2.0.0-M06, InstanceId=3, LastCommittedTxId=18, Role=slave}
...
removed for brevity
总体而言,这种方法效果很好,尽管我总是愿意学习更好的方法!
翻译自: https://www.javacodegeeks.com/2013/11/java-schedule-a-job-to-run-on-a-time-interval.html