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