/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.yarn.server.resourcemanager.recovery; import com.google.common.base.Optional; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import javax.crypto.SecretKey; import org.apache.curator.test.TestingServer; import org.apache.hadoop.security.token.Token; import org.apache.hadoop.util.StringUtils; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.security.AMRMTokenIdentifier; import org.apache.hadoop.yarn.server.resourcemanager.RMContext; import org.apache.hadoop.yarn.server.resourcemanager.recovery.records.ApplicationStateData; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; import org.apache.hadoop.yarn.server.resourcemanager.security.AMRMTokenSecretManager; import org.apache.hadoop.yarn.server.resourcemanager.security.ClientToAMTokenSecretManagerInRM; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.junit.Before; import org.junit.After; import org.junit.Test; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class TestZKRMStateStorePerf extends RMStateStoreTestBase implements Tool { public static final Log LOG = LogFactory.getLog(TestZKRMStateStore.class); final String version = "0.1"; // Configurable variables for performance test private int ZK_PERF_NUM_APP_DEFAULT = 1000; private int ZK_PERF_NUM_APPATTEMPT_PER_APP = 10; private final long clusterTimeStamp = 1352994193343L; private static final String USAGE = "Usage: " + TestZKRMStateStorePerf.class.getSimpleName() + " -appSize numberOfApplications" + " -appAttemptSize numberOfApplicationAttempts" + " [-hostPort Host:Port]" + " [-workingZnode rootZnodeForTesting]\n"; private YarnConfiguration conf = null; private String workingZnode = "/Test"; private ZKRMStateStore store; private AMRMTokenSecretManager appTokenMgr; private ClientToAMTokenSecretManagerInRM clientToAMTokenMgr; private TestingServer curatorTestingServer; @Before public void setUpZKServer() throws Exception { curatorTestingServer = new TestingServer(); } @After public void tearDown() throws Exception { if (store != null) { store.stop(); } if (appTokenMgr != null) { appTokenMgr.stop(); } curatorTestingServer.stop(); } private void initStore(String hostPort) { Optional<String> optHostPort = Optional.fromNullable(hostPort); RMContext rmContext = mock(RMContext.class); conf = new YarnConfiguration(); conf.set(YarnConfiguration.RM_ZK_ADDRESS, optHostPort.or(curatorTestingServer.getConnectString())); conf.set(YarnConfiguration.ZK_RM_STATE_STORE_PARENT_PATH, workingZnode); store = new ZKRMStateStore(); store.init(conf); store.start(); when(rmContext.getStateStore()).thenReturn(store); appTokenMgr = new AMRMTokenSecretManager(conf, rmContext); appTokenMgr.start(); clientToAMTokenMgr = new ClientToAMTokenSecretManagerInRM(); } @SuppressWarnings("unchecked") @Override public int run(String[] args) { LOG.info("Starting ZKRMStateStorePerf ver." + version); int numApp = ZK_PERF_NUM_APP_DEFAULT; int numAppAttemptPerApp = ZK_PERF_NUM_APPATTEMPT_PER_APP; String hostPort = null; boolean launchLocalZK= true; if (args.length == 0) { System.err.println("Missing arguments."); return -1; } for (int i = 0; i < args.length; i++) { // parse command line if (args[i].equalsIgnoreCase("-appsize")) { numApp = Integer.parseInt(args[++i]); } else if (args[i].equalsIgnoreCase("-appattemptsize")) { numAppAttemptPerApp = Integer.parseInt(args[++i]); } else if (args[i].equalsIgnoreCase("-hostPort")) { hostPort = args[++i]; launchLocalZK = false; } else if (args[i].equalsIgnoreCase("-workingZnode")) { workingZnode = args[++i]; } else { System.err.println("Illegal argument: " + args[i]); return -1; } } if (launchLocalZK) { try { setUpZKServer(); } catch (Exception e) { System.err.println("failed to setup. : " + e.getMessage()); return -1; } } initStore(hostPort); long submitTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis() + 1234; ArrayList<ApplicationId> applicationIds = new ArrayList<>(); ArrayList<RMApp> rmApps = new ArrayList<>(); ArrayList<ApplicationAttemptId> attemptIds = new ArrayList<>(); HashMap<ApplicationId, Set<ApplicationAttemptId>> appIdsToAttemptId = new HashMap<>(); TestDispatcher dispatcher = new TestDispatcher(); store.setRMDispatcher(dispatcher); for (int i = 0; i < numApp; i++) { ApplicationId appId = ApplicationId.newInstance(clusterTimeStamp, i); applicationIds.add(appId); ArrayList<ApplicationAttemptId> attemptIdsForThisApp = new ArrayList<>(); for (int j = 0; j < numAppAttemptPerApp; j++) { ApplicationAttemptId attemptId = ApplicationAttemptId.newInstance(appId, j); attemptIdsForThisApp.add(attemptId); } appIdsToAttemptId.put(appId, new LinkedHashSet(attemptIdsForThisApp)); attemptIds.addAll(attemptIdsForThisApp); } for (ApplicationId appId : applicationIds) { RMApp app = null; try { app = storeApp(store, appId, submitTime, startTime); } catch (Exception e) { System.err.println("failed to create Application Znode. : " + e.getMessage()); return -1; } waitNotify(dispatcher); rmApps.add(app); } for (ApplicationAttemptId attemptId : attemptIds) { Token<AMRMTokenIdentifier> tokenId = generateAMRMToken(attemptId, appTokenMgr); SecretKey clientTokenKey = clientToAMTokenMgr.createMasterKey(attemptId); try { storeAttempt(store, attemptId, ContainerId.newContainerId(attemptId, 0L).toString(), tokenId, clientTokenKey, dispatcher); } catch (Exception e) { System.err.println("failed to create AppAttempt Znode. : " + e.getMessage()); return -1; } } long storeStart = System.currentTimeMillis(); try { store.loadState(); } catch (Exception e) { System.err.println("failed to locaState from ZKRMStateStore. : " + e.getMessage()); return -1; } long storeEnd = System.currentTimeMillis(); long loadTime = storeEnd - storeStart; String resultMsg = "ZKRMStateStore takes " + loadTime + " msec to loadState."; LOG.info(resultMsg); System.out.println(resultMsg); // cleanup try { for (RMApp app : rmApps) { ApplicationStateData appState = ApplicationStateData.newInstance(app.getSubmitTime(), app.getStartTime(), app.getApplicationSubmissionContext(), app.getUser()); ApplicationId appId = app.getApplicationId(); Map m = mock(Map.class); when(m.keySet()).thenReturn(appIdsToAttemptId.get(appId)); appState.attempts = m; store.removeApplicationStateInternal(appState); } } catch (Exception e) { System.err.println("failed to cleanup. : " + e.getMessage()); return -1; } return 0; } @Override public void setConf(Configuration conf) { // currently this function is just ignored } @Override public Configuration getConf() { return conf; } @Test public void perfZKRMStateStore() throws Exception { String[] args = { "-appSize", String.valueOf(ZK_PERF_NUM_APP_DEFAULT), "-appAttemptSize", String.valueOf(ZK_PERF_NUM_APPATTEMPT_PER_APP) }; run(args); } static public void main(String[] args) throws Exception { TestZKRMStateStorePerf perf = new TestZKRMStateStorePerf(); int res = -1; try { res = ToolRunner.run(perf, args); } catch(Exception e) { System.err.print(StringUtils.stringifyException(e)); res = -2; } if(res == -1) { System.err.print(USAGE); } System.exit(res); } }