@Override protected void pageBody(HttpServletRequest req, HttpServletResponse response, StringBuilder sb) throws Exception { String tserverAddress = req.getParameter("s"); // Check to make sure tserver is a known address boolean tserverExists = false; if (tserverAddress != null && tserverAddress.isEmpty() == false) { for (TabletServerStatus ts : Monitor.getMmi().getTServerInfo()) { if (tserverAddress.equals(ts.getName())) { tserverExists = true; break; } } } if (tserverAddress == null || tserverAddress.isEmpty() || tserverExists == false) { doBadTserverList(req, sb); doDeadTserverList(req, sb); ArrayList<TabletServerStatus> tservers = new ArrayList<TabletServerStatus>(); if (Monitor.getMmi() != null) tservers.addAll(Monitor.getMmi().tServerInfo); Table tServerList = new Table("tservers", "Tablet Servers"); tServerList.setSubCaption( "Click on the <span style='color: #0000ff;'>server address</span> to view detailed performance statistics for that server."); doTserverList(req, sb, tservers, null, tServerList); return; } double totalElapsedForAll = 0; double splitStdDev = 0; double minorStdDev = 0; double minorQueueStdDev = 0; double majorStdDev = 0; double majorQueueStdDev = 0; double currentMinorAvg = 0; double currentMajorAvg = 0; double currentMinorStdDev = 0; double currentMajorStdDev = 0; TabletStats total = new TabletStats(null, new ActionStats(), new ActionStats(), new ActionStats(), 0, 0, 0, 0); InetSocketAddress address = AddressUtil.parseAddress(tserverAddress, -1); TabletStats historical = new TabletStats(null, new ActionStats(), new ActionStats(), new ActionStats(), 0, 0, 0, 0); List<TabletStats> tsStats = new ArrayList<TabletStats>(); try { TabletClientService.Client client = ThriftUtil.getClient( new TabletClientService.Client.Factory(), address, Monitor.getSystemConfiguration()); try { for (String tableId : Monitor.getMmi().tableMap.keySet()) { tsStats.addAll( client.getTabletStats( Tracer.traceInfo(), SystemCredentials.get().toThrift(Monitor.getInstance()), tableId)); } historical = client.getHistoricalStats( Tracer.traceInfo(), SystemCredentials.get().toThrift(Monitor.getInstance())); } finally { ThriftUtil.returnClient(client); } } catch (Exception e) { banner(sb, "error", "No Such Tablet ServerAvailable"); log.error(e, e); return; } Table perTabletResults = new Table("perTabletResults", "Detailed Current Operations"); perTabletResults.setSubCaption("Per-tablet Details"); perTabletResults.addSortableColumn("Table", new TableLinkType(), null); perTabletResults.addSortableColumn("Tablet"); perTabletResults.addSortableColumn("Entries", new NumberType<Long>(), null); perTabletResults.addSortableColumn("Ingest", new NumberType<Long>(), null); perTabletResults.addSortableColumn("Query", new NumberType<Long>(), null); perTabletResults.addSortableColumn("Minor Avg", new SecondType(), null); perTabletResults.addSortableColumn("Minor Std Dev", new SecondType(), null); perTabletResults.addSortableColumn("Minor Avg e/s", new NumberType<Double>(), null); perTabletResults.addSortableColumn("Major Avg", new SecondType(), null); perTabletResults.addSortableColumn("Major Std Dev", new SecondType(), null); perTabletResults.addSortableColumn("Major Avg e/s", new NumberType<Double>(), null); for (TabletStats info : tsStats) { if (info.extent == null) { historical = info; continue; } total.numEntries += info.numEntries; TabletStatsKeeper.update(total.minors, info.minors); TabletStatsKeeper.update(total.majors, info.majors); KeyExtent extent = new KeyExtent(info.extent); String tableId = extent.getTableId().toString(); MessageDigest digester = MessageDigest.getInstance("MD5"); if (extent.getEndRow() != null && extent.getEndRow().getLength() > 0) { digester.update(extent.getEndRow().getBytes(), 0, extent.getEndRow().getLength()); } String obscuredExtent = new String(Base64.encodeBase64(digester.digest())); String displayExtent = String.format("<code>[%s]</code>", obscuredExtent); TableRow row = perTabletResults.prepareRow(); row.add(tableId); row.add(displayExtent); row.add(info.numEntries); row.add(info.ingestRate); row.add(info.queryRate); row.add(info.minors.num != 0 ? info.minors.elapsed / info.minors.num : null); row.add(stddev(info.minors.elapsed, info.minors.num, info.minors.sumDev)); row.add(info.minors.elapsed != 0 ? info.minors.count / info.minors.elapsed : null); row.add(info.majors.num != 0 ? info.majors.elapsed / info.majors.num : null); row.add(stddev(info.majors.elapsed, info.majors.num, info.majors.sumDev)); row.add(info.majors.elapsed != 0 ? info.majors.count / info.majors.elapsed : null); perTabletResults.addRow(row); } // Calculate current averages oldServer adding in historical data if (total.minors.num != 0) currentMinorAvg = (long) (total.minors.elapsed / total.minors.num); if (total.minors.elapsed != 0 && total.minors.num != 0) currentMinorStdDev = stddev(total.minors.elapsed, total.minors.num, total.minors.sumDev); if (total.majors.num != 0) currentMajorAvg = total.majors.elapsed / total.majors.num; if (total.majors.elapsed != 0 && total.majors.num != 0 && total.majors.elapsed > total.majors.num) currentMajorStdDev = stddev(total.majors.elapsed, total.majors.num, total.majors.sumDev); // After these += operations, these variables are now total for current // tablets and historical tablets TabletStatsKeeper.update(total.minors, historical.minors); TabletStatsKeeper.update(total.majors, historical.majors); totalElapsedForAll += total.majors.elapsed + historical.splits.elapsed + total.minors.elapsed; minorStdDev = stddev(total.minors.elapsed, total.minors.num, total.minors.sumDev); minorQueueStdDev = stddev(total.minors.queueTime, total.minors.num, total.minors.queueSumDev); majorStdDev = stddev(total.majors.elapsed, total.majors.num, total.majors.sumDev); majorQueueStdDev = stddev(total.majors.queueTime, total.majors.num, total.majors.queueSumDev); splitStdDev = stddev(historical.splits.num, historical.splits.elapsed, historical.splits.sumDev); doDetailTable(req, sb, address, tsStats.size(), total, historical); doAllTimeTable( req, sb, total, historical, majorQueueStdDev, minorQueueStdDev, totalElapsedForAll, splitStdDev, majorStdDev, minorStdDev); doCurrentTabletOps( req, sb, currentMinorAvg, currentMinorStdDev, currentMajorAvg, currentMajorStdDev); perTabletResults.generate(req, sb); }
static void doTserverList( HttpServletRequest req, StringBuilder sb, List<TabletServerStatus> tservers, String tableId, Table tServerList) { int guessHighLoad = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); long now = System.currentTimeMillis(); double avgLastContact = 0.; for (TabletServerStatus status : tservers) { avgLastContact += (now - status.lastContact); } final long MINUTES = 3 * 60 * 1000; tServerList.addSortableColumn("Server", new TServerLinkType(), null); tServerList.addSortableColumn( "Hosted Tablets", new NumberType<Integer>(0, Integer.MAX_VALUE), null); tServerList.addSortableColumn( "Last Contact", new DurationType(0l, (long) Math.min(avgLastContact * 4, MINUTES)), null); tServerList.addSortableColumn( "Entries", new NumberType<Long>(), "The number of key/value pairs."); tServerList.addSortableColumn( "Ingest", new NumberType<Long>(), "The number of key/value pairs inserted. (Note that deletes are also 'inserted')"); tServerList.addSortableColumn( "Query", new NumberType<Long>(), "The number of key/value pairs returned to clients. (Not the number of scans)"); tServerList.addSortableColumn( "Hold Time", new DurationType(), "The amount of time ingest is suspended waiting for data to be written to disk."); tServerList.addSortableColumn( "Running<br />Scans", new CompactionsType("scans"), "The number of scans running and queued on this tablet server."); tServerList.addSortableColumn( "Minor<br />Compactions", new CompactionsType("minor"), "The number of minor compactions running and (queued waiting for resources). Minor compactions are the operations where entries are flushed from memory to disk."); tServerList.addSortableColumn( "Major<br />Compactions", new CompactionsType("major"), "The number of major compactions running and (queued waiting for resources). " + "Major compactions are the operations where many smaller files are grouped into a larger file, eliminating duplicates and cleaning up deletes."); tServerList.addSortableColumn( "Index Cache<br />Hit Rate", new PercentageType(), "The recent index cache hit rate."); tServerList.addSortableColumn( "Data Cache<br />Hit Rate", new PercentageType(), "The recent data cache hit rate."); tServerList.addSortableColumn( "OS Load", new NumberType<Double>(0., guessHighLoad * 1., 0., guessHighLoad * 3.), "The Unix one minute load average. The average number of processes in the run queue over a one minute interval."); log.debug("tableId: " + tableId); for (TabletServerStatus status : tservers) { if (status == null) status = NO_STATUS; TableInfo summary = Monitor.summarizeTableStats(status); if (tableId != null) summary = status.tableMap.get(tableId); if (summary == null) continue; TableRow row = tServerList.prepareRow(); row.add(status); // add for server name row.add(summary.tablets); row.add(now - status.lastContact); row.add(summary.recs); row.add(summary.ingestRate); row.add(summary.queryRate); row.add(status.holdTime); row.add(summary); // add for scans row.add(summary); // add for minor compactions row.add(summary); // add for major compactions double indexCacheHitRate = status.indexCacheHits / (double) Math.max(status.indexCacheRequest, 1); row.add(indexCacheHitRate); double dataCacheHitRate = status.dataCacheHits / (double) Math.max(status.dataCacheRequest, 1); row.add(dataCacheHitRate); row.add(status.osLoad); tServerList.addRow(row); } tServerList.generate(req, sb); }