View Javadoc

1   /**
2    * Copyright 2007 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.IOException;
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.TreeMap;
30  import java.util.TreeSet;
31  
32  import org.apache.hadoop.hbase.util.Bytes;
33  import org.apache.hadoop.hbase.util.Strings;
34  import org.apache.hadoop.io.VersionedWritable;
35  import org.apache.hadoop.io.WritableComparable;
36  
37  /**
38   * This class is used exporting current state of load on a RegionServer.
39   */
40  public class HServerLoad extends VersionedWritable
41  implements WritableComparable<HServerLoad> {
42    private static final byte VERSION = 2;
43    // Empty load instance.
44    public static final HServerLoad EMPTY_HSERVERLOAD = new HServerLoad();
45  
46    /** Number of requests per second since last report.
47     */
48    // TODO: Instead build this up out of region counters.
49    private int numberOfRequests = 0;
50  
51    /** Total Number of requests from the start of the region server.
52     */
53    private int totalNumberOfRequests = 0;
54    
55    /** the amount of used heap, in MB */
56    private int usedHeapMB = 0;
57  
58    /** the maximum allowable size of the heap, in MB */
59    private int maxHeapMB = 0;
60  
61    // Regionserver-level coprocessors, e.g., WALObserver implementations.
62    // Region-level coprocessors, on the other hand, are stored inside RegionLoad
63    // objects.
64    private Set<String> coprocessors =
65        new TreeSet<String>();
66  
67    /**
68     * HBASE-4070: Improve region server metrics to report loaded coprocessors.
69     *
70     * @return Returns the set of all coprocessors on this
71     * regionserver, where this set is the union of the
72     * regionserver-level coprocessors on one hand, and all of the region-level
73     * coprocessors, on the other.
74     *
75     * We must iterate through all regions loaded on this regionserver to
76     * obtain all of the region-level coprocessors.
77     */
78    public String[] getCoprocessors() {
79      TreeSet<String> returnValue = new TreeSet<String>(coprocessors);
80      for (Map.Entry<byte[], RegionLoad> rls: getRegionsLoad().entrySet()) {
81        for (String coprocessor: rls.getValue().getCoprocessors()) {
82          returnValue.add(coprocessor);
83        }
84      }
85      return returnValue.toArray(new String[0]);
86    }
87  
88    /** per-region load metrics */
89    private Map<byte[], RegionLoad> regionLoad =
90      new TreeMap<byte[], RegionLoad>(Bytes.BYTES_COMPARATOR);
91  
92    /** @return the object version number */
93    public byte getVersion() {
94      return VERSION;
95    }
96  
97    /**
98     * Encapsulates per-region loading metrics.
99     */
100   public static class RegionLoad extends VersionedWritable {
101     private static final byte VERSION = 1;
102 
103     /** @return the object version number */
104     public byte getVersion() {
105       return VERSION;
106     }
107 
108     /** the region name */
109     private byte[] name;
110     /** the number of stores for the region */
111     private int stores;
112     /** the number of storefiles for the region */
113     private int storefiles;
114     /** the total size of the store files for the region, uncompressed, in MB */
115     private int storeUncompressedSizeMB;
116     /** the current total size of the store files for the region, in MB */
117     private int storefileSizeMB;
118     /** the current size of the memstore for the region, in MB */
119     private int memstoreSizeMB;
120 
121     /**
122      * The current total size of root-level store file indexes for the region,
123      * in MB. The same as {@link #rootIndexSizeKB} but in MB.
124      */
125     private int storefileIndexSizeMB;
126     /** the current total read requests made to region */
127     private int readRequestsCount;
128     /** the current total write requests made to region */
129     private int writeRequestsCount;
130     /** the total compacting key values in currently running compaction */
131     private long totalCompactingKVs;
132     /** the completed count of key values in currently running compaction */
133     private long currentCompactedKVs;
134 
135     /** The current total size of root-level indexes for the region, in KB. */
136     private int rootIndexSizeKB;
137 
138     /** The total size of all index blocks, not just the root level, in KB. */
139     private int totalStaticIndexSizeKB;
140 
141     /**
142      * The total size of all Bloom filter blocks, not just loaded into the
143      * block cache, in KB.
144      */
145     private int totalStaticBloomSizeKB;
146 
147     // Region-level coprocessors.
148     Set<String> coprocessors =
149         new TreeSet<String>();
150 
151     /**
152      * Constructor, for Writable
153      */
154     public RegionLoad() {
155         super();
156     }
157 
158     /**
159      * @param name
160      * @param stores
161      * @param storefiles
162      * @param storeUncompressedSizeMB
163      * @param storefileSizeMB
164      * @param memstoreSizeMB
165      * @param storefileIndexSizeMB
166      * @param readRequestsCount
167      * @param writeRequestsCount
168      * @param totalCompactingKVs
169      * @param currentCompactedKVs
170      * @param coprocessors
171      */
172     public RegionLoad(final byte[] name, final int stores,
173         final int storefiles, final int storeUncompressedSizeMB,
174         final int storefileSizeMB,
175         final int memstoreSizeMB, final int storefileIndexSizeMB,
176         final int rootIndexSizeKB, final int totalStaticIndexSizeKB,
177         final int totalStaticBloomSizeKB,
178         final int readRequestsCount, final int writeRequestsCount,
179         final long totalCompactingKVs, final long currentCompactedKVs,
180         final Set<String> coprocessors) {
181       this.name = name;
182       this.stores = stores;
183       this.storefiles = storefiles;
184       this.storeUncompressedSizeMB = storeUncompressedSizeMB;
185       this.storefileSizeMB = storefileSizeMB;
186       this.memstoreSizeMB = memstoreSizeMB;
187       this.storefileIndexSizeMB = storefileIndexSizeMB;
188       this.rootIndexSizeKB = rootIndexSizeKB;
189       this.totalStaticIndexSizeKB = totalStaticIndexSizeKB;
190       this.totalStaticBloomSizeKB = totalStaticBloomSizeKB;
191       this.readRequestsCount = readRequestsCount;
192       this.writeRequestsCount = writeRequestsCount;
193       this.totalCompactingKVs = totalCompactingKVs;
194       this.currentCompactedKVs = currentCompactedKVs;
195       this.coprocessors = coprocessors;
196     }
197 
198     // Getters
199     private String[] getCoprocessors() {
200       return coprocessors.toArray(new String[0]);
201     }
202 
203     /**
204      * @return the region name
205      */
206     public byte[] getName() {
207       return name;
208     }
209 
210     /**
211      * @return the region name as a string
212      */
213     public String getNameAsString() {
214       return Bytes.toString(name);
215     }
216 
217     /**
218      * @return the number of stores
219      */
220     public int getStores() {
221       return stores;
222     }
223 
224     /**
225      * @return the number of storefiles
226      */
227     public int getStorefiles() {
228       return storefiles;
229     }
230 
231     /**
232      * @return the total size of the storefiles, in MB
233      */
234     public int getStorefileSizeMB() {
235       return storefileSizeMB;
236     }
237 
238     /**
239      * @return the memstore size, in MB
240      */
241     public int getMemStoreSizeMB() {
242       return memstoreSizeMB;
243     }
244 
245     /**
246      * @return the approximate size of storefile indexes on the heap, in MB
247      */
248     public int getStorefileIndexSizeMB() {
249       return storefileIndexSizeMB;
250     }
251 
252     /**
253      * @return the number of requests made to region
254      */
255     public long getRequestsCount() {
256       return readRequestsCount + writeRequestsCount;
257     }
258 
259     /**
260      * @return the number of read requests made to region
261      */
262     public long getReadRequestsCount() {
263       return readRequestsCount;
264     }
265 
266     /**
267      * @return the number of read requests made to region
268      */
269     public long getWriteRequestsCount() {
270       return writeRequestsCount;
271     }
272 
273     /**
274      * @return the total number of kvs in current compaction
275      */
276     public long getTotalCompactingKVs() {
277       return totalCompactingKVs;
278     }
279 
280     /**
281      * @return the number of already compacted kvs in current compaction
282      */
283     public long getCurrentCompactedKVs() {
284       return currentCompactedKVs;
285     }
286 
287     // Setters
288 
289     /**
290      * @param name the region name
291      */
292     public void setName(byte[] name) {
293       this.name = name;
294     }
295 
296     /**
297      * @param stores the number of stores
298      */
299     public void setStores(int stores) {
300       this.stores = stores;
301     }
302 
303     /**
304      * @param storefiles the number of storefiles
305      */
306     public void setStorefiles(int storefiles) {
307       this.storefiles = storefiles;
308     }
309 
310     /**
311      * @param memstoreSizeMB the memstore size, in MB
312      */
313     public void setMemStoreSizeMB(int memstoreSizeMB) {
314       this.memstoreSizeMB = memstoreSizeMB;
315     }
316 
317     /**
318      * @param storefileIndexSizeMB the approximate size of storefile indexes
319      *  on the heap, in MB
320      */
321     public void setStorefileIndexSizeMB(int storefileIndexSizeMB) {
322       this.storefileIndexSizeMB = storefileIndexSizeMB;
323     }
324 
325     /**
326      * @param requestsCount the number of read requests to region
327      */
328     public void setReadRequestsCount(int requestsCount) {
329       this.readRequestsCount = requestsCount;
330     }
331 
332     /**
333      * @param requestsCount the number of write requests to region
334      */
335     public void setWriteRequestsCount(int requestsCount) {
336       this.writeRequestsCount = requestsCount;
337     }
338 
339     /**
340      * @param totalCompactingKVs the number of kvs total in current compaction
341      */
342     public void setTotalCompactingKVs(long totalCompactingKVs) {
343       this.totalCompactingKVs = totalCompactingKVs;
344     }
345 
346     /**
347      * @param currentCompactedKVs the number of kvs already compacted in
348      * current compaction
349      */
350     public void setCurrentCompactedKVs(long currentCompactedKVs) {
351       this.currentCompactedKVs = currentCompactedKVs;
352     }
353 
354     // Writable
355     public void readFields(DataInput in) throws IOException {
356       super.readFields(in);
357       int version = in.readByte();
358       if (version > VERSION) throw new IOException("Version mismatch; " + version);
359       int namelen = in.readInt();
360       this.name = new byte[namelen];
361       in.readFully(this.name);
362       this.stores = in.readInt();
363       this.storefiles = in.readInt();
364       this.storeUncompressedSizeMB = in.readInt();
365       this.storefileSizeMB = in.readInt();
366       this.memstoreSizeMB = in.readInt();
367       this.storefileIndexSizeMB = in.readInt();
368       this.readRequestsCount = in.readInt();
369       this.writeRequestsCount = in.readInt();
370       this.rootIndexSizeKB = in.readInt();
371       this.totalStaticIndexSizeKB = in.readInt();
372       this.totalStaticBloomSizeKB = in.readInt();
373       this.totalCompactingKVs = in.readLong();
374       this.currentCompactedKVs = in.readLong();
375       int coprocessorsSize = in.readInt();
376       coprocessors = new TreeSet<String>();
377       for (int i = 0; i < coprocessorsSize; i++) {
378         coprocessors.add(in.readUTF());
379       }
380     }
381 
382     public void write(DataOutput out) throws IOException {
383       super.write(out);
384       out.writeByte(VERSION);
385       out.writeInt(name.length);
386       out.write(name);
387       out.writeInt(stores);
388       out.writeInt(storefiles);
389       out.writeInt(storeUncompressedSizeMB);
390       out.writeInt(storefileSizeMB);
391       out.writeInt(memstoreSizeMB);
392       out.writeInt(storefileIndexSizeMB);
393       out.writeInt(readRequestsCount);
394       out.writeInt(writeRequestsCount);
395       out.writeInt(rootIndexSizeKB);
396       out.writeInt(totalStaticIndexSizeKB);
397       out.writeInt(totalStaticBloomSizeKB);
398       out.writeLong(totalCompactingKVs);
399       out.writeLong(currentCompactedKVs);
400       out.writeInt(coprocessors.size());
401       for (String coprocessor: coprocessors) {
402         out.writeUTF(coprocessor);
403       }
404     }
405 
406     /**
407      * @see java.lang.Object#toString()
408      */
409     @Override
410     public String toString() {
411       StringBuilder sb = Strings.appendKeyValue(new StringBuilder(), "numberOfStores",
412         Integer.valueOf(this.stores));
413       sb = Strings.appendKeyValue(sb, "numberOfStorefiles",
414         Integer.valueOf(this.storefiles));
415       sb = Strings.appendKeyValue(sb, "storefileUncompressedSizeMB",
416         Integer.valueOf(this.storeUncompressedSizeMB));
417       sb = Strings.appendKeyValue(sb, "storefileSizeMB",
418           Integer.valueOf(this.storefileSizeMB));
419       if (this.storeUncompressedSizeMB != 0) {
420         sb = Strings.appendKeyValue(sb, "compressionRatio",
421             String.format("%.4f", (float)this.storefileSizeMB/
422                 (float)this.storeUncompressedSizeMB));
423       }
424       sb = Strings.appendKeyValue(sb, "memstoreSizeMB",
425         Integer.valueOf(this.memstoreSizeMB));
426       sb = Strings.appendKeyValue(sb, "storefileIndexSizeMB",
427         Integer.valueOf(this.storefileIndexSizeMB));
428       sb = Strings.appendKeyValue(sb, "readRequestsCount",
429           Long.valueOf(this.readRequestsCount));
430       sb = Strings.appendKeyValue(sb, "writeRequestsCount",
431           Long.valueOf(this.writeRequestsCount));
432       sb = Strings.appendKeyValue(sb, "rootIndexSizeKB",
433           Integer.valueOf(this.rootIndexSizeKB));
434       sb = Strings.appendKeyValue(sb, "totalStaticIndexSizeKB",
435           Integer.valueOf(this.totalStaticIndexSizeKB));
436       sb = Strings.appendKeyValue(sb, "totalStaticBloomSizeKB",
437         Integer.valueOf(this.totalStaticBloomSizeKB));
438       sb = Strings.appendKeyValue(sb, "totalCompactingKVs",
439           Long.valueOf(this.totalCompactingKVs));
440       sb = Strings.appendKeyValue(sb, "currentCompactedKVs",
441           Long.valueOf(this.currentCompactedKVs));
442       float compactionProgressPct = Float.NaN;
443       if( this.totalCompactingKVs > 0 ) {
444         compactionProgressPct = Float.valueOf(
445             this.currentCompactedKVs / this.totalCompactingKVs);
446       }
447       sb = Strings.appendKeyValue(sb, "compactionProgressPct",
448           compactionProgressPct);
449       String coprocessors = Arrays.toString(getCoprocessors());
450       if (coprocessors != null) {
451         sb = Strings.appendKeyValue(sb, "coprocessors",
452             Arrays.toString(getCoprocessors()));
453       }
454       return sb.toString();
455     }
456   }
457 
458   /*
459    * TODO: Other metrics that might be considered when the master is actually
460    * doing load balancing instead of merely trying to decide where to assign
461    * a region:
462    * <ul>
463    *   <li># of CPUs, heap size (to determine the "class" of machine). For
464    *       now, we consider them to be homogeneous.</li>
465    *   <li>#requests per region (Map<{String|HRegionInfo}, Integer>)</li>
466    *   <li>#compactions and/or #splits (churn)</li>
467    *   <li>server death rate (maybe there is something wrong with this server)</li>
468    * </ul>
469    */
470 
471   /** default constructor (used by Writable) */
472   public HServerLoad() {
473     super();
474   }
475 
476   /**
477    * Constructor
478    * @param numberOfRequests
479    * @param usedHeapMB
480    * @param maxHeapMB
481    * @param coprocessors : coprocessors loaded at the regionserver-level
482    */
483   public HServerLoad(final int totalNumberOfRequests,
484       final int numberOfRequests, final int usedHeapMB, final int maxHeapMB,
485       final Map<byte[], RegionLoad> regionLoad,
486       final Set<String> coprocessors) {
487     this.numberOfRequests = numberOfRequests;
488     this.usedHeapMB = usedHeapMB;
489     this.maxHeapMB = maxHeapMB;
490     this.regionLoad = regionLoad;
491     this.totalNumberOfRequests = totalNumberOfRequests;
492     this.coprocessors = coprocessors;
493   }
494 
495   /**
496    * Constructor
497    * @param hsl the template HServerLoad
498    */
499   public HServerLoad(final HServerLoad hsl) {
500     this(hsl.totalNumberOfRequests, hsl.numberOfRequests, hsl.usedHeapMB,
501         hsl.maxHeapMB, hsl.getRegionsLoad(), hsl.coprocessors);
502     for (Map.Entry<byte[], RegionLoad> e : hsl.regionLoad.entrySet()) {
503       this.regionLoad.put(e.getKey(), e.getValue());
504     }
505   }
506 
507   /**
508    * Originally, this method factored in the effect of requests going to the
509    * server as well. However, this does not interact very well with the current
510    * region rebalancing code, which only factors number of regions. For the
511    * interim, until we can figure out how to make rebalancing use all the info
512    * available, we're just going to make load purely the number of regions.
513    *
514    * @return load factor for this server
515    */
516   public int getLoad() {
517     // int load = numberOfRequests == 0 ? 1 : numberOfRequests;
518     // load *= numberOfRegions == 0 ? 1 : numberOfRegions;
519     // return load;
520     return this.regionLoad.size();
521   }
522 
523   /**
524    * @see java.lang.Object#toString()
525    */
526   @Override
527   public String toString() {
528     return toString(1);
529   }
530 
531   /**
532    * Returns toString() with the number of requests divided by the message
533    * interval in seconds
534    * @param msgInterval
535    * @return The load as a String
536    */
537   public String toString(int msgInterval) {
538     int numberOfRegions = this.regionLoad.size();
539     StringBuilder sb = new StringBuilder();
540     sb = Strings.appendKeyValue(sb, "requestsPerSecond",
541       Integer.valueOf(numberOfRequests/msgInterval));
542     sb = Strings.appendKeyValue(sb, "numberOfOnlineRegions",
543       Integer.valueOf(numberOfRegions));
544     sb = Strings.appendKeyValue(sb, "usedHeapMB",
545       Integer.valueOf(this.usedHeapMB));
546     sb = Strings.appendKeyValue(sb, "maxHeapMB", Integer.valueOf(maxHeapMB));
547     return sb.toString();
548   }
549 
550   /**
551    * @see java.lang.Object#equals(java.lang.Object)
552    */
553   @Override
554   public boolean equals(Object o) {
555     if (this == o) {
556       return true;
557     }
558     if (o == null) {
559       return false;
560     }
561     if (getClass() != o.getClass()) {
562       return false;
563     }
564     return compareTo((HServerLoad)o) == 0;
565   }
566 
567   // Getters
568 
569   /**
570    * @return the numberOfRegions
571    */
572   public int getNumberOfRegions() {
573     return this.regionLoad.size();
574   }
575 
576   /**
577    * @return the numberOfRequests per second.
578    */
579   public int getNumberOfRequests() {
580     return numberOfRequests;
581   }
582   
583   /**
584    * @return the numberOfRequests
585    */
586   public int getTotalNumberOfRequests() {
587     return totalNumberOfRequests;
588   }
589 
590   /**
591    * @return the amount of heap in use, in MB
592    */
593   public int getUsedHeapMB() {
594     return usedHeapMB;
595   }
596 
597   /**
598    * @return the maximum allowable heap size, in MB
599    */
600   public int getMaxHeapMB() {
601     return maxHeapMB;
602   }
603 
604   /**
605    * @return region load metrics
606    */
607   public Map<byte[], RegionLoad> getRegionsLoad() {
608     return Collections.unmodifiableMap(regionLoad);
609   }
610 
611   /**
612    * @return Count of storefiles on this regionserver
613    */
614   public int getStorefiles() {
615     int count = 0;
616     for (RegionLoad info: regionLoad.values())
617     	count += info.getStorefiles();
618     return count;
619   }
620 
621   /**
622    * @return Total size of store files in MB
623    */
624   public int getStorefileSizeInMB() {
625     int count = 0;
626     for (RegionLoad info: regionLoad.values())
627       count += info.getStorefileSizeMB();
628     return count;
629   }
630 
631   /**
632    * @return Size of memstores in MB
633    */
634   public int getMemStoreSizeInMB() {
635     int count = 0;
636     for (RegionLoad info: regionLoad.values())
637     	count += info.getMemStoreSizeMB();
638     return count;
639   }
640 
641   /**
642    * @return Size of store file indexes in MB
643    */
644   public int getStorefileIndexSizeInMB() {
645     int count = 0;
646     for (RegionLoad info: regionLoad.values())
647     	count += info.getStorefileIndexSizeMB();
648     return count;
649   }
650 
651   // Writable
652 
653   public void readFields(DataInput in) throws IOException {
654     super.readFields(in);
655     int version = in.readByte();
656     if (version > VERSION) throw new IOException("Version mismatch; " + version);
657     numberOfRequests = in.readInt();
658     usedHeapMB = in.readInt();
659     maxHeapMB = in.readInt();
660     int numberOfRegions = in.readInt();
661     for (int i = 0; i < numberOfRegions; i++) {
662       RegionLoad rl = new RegionLoad();
663       rl.readFields(in);
664       regionLoad.put(rl.getName(), rl);
665     }
666     totalNumberOfRequests = in.readInt();
667     int coprocessorsSize = in.readInt();
668     for(int i = 0; i < coprocessorsSize; i++) {
669       coprocessors.add(in.readUTF());
670     }
671   }
672 
673   public void write(DataOutput out) throws IOException {
674     super.write(out);
675     out.writeByte(VERSION);
676     out.writeInt(numberOfRequests);
677     out.writeInt(usedHeapMB);
678     out.writeInt(maxHeapMB);
679     out.writeInt(this.regionLoad.size());
680     for (RegionLoad rl: regionLoad.values())
681       rl.write(out);
682     out.writeInt(totalNumberOfRequests);
683     out.writeInt(coprocessors.size());
684     for (String coprocessor: coprocessors) {
685       out.writeUTF(coprocessor);
686     }
687   }
688 
689   // Comparable
690 
691   public int compareTo(HServerLoad o) {
692     return this.getLoad() - o.getLoad();
693   }
694 }