tag:blogger.com,1999:blog-72355093820757567372024-03-29T07:07:50.273-07:00HBaseRandom HBase topicsLars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.comBlogger50125tag:blogger.com,1999:blog-7235509382075756737.post-5478479542254232932019-12-25T02:35:00.000-08:002020-02-10T07:33:52.274-08:00HBase, Phoenix - Local index optimizations with region pruning<b>By Lars Hofhansl</b> <br>
(Updated for clarity)<br>
<br>
<h3>
Why Local Indexes? </h3>
Local indexes are a powerful tool in the HBase/Phoenix toolbox. They are (1) naturally and cheaply transactional, they (2) avoid creating extra index tables, (3) provide the best write performance, and (4) they can small since they work uncovered in all cases (i.e. you do not have to include extra columns so that a query can be answered from only the index).<br>
<br>
<h3>
Problems with Local Indexes?</h3>
Local indexes work by maintaining an index per HBase region, each region has its own local index.<br>
<br>
At read-time, for a query along the index that means that each region of a table needs to be consulted. And even though the RPCs can be done in parallel and regions with no matching keys will be ruled out quickly, for large tables for 1000's or 10000's of regions this can cause many unnecessary RPC.<br>
<br>
Say we have the following simple table:<br>
<br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">CREATE TABLE T (pk1 INTEGER NOT NULL,</span></span><br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;"> pk2 INTEGER NOT NULL,</span></span><br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;"> v1 FLOAT,</span></span><br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;"> v2 FLOAT</span></span><br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;"> CONSTRAINT pk PRIMARY
KEY (pk1, pk2));</span></span><br>
<span style="font-size: small;"><br></span>
With the the following index:<br>
<br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">CREATE LOCAL INDEX L <b>T(v2)</b>;</span></span><br>
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><br></span></span>A query for the form:<br>
<br>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT ... FROM T WHERE v2 = ...</span><br>
<br>
Would now need to check each and every region of the table to see if there are any rows matching the v2 = ... condition.<br>
<br>
<h3>
Region Pruning</h3>
This is where <b>region pruning</b> comes into the picture.<br>
<br>
Can we rule out some of the regions by using other parts of the query? It turns out we can!<br>
<br>
There are currently two methods to do that.<br>
<br>
One is implemented in <a href="https://issues.apache.org/jira/browse/PHOENIX-3941">PHOENIX-3941</a>, and requires to declare the index in a specific way (assuming the same simple table):<br>
<br>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">CREATE LOCAL INDEX L <b>T(pk1, v2)</b>;</span></span><br>
<br>
Notice that we included the prefix of the pk (namely pk1) we'll use for extra pruning in the index definition. Now a query of the form<span style="font-family: "courier new" , "courier" , monospace;"> </span><br>
<br>
<span style="font-family: "courier new" , "courier" , monospace;">> SELECT ... FROM T WHERE v2 = ...</span><br>
<br>
will <b>not</b> be able to use the index!<br>
<br>
But if we provide a value (or range) for pk1 the query compiler can now <b>remove regions where this key is known not to be found</b>, as in<span style="font-family: "courier new" , "courier" , monospace;"> </span><br>
<br>
<span style="font-family: "courier new" , "courier" , monospace;">> SELECT ... FROM T WHERE v2 = ... AND pk1 = ...</span><br>
<br>
Phoenix does this by re-arranging the key structure of the local index.<br>
<br>
<span style="font-family: inherit;">Normally the key would look like this:</span><br>
<span style="font-family: inherit;">(INDEX_ID, <b>v2</b>, pk1, pk2)</span><br>
<br>
<span style="font-family: inherit;">The pk1 is included so that we can find the row once we found a match. With the rearrange index it now looks like this:</span><br>
<span style="font-family: inherit;"><span style="font-family: inherit;">(INDEX_ID, <b>pk1</b>, <b>v2</b>, pk2)</span></span><br>
<br>
Thus Phoenix can now use its algorithms for key range intersection along the (pk1, v2) key space to effectively limit how much scanning it needs to perform with the local index... Albeit at the expense that the index can only be used when querying along all declared index parts.<br>
<br>
<h3>
Can we do better?</h3>
Again, it turns out we can. See <a href="https://issues.apache.org/jira/browse/PHOENIX-5096">PHOENIX-5096</a> (will be in 4.16.0).<br>
<br>
(This was a long standing problem, but it turns out adding more pruning was ridiculously simple once the code was understood. All I had to do was filter the regions through the non-index query plan, and voilá.)<br>
<br>
Now we can declare the index naturally (same table definition): <br>
<span style="font-size: small;"><br></span>
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">CREATE LOCAL INDEX L <b>T(v2)</b>;</span></span><br>
<br>
And a query like: <br>
<br>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT ... FROM T WHERE v2 = ...</span><br>
<br>
would correctly use the local index - but ping every region of the table.<br>
<br>
But<br>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT ... FROM T WHERE v2 = ... AND pk1 = ...</span><br>
<br>
can still use the pk1 part of the query to rule out any region where we know for sure a key with this prefix cannot be found. <br>
<br>
So now the we can use and define the index as expected, <b>and</b> get the region pruning.<br>
<br>
PHOENIX-5096 and PHOENIX-3941 complement each other. If you know that you will always include a certain prefix of the row key you should define your indexes with the rearranged key structure.<br>
<br>
<h3>
Conclusion </h3>
<ul>
<li>Local indexes are an effective and perhaps overlooked tool in Phoenix.</li>
<li>At read time performance is impacted by the fact that all region need to be consulted.</li>
<li>Phoenix can automatically prune those regions by looking at other parts of the query.</li>
<li>If we know that we will always include certain parts of the PK we should include those in the local index definition (as prefix).</li>
<li>If we want to use a local index sometimes with, sometimes without knowing anything about part of the key, we can now rely on Phoenix to prune unnecessary regions. And this expands the areas where local indexes are useful.</li>
</ul>
<br>
<br>
<br>
<br>
<br>
<br>
<span style="font-family: "courier new" , "courier" , monospace;"></span><br>
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"></span></span>Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-1798356607305737212018-10-04T00:09:00.001-07:002018-10-04T10:31:09.647-07:00Apache HBase and Apache Phoenix, more on block encoding and compression<b>By Lars Hofhansl</b><br />
<br />
2 1/2 years ago I blogged about <a href="http://hadoop-hbase.blogspot.com/2016/02/hbase-compression-vs-blockencoding_17.html">HBase Compression vs Blockencoding</a>.<br />
<br />
Things have moved on since then. The Hadoop and HBase communities added new compression schemes like <a href="http://www.zstd.net/">zSTD</a>, and new block encoders like <a href="https://issues.apache.org/jira/browse/HBASE-16213">ROW_INDEX_V1</a>.<br />
<br />
<b>zSTD</b> promises to be fast and yield great compression ratios.<br />
The <b>ROW_INDEX_V1</b> encoder allows fast seeks into an HFile block by storing the offsets of all Cells in that block so a Cell can be found by binary search, instead of the usual linear search.<br />
<br />
So let's do some tests. Like in the previous blog I'm setting up a single node HBase, on a single node HDFS, with a single node ZK.<br />
(But note that these are different machines so do not compare these numbers to a two years old blog post)<br />
<br />
CREATE TABLE <table> (pk INTEGER PRIMARY key, v1 FLOAT, v2 FLOAT, v3 INTEGER) DISABLE_WAL=true, SALT_BUCKETS=8<br />
<br />
Then I loaded 2^22 = 4194304 rows. Columns v1 and v2 are random values from [0,1).<br />
<br />
Let's look at the size of the data. Remember this is just a single machine test. This is a qualitative test. We verified elsewhere that that this scales with adding machines.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> 88.5MB <b>ROW_INDEX_V1 + zSTD</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">112.1MB <b>ROW_INDEX_v1 + GZ</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">184.0MB <b>ROW_INDEX_V1 + SNAPPY</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">200.0MB <b>FAST_DIFF</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">556.9MB <b>NONE</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">572.9MB <b>ROW_INDEX_V1</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </span> <br />
So far, nothing surprising:<br />
<ul>
<li>The ROW_INDEX adds a bit more data (~3% for these small Cells).</li>
<li>zSTD offers the best compression, followed by GZ, and SNAPPY.</li>
<li>Uncompressed and unencoded HBase bloats the data a lot. </li>
</ul>
<br />
<ul>
</ul>
<h2>
Full scans: </h2>
Let's first do some scanning. First from the OS buffer cache (1), then from the HBase block cache (2).<br />
<br />
(1) SELECT /*+ NO_CACHE SERIAL */ COUNT(*) FROM <table><br />
(2) SELECT /*+ SERIAL */ COUNT(*) FROM <table><br />
<br />
I'm using the SERIAL hint in Phoenix in order to get consistent results independently of how Phoenix decides to parallelize the query (which is based on region sizes as well the current stats).<br />
<img src="data:image/png;base64,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" /><br />
<ul>
<li>zSTD decompression rate is pretty good, closer to Snappy than to Gzip.</li>
<li>ROW_INDEX - as expected - does not help with full scans, but it also dos not seem hurt (variance was within the noise). </li>
<li>FAST_DIFF has the worst scan times, whether data is in the block cache or not. </li>
</ul>
<br />
<ul>
</ul>
<h2>
Where do we seek a lot with Phoenix? </h2>
<ul>
</ul>
ROW_INDEX_V1 helps with random seeks, but where do we do this in Phoenix. Some areas are obvious, some might surprise you: <br />
<ul>
<li>SELECT on random PKs. Well Dah...</li>
<li>Reverse Scans</li>
<li>Scans through tables with lot of deleted rows (before they are compacted away) </li>
<li>Row lookup from uncovered indexes</li>
</ul>
<ul>
</ul>
<h3>
</h3>
<h3>
Point Gets:</h3>
So let's start with random gets, just point queries like these. To avoid repeated meta-data lookup I re-configured the table with UPDATE_CACHE_FREQUENCY = NEVER. And then issued:<br />
<br />
SELECT pk FROM <table> WHERE pk = <random pk>, 1000 times.<br />
<img src="data:image/png;base64,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" /> <br />
So now we see how ROW_INDEX_V1 helps, GETs are improved by 24% and remember that this is <b>end-to-end</b> (query planning/compilation, network overhead, and finally the HBase scan).<br />
We also see the relative decompression cost the schemes are adding (the OS buffer cache case).<br />
<br />
Yet, zSTD decompression, seems to be on par with FAST_DIFF, and almost as fast as SNAPPY, while providing vastly better compression ratios.<br />
<br />
Also remember that default blocks are stored uncompressed in the block cache (so all ROW_INDEX block cache requests are the same performance). <br />
<br />
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
Reverse Scans:</h3>
HBase offers reverse scans, Phoenix will automatically make use of those in queries like these: <br />
<br />
SELECT * FROM <table> ORDER BY pk DESC LIMIT 100;<br />
<img src="data:image/png;base64,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" /><br />
<br />
(Everything is in the block cache here)<br />
<br />
Reverse scanning involves a lot of seeking. For each Cell (i.e. each column in Phoenix) we need to seek the previous row, then skip forward again for the columns of that row. We see that ROW_INDEX_V1 is 2.5x faster than no encoding and over 6x faster compared to FAST_DIFF.<br />
<br />
<h4>
99.9% of cells deleted:</h4>
When HBase deletes data, it is not actually removed immediately but rather marked for deletion in the future by placing tombstones.<br />
<br />
For this scenario I deleted 99.9% of the rows:<br />
DELETE FROM <table> WHERE v1 < 0.999 <br />
<br />
Then issued:<br />
SELECT /*+ SERIAL */ COUNT(*) FROM <table><br />
<br />
<br />
<img src="data:image/png;base64,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" /> <br />
<br />
We see that ROW_INDEX_V1 helps with seeking past the delete markers. About a 24% improvement.<br />
<br />
<br />
Now what about reverse scanning with lots of delete marker? <br />
SELECT * FROM <table> ORDER BY pk DESC LIMIT 100<br />
<br />
<img src="data:image/png;base64,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cw5qAVgc1r0935prf1L/+nDE323iZFdM+U0jac+F9aIU5o+AFVDWTTSvATPTocrlE7+pfXPnx4D116smGvO16tT7bvh4TNVHRvX25iHt+SqqhwPj+utV9s+NIQPYsO7tRZmVf/7vz6vs14XZlz0ErICybqI5a5ZDlZNbsLrvTd+C9erq1IEzeXnLyiN6HBnXO/w9LmDJsu7txap0R1a/iIX5I2AFlHUTzadmOlT5lfKI3tkyrL7BiX2wXglP7K81NKaU/at+UhHRpk/G/OGzrDyi+0/HJ74mDMDzY8gA2Wfd2xSzzxUCVkBZN9FcNeuhyuGJ8PTg6bjCLaP66cqIWtqjOn1l+s6dNx4kVH1kVP+pPKLS/aP64dm4v59WkAvA4rDubYrZ5woBK6Csm2jOmuVQ5b8qm7ju99uH9f3DhCKj0oXv43pj3VDqocrlEf2PTUP65k5CQ2PSjQcJ/euOYS0rZyd3YKmy7m2K2ecKASugrJtoPjXbocppj6qZeqjyn28/r+UGrAAsDuvepph9rhCwAsq6ieZbsx2qPPlP47yS5lDl5OWvpLl90AvA4rDubYrZ5woBK6Csm2gxikOVAczFurcpZp8rBKyAsm6ixSoOVQYwG+vepph9rhCwAsq6iSiGDGDBurcpZp8rBKyAsm4iiiEDWLDubYrZ5woBK6Csm4hiyAAWrHubYva5QsAKKOsmohgygAXr3qaYfa4QsALKuokohgxgwbq3KWafKwSsgLJuIoohA1iw7m2K2ecKASugrJuIYsgAFqx7m2L2uULACijrJqIYMoAF696mmH2uELACyrqJKIYMYMG6tylmnysErICybiKKIQNYsO5titnnCgEroKybiGLIABase5ti9rlCwAoo6yaiGDKABevepph9rhCwAsq6iSiGDGDBurcpZp8rBKyAsm4iiiEDWLDubYrZ5woBK6Csm4hiyAAWrHubYva5QsAKKOsmohgygAXr3qaYfa4QsALKuokohgxgwbq3KWafKwSsgLJuIoohA1iw7m2K2ecKASugrJuIYsgAFqx7m2L2uULACijrJqIYMoAF696mmH2uELACyrqJKIYMYMG6tylmnysErICybiKKIQNYsO5titnnCgEroKybiGLIABase5ti9rlCwAoo6yaiGDKABevepph9rhCwAsq6iSiGDGDBurcpZp8rBKyAsm4i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" /> <br />
WOW... Reverse scanning with deleted Cells is somewhat of a worst case for HBase, we need to seek backwards Cell by Cell until we find the next non-deleted one.<br />
<br />
ROW_INDEX_V1 makes a huge difference here. In fact without it, just scanning 100 row reverse is almost four times slower than scanning through all 4m rows plus almost 4m delete markers.<br />
<br />
If you have lots of deletes in your data set, for example if it is churning set, you might want to switch the encoding to ROW_INDEX_V1.<br />
<br />
<h3>
Local Secondary (uncovered) Indexes:</h3>
Still 2^22 rows...<br />
<br />
Now we have two decisions to make: (1) how to encode/compress the main column family, and (2) how to encode/compress the local index column family. In the interest of brevity I limited this to three cases:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">308.1MB <b>FAST_DIFF, FAST_DIFF</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">195.8MB <b>RI + zSTD, FAST_DIFF</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">170.9MB <b>RI + zSTD, RI + zSTD</b></span><br />
<br />
Let's first do a full scan: <br />
SELECT /*+ SERIAL */ COUNT(*) FROM <table><br />
<img src="data:image/png;base64,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" /><br />
<br />
Looks like this is now purely driven by the size of the index, as expected, since Phoenix now scans along the index, rather than the main data. <br />
<br />
<br />
Let's do some filtering. <br />
<br />
SELECT /*+ SERIAL */ COUNT(*) FROM <table> WHERE v2 < p<br />
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAFzCAYAAADi5Xe0AAAgAElEQVR4nO3deXAcd2Pe+flnk3U5iZPNJk5ldxO7alOJU0mlHJclxymvLYnvmfdd2/HxJmW/Tl4n9huv7SQbp3EJBwkOQIICSBAgIFIALwgQD0iESIoEFYkSJR4iRZAgRBI8QEIkcRAHRQLg4JjBzDz5A5omBhgMfjPsQTeA76eqS8T0HN09j379oKen4RMAAAAc5XN7AQAAAFYaChYAAIDDKFgAAAAOo2ABAAA4jIIFAADgMAoWAACAwyhYAAAADqNgAQAAOIyCBQAA4DAKFgAAgMMoWAAAAA6jYAEAADiMggUAAOAwChYAAIDDKFgAAAAOo2ABAAA4jIIFAADgMAoWAACAwyhYAAAADnO8YN2/f1+WZamxsdHpp1ZOTo42bdrk+POaiEQiOn36tCorK5WXl6dXX31VW7Zs0ccff6zp6WlXlskpn332mfLy8tTZ2en2oqRt//79sixLDx8+dHtRUvLRRx/Jsix1dHS4tgzP8/6vhOwAQCZQsAyEw2Ht2LFDlmWppKREjY2Neuutt1RWVibLsrRlyxZNTU0t+XKl6oMPPtC5c+fm3f7hhx/Ksiy1tbW5sFTOoGAtLhPv/0KPXei1AGC1oGAZOH36tCzL0ptvvqlwOGzfHolEdPjwYVmWpZaWliVfrlRlZWVp8+bNCecFAoElXhpnUbAWl6n3P9Fjk70WAKwGFCwD9fX1sixLDx48mDcvHA4rLy9P+fn5S75cqVrJOz0K1uKW8v1fyVkDABNLUrBiO7/h4WEdOXJExcXFysvLU1VVlbq6uuY9x9jYmPbt26fCwkLl5eVp+/btevDgQcKCFY1Gdfr0ab322mvKycmR3+/X4cOHNTk5ad+nr69P2dnZ2rhxY9z5UqOjo8rPz1dBQYFGR0cXXKdYwUq0rJJ0+fJlnTlzJu7oVigU0vvvv6+ysjLl5ORo/fr1OnTokMbHx+Me++jRIx04cEDr169XTk6ONm7cqKNHj8YtfzrbcLZ169bJsqy4qbKy0p6faCf/1ltvybIsDQwM6MCBA1q7dq1yc3O1detW+/UuXryoiooK5ebmasOGDTp27JhCodC81zd5j2IGBwfV0NCg9evX2+e5nT9/XpFIJOk6xrZPV1eX9u/fr6KiIuXm5qqmpkbd3d32/Zqbm2VZltrb2+c9R2lpqbKzszUxMbHg65gun+k6L1SwUtlmi2Ut1ff//fffX7D07d69W5Zl6dGjRwkfm+y1nnfbA8BysqQFa9OmTfL7/dq/f79dWnJycvT48WP7vlNTU9q0aZN9blNzc7NqamqUl5enrKysuIIVjUbV0NAgy7JUXV2tw4cP6/XXX5dlWaqqqorb6R07dkyWZenkyZP2bU1NTbIsS5999lnSdTp37py9/IODg4tug3A4rOrqanu53n33Xb3xxhv2c8R2kg8fPlRBQYHy8vK0f/9+tba22tvl9ddfVzQaTWsbzvX555/rzJkzysrK0vr163XmzBlduXLFnp+sYK1du1aVlZU6ePCgamtrZVmWcnNz1dzcrOzsbO3evVv79u3T+vXrZVmW3n333bjXTuU96u/vt79AcODAAb377rsqLS2VZVlqbm5Ous1j26eoqEgbN27UgQMHtH37dnv7xI4+3r17V5Zlae/evXGPf/jwoSzL0q5duxZ8DdPlS2WdE237VB5vkrVU3/+hoaGER6FDoZBdshd6bLLXep5tDwDLzZIWrB07dsQd4YgNzh988IF9W+y354MHD8YVjNh5ULML1ueffy7LsnTo0KG4+7a0tMiyLH3++ef2baFQSBs3blReXp5GRkbU3d0ty7JUU1MT99hEIpGI3nzzTVmWpaysLO3atUuXL19e8MT22HodOXIk7vaTJ0/KsiydOHFCknT48GGtW7du3hGoAwcOyLIsffnll2ltw4Us9LFNsoJ16NChuPseP37c3g537tyxb5+YmLCPGs3enqm8RwcPHpRlWbp586Z929TUlDZu3CjLsjQyMrLgusW2z969e+MKyMWLF+33WZopL36/X3l5eXHbMfbeXL58ecHXMF2+VNY50bZP5/GLZU1K7f2vrKxUfn5+3BHfL774QpZl6ZNPPkn62IVe63m2PQAsN0tasHp6euLuG/vN9cCBA/ZtmzZtUlZWVsKd6dyPCKuqqpSdnT3vY5PR0VFZlqU9e/bE3X779m37ZPWKigrl5OQYHZGKaW9vV0VFhf3RR25urt5++22NjY3F3W/Tpk169dVX5y3X9PS0Nm3apKampoTPHw6HNTExYZfJ8+fP2/NS2YYLSadgzT2nqaenJ66wzBb7+Gj20bRU3qPYEcXZxVKSHjx4oI6Ojnkfr84W2z59fX3z5m3e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" /><br />
<br />
Pretty much as expected. The index encoding is what counts, and differences are marginal.<br />
<br />
<br />
Next: The indexes I created are uncovered, they include only the indexed column(s) but no other columns. So now when we include some columns not in the index Phoenix needs to retrieve those as well.<br />
<br />
SELECT /*+ SERIAL */ COUNT(v1) FROM <table> WHERE v2 < p;<br />
<img src="data:image/png;base64,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" /> <br />
<br />
Again... Wow... We see a huge difference. Phoenix' default FAST_DIFF, FAST_DIFF is almost useless. Look back at the full scan times in the beginning. We can conclude that unless the index returns less than 0.5% of the rows a full scan is faster!<br />
<br />
Why's that!? Well, for each row we need find the remainder of the row (at least a part of it). All we have for that in HBase is a GET. Each GET needs to SEEK into the relevant blocks and a SEEK with FAST_DIFF implies SEEKing the last full key before the key we're looking for and then forward to the actual key. That's quite expensive.<br />
<br />
When we switch the encoding to ROW_INDEX_V1 the GET can now instead be served with a binary search this the Cell offset in the blocks are known. Now index queries that return up to 10% of the Cells are still faster than a full scan.<br />
<br />
Since ROW_INDEX_V1 add so little storage overhead I did not test with no encoding.<br />
<br />
<h2>
Takeaways:</h2>
<ul>
<li>ROW_INDEX_V1 does not add much overhead but can potentially very helpful.</li>
<li>If you use uncovered local indexes (which you should, since all other cases will ust blow up the data), you <i>must</i> configure the main table with ROW_INDEX_V1 or the related row lookup is simply too slow.</li>
<li>zSTD provides an excellent compromise between compression ratio and decompression speed (I didn't test compression speed). It should probably be the default.</li>
<li>ROW_INDEX_V1 together with zSTD compression make for an great default for a wide range of use cases. </li>
</ul>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-7582685644816881592018-10-01T21:03:00.000-07:002018-10-01T21:03:36.035-07:00More on HBase data locality<b>By Lars Hofhansl</b><br />
<br />
<div class="post-title entry-title" itemprop="name">
Warning: General topic ahead. </div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Over five years ago I posted <a href="http://hadoop-hbase.blogspot.com/2013/07/hbase-and-data-locality.html">HBase and data locality</a>, summarizing how important data locality is and how HBase ensures it.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
A lot has changed since then. We now have typically less than 0.1ms network latency inside a site (a datacenter) and 10Ge and even 40Ge or 100Ge networks are commonplace - without oversubscription at the ToR and Spine switches or at the fabric.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Meanwhile rotating disks still show 4 - 15ms latency and 120-140MB/s throughput.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Even SSDs typicaly have 0.08 to 0.16ms of "seek" times, and the drive-to-host data transfer is often limited to 300MB/s (10bit encoding over 3.0GBit/s SATA).</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
(The usual disclaimer: I'm not a H/W guy... But these number are ballpark correct.)</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
So a 10Ge link can comfortably serve from a remote machine with 10 HDDs or 4 SSD at full throttle. With a 40Ge networks or better we just do not need to think about this anymore.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
So... I think it's safe to say that <b>Data Locality No Longer Matters!</b></div>
<div class="post-title entry-title" itemprop="name">
What still matters is <b>cache locality</b> (bandwidth between RAM and CPU is still better than the network, 40GB/s or more.) I.e. that HBase still has its block cache local to the RegionServers.<b> </b></div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Instead we should focus on untangling storage from compute going forward. Unlike storage, (stateless) compute is elastic; we can grow and shrink it on demand. Only storage (HDFS in our case, or S3 on AWS or GCS on GCP) need to be carefully managed.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
That allows us to manage required storage in new ways (pick storage dense machines or VMs) or even outsource storage to the likes of S3 or GCS, while allowing us to choose CPU/RAM heavy machines or VMs for out compute needs. Note that both <b>HBase and Phoenix are compute</b>. So are MapReduce and Spark.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
The Spark community has seen this trend years ago and Spark comfortably works over purely remote storage.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
The older MapReduce as a programming paradigm is still relevant. As a means to bring the compute to the data, it is outmoded and no longer needed or desired.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
For <b>HBase</b> it means that instead of running the HBase RegionServers and the HDFS DataNodes on the same machines/VMs, and have HBase try to maintain data locality - as in the five year old post above - we should pick our storage and compute options separately and optimize each independently, and rely on a fast network between them.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
My team and I will soon look into how we can increase the elasticity of HBase, make it easier to grow and shrink the set of RegionServer dynamically quickly with low overhead.</div>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-84848047520803894412017-07-24T06:36:00.000-07:002017-07-24T06:36:22.697-07:00Poor-mans sampling in HBase and Phoenix<b>By Lars Hofhansl</b> <br />
<br />
Sampling is an important feature when lots of data is (are?) involved.<br />
<br />
In HBase this is traditionally tricky, as there is no notion of the n-th key without actually reading n key values from disk. IO is usually the bottleneck.<br />
<br />
As it turns out there is a simple trick, involving a separate column family and HBase's "essential column family" <a href="https://issues.apache.org/jira/browse/HBASE-5416">feature</a>.<br />
<br />
The trick is now to randomly write a value (any value) or nothing to separate column family, then scan along that column family - which is possible as long as the filter only apply to column in that column family - and let HBase/Phoenix load the other column families as needed. <br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">CREATE TABLE <table> (mykey INTEGER NOT NULL PRIMARY KEY, A.cola INTEGER, B.colb INTEGER)</span><br />
<br />
Now you UPSERT with a certain randomness (<span style="font-family: "Courier New",Courier,monospace;">Math.Random r; r.nextFloat() < 0.0001</span>, for 0.01% sampling):<br />
UPSERT INTO <table> VALUES(?,?,?)<br />
<br />
And otherwise this: <br />
UPSERT INTO <table> VALUES(?,?)<br />
<br />
So now, as long as you do not update existing values, you get rows in HBase where with a 0.1% chance B.colb has a non-null value. We can use that fact now for our sampling by adding <span style="font-family: "Courier New",Courier,monospace;">WHERE colb IS NOT NULL</span> to our queries.<br />
<br />
The queries are:<br />
<ol>
<li>SELECT COUNT(*) FROM <table></li>
<li>SELECT COUNT(*) FROM <table> WHERE colb IS NOT NULL</li>
<li>SELECT COUNT(cola) FROM <table> WHERE colb IS NOT NULL </li>
</ol>
Query #1 performs a simple full scan. Query number #2 scans along the sampled column only. Query #3 scans along the sampled column, and then brings in the matching parts of the row from the other column family, this will likely be the most likely scenario.<br />
<br />
Now: <br />
<img src="data:image/png;base64,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" /><br />
<br />
As you can see, this kind of sampling is no longer useful when the
selectivity approaches 20% or worse. In real-world scenarios 0.1% or less is
probably prudent anyway.<br />
Also note that a full scan across the table is not entirely free, the relevant parts of the sampled column also need to be scanned, though the difference is minimal. <br />
<br />
Zoomed into the more useful range:<br />
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAFzCAYAAADi5Xe0AAAgAElEQVR4nO3d3VqTZ77H8TmGdQSzu7Zmo1vrGGZ25iTWGQQReSuQFgTUYkEZa8VBrA22vqCOl3jp1OLIINJFVQQFKqWggBWJSJCX/NaGF88EbiQRk+efG76f63o2Ql4M4f9wfw1Pkj8IAAAAWfUH6zsAAACw0xBYAAAAWUZgAQAAZBmBBQAAkGUEFgAAQJYRWAAAAFlGYAEAAGQZgQUAAJBlBBYAAECWEVgAAABZRmABAABkGYEFAACQZQQWAABAlhFYAAAAWUZgAQAAZBmBBQAAkGUEFgAAQJYRWAAAAFmW88AaHR1VXV2diouLdezYMc3NzW16ubt37+qzzz5TcXGxvv76a71+/TrXdw0AAGQg/mZFzR2TGW2nr08p/mbF+i6by2lgra6uqqKiQn19fUokEmpvb1dbW5tzuefPn6u0tFS//fabFhcXFYvF1N7ensu7BgAAMnT04oQ++d/ejLe261NpbzMej+vEiRMqKipSSUmJYrGYlpaWtn35eDyu3t5etbW1qaKiwrl+Z2enSkpKdPDgQc3MzGzvgfgAOQ2s8fFxRaPR4PT09LRKS0udy718+VJDQ0PB6UePHqmhoSGXdw0AAGToQwPr6MWJtLd5/PhxNTU1aWZmRhMTE6qpqVFHR8e2L19XV6fm5mbFYjEVFBSsu+7MzIyqq6v1+vVr3bp1K3iyZ3p6WmfOnNnmo7K1nAbWwMCADh8+HJxeXFxUJBLZslDfvHmj1tZW/eMf/8jlXQMAABnKdmAlEgkVFBRodHQ0+Fp3d7eqqqq2ffm1thgcHHQCa2hoSK2trZLe/dWsoaFByWRSR44c0cjIyIc9GBnKaWD19/ersbExOL28vKxIJKKFhYVNL3/s2DFFIhFVV1e/9zIAACBc2Q6syclJRSKRdcdbDw8PKxKJaGXFPX7rQy6/WWClPoPV1dWlU6dO6c6dOzp79ux2Ho6M5PwZrNQ/9a09g7W8vPze6yQSCZ0/f14tLS3vvczk5KR6e3vZ2NjY2NjYUrbJycmsruNrsh1YY2NjikQiWlxcDL42Pj6uSCSiRCLxUZffLLCk/xyDdeDAAQ0PD6u2tnbTfytbchpYExMTqqysDE5PTU1tegzW1NSUhoeHg9PPnz9XeXl5Lu8aAADI0E4IrFQtLS26f/++vv32W+3bt0/Nzc1Z/8tZzl9FGI1G1dPTo0QioVgstu5gsvHxcUnv3srh008/1eTkpN6+fauOjg4dP348l3cNAABkKFd/Ikx966aRkZG0fyLM5PLpAqu/v1+tra0aGBhQU1OTEomEzp07p87Ozkwfjozk/H2wnj59qvr6+uB9sOLxuKR3B7OXl5cHp7u6uhSNRlVUVKSvvvpKs7Ozub5rAAAgA9kOrLdv32rPnj168uRJ8LXu7u517zyw3ctvFVgLCwuqra1VPB5XV1eXrly5Ikl6+PBh1l9NyDu5AwCALeXibRpOnjypL7/8Ui9evNCzZ89UU1Ojy5cvB+f39fXpxYsXGV9+zVaB1d3drZ6eHkla9wzWhQsXdO3atQ99WLZEYAEAgC3lIrDm5+fV0tKioqIiFRcXKxaLrXsR3P79+3Xnzp2ML78mk2OwJCmZTPp7DBYAAPBfLgJrpyOwAADAluJvVnT04kTGG59FSGABAABkHYEFAACQZQQWAMA1cVNq+6PU/If829r++O7+AXmMwAIAuPI1rlIjC8hjBBYAwGUdUJlsQB5jQgEALut4IrDgOSYUAOCyjicCC55jQgEALut4IrDgOSYUAOCyjicCC55jQgEALut4IrDgOSYUAOCyjicCC55jQgEALut4IrDyymr8lV5+VZPR9urMEa3GX1nfZXNMKADAZR1PBFZe+f1YtYb/578y3l6daUp7m/F4XCdOnFBRUZFKSkoUi8W0tLS05eV7e3vV1tamioqKD769zs5OlZSU6ODBg5qZmdneA/EBmFAAgMs6ngisvPKhgfX7seq0t3n8+HE1NTVpZmZGExMTqqmpUUdHx3svX1dXp+bmZsViMRUUFHzQ7c3MzKi6ulqvX7/WrVu31NbWJkmanp7WmTNntvmobI0JBQC4rOOJwMor2Q6sRCKhgoICjY6OBl/r7u5WVVXVe6+z9mzU4OCgE1jpbm9oaEitra2SpOfPn6uhoUHJZFJHjhzRyMjIhz0YGWJCAQAu63gisPJKtgNrcnJSkUhEr1+/Dr42PDysSCSilZWVLa+7WWClu73UZ7C6urp06tQp3blzR2fPnt3Go5EZJhQA4LKOJwIrr2Q7sMbGxhSJRLS4uBh8bXx8XJFIRIlEYsvrbhZYmdze2jFYBw4c0PDwsGpra9P+Wx+DCQUAuKzjicDKKzshsFK1tLTo/v37+vbbb7Vv3z41NzdrYWEhk4ciY0woAMBlHU8EVl7J1Z8I5+bmgq+NjIx89J8IM7m9/v5+tba2amBgQE1NTUokEjp37pw6OzszfTgywoQCAFzW8URg5ZVsB9bbt2+1Z88ePXnyJPhad3e3otFo2vuyWWBlensLCwuqra1VPB5XV1eXrly5Ikl6+PBh1l9NyIQCAFzW8URg5ZVcvE3DyZMn9eWXX+rFixd69uyZampqdPny5eD8vr4+vXjxwrneZoGVye1J76Krp6dHktY9g3XhwgVdu3btQx+WLTGhAACXdTwRWHklF4E1Pz+vlpYWFRUVqbi4WLFYTMvLy8H5+/fv1507d5zrvS+w0t3eRslkkmOwAAAhs44nAiuv5CKwdjomFADgso4nAiuvrMZf6fdj1RlvfBYhgQUA2Ix1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgZVf3s5KveWZbT8fenf5XY4JBQC4rOOJwMovvWUf9rP5+WDam4zH4+rt7VVbW5sqKiqc8zs7O1VSUqKDBw9qZmYmB99UbjGhAACXdTwRWPnlQwOrtyztTdbV1am5uVmxWEwFBQXrzpuZmVF1dbVev36tW7duqa2tTZI0PT2tM2fO5OAbzD4mFADgso4nAiu/5CCwlpaWJEmDg4NOYA0NDam1tVWS9Pz5czU0NCiZTOrIkSMaGRnJ9neXE0woAMBlHU8EVn7JQWCt2SywUp/B6urq0qlTp3Tnzh2dPXs2u99XDjGhAACXdTwRWPkl5MCS/nMM1oEDBzQ8PKza2lolEonsfU85xoQCAFzW8URg5ReDwErV0tKi+/fv69tvv9W+ffvU3NyshYWFj/uecowJBQC4rOOJwMovhoHV39+v1tZWDQwMqKmpSYlEQufOnVNnZ+fHf185xIQCAFzW8URg5RejwFpYWFBtba3i8bi6urp05coVSdLDhw/z/tWETCgAwGUdTwRWfjEKrO7ubvX09EjSumewLly4oGvXrmXhG8sdJhQA4LKOJwIrvxgfgyVJyWSSY7AAAJ6zjicCK7/kMLB2KiYUAOCyjicCK7+8nX0XTZlufBYhgQUA2IR1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXPMaEAAJd1PBFY8BwTCgBwWccTgQXP5XxCR0dHVVdXp+LiYh07dkxzc3ObXu7evXuqrq5WUVGRjh49qhcvXuT6rgEA3sc6nggseC6nE7q6uqqKigr19fUpkUiovb1dbW1tzuUmJiZUVlamsbExLS4uKhaL6auvvsrlXQMAbMU6nggseC6nEzo+Pq5oNBqcnp6eVmlpqXO5kZERdXV1BaefPn2q6urqXN41AMBWrOOJwILncjqhAwMDOnz4cHB6cXFRkUhES0tLW17v5s2bisViubxrAICtWMcTgQXP5XRC+/v71djYGJxeXl5WJBLRwsLCe6/z22+/qbKyUq9evcrlXQMAbMU6nggseC7nz2A1NDQEp9eewVpeXt708rOzs4pGo3r8+PGWtzs5Oane3l42NjY2thxt5vGUwWb9GOXjNjk5mdV1HNuX08CamJhQZWVlcHpqamrTY7AkKZFIqL6+Xvfu3cvlXQIAZCIPAopnsOCznE7o6uqqotGoenp6lEgkFIvFdObMmeD88fFxSdLKyoqOHj2qmzdv5vLuAAAyZR1PBBY8l/MJffr0qerr64P3wYrH45KkN2/eqLy8XPF4XI8ePVIkEnG2gYGBXN89AMBmrOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4rOOJwILnmFAAgMs6nggseI4JBQC4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" /> <br />
Note that we're approaching the timer resolution as well as the static planning cost of the Phoenix queries.<br />
<br />
So here's another test with 10m rows and 0.1% and 0.01% sampling.<br />
<b>A full scan now takes 6.9s.</b> <br />
<br />
<img src="data:image/png;base64,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YMVisXyuHgAUBNuhwxEswJT3TxGGw2ENDg7K931FIhFduHAhuD0ajQb/ferUKV27dk2+7+v27dtqbm7O56oBQMGwHToEFmDK+3WwZmdn1dTUFFwHa+eo1Pr6uiorK4P5lZUVffXVVzp69KhOnjypxcXFfK8aABQE26FDYAEmruQOAI6zHToEFmAisADAcbZDh8ACTAQWADjOdugQWICJwAIAx9kOHQILMBFYAOA426FDYAEmAgsAHGc7dAgswERgAYDjbIcOgQWYCCwAcJzt0CGwABOBBQCOsx06BBZgIrAAwHG2Q4fAAkwEFgA4znboEFiAicACAMfZDh0CCzARWADgONuhQ2ABJgILABxnO3QILMBEYAGA42yHDoEFmAgsAHCc7dAhsAATgQUAjrMdOgQWYCKwAMBxtkOHwAJMBBYAOM526BBYgInAAgDH2Q4dAgswEVgA4DjboUNgASYCCwAcZzt0CCzARGABgONshw6BBZgILABwnO3QIbAAE4EFAI6zHToEFmAisADAcbZDh8ACTAQWADjOdugQWICJwAIAx9kOHQILMBFYAOA426FDYAEmAgsAHGc7dAgswERgAYDjbIcOgQWYCCwAcJzt0CGwABOBBQCOsx06BBZgIrAAwHG2Q4fAAkwEFgA4znboEFiAicACAMfZDh0CCzARWADgONuhQ2ABJgILABxnO3QILMBEYAGA42yHDoEFmAgsAHCc7dAhsAATgQUAjrMdOgQWYCKwAMBxtkOHwAJMBBYAOM526BBYgInAAgDH2Q4dAgswEVgA4DjboUNgASYCCwAcZzt0CCzARGABgONshw6BBZgILABwnO3QIbAAE4EFAI6zHToEFmAisADAcbZDh8ACTAQWADjOdugQWICJwAIAx9kOHQILMBFYAOA426FDYAEmAgsAHGc7dAgswERgAYDjbIcOgQWYCCwAcJzt0CGwABOBBQCOsx06BBZgIrAAwHG2Q4fAAkwEFgA4znboEFiAicACAMfZDh0CCzARWADgONuhQ2ABJgILABxnO3QILMBEYAGA42yHDoEFmAgsAHCc7dAhsAATgQUAjrMdOgQWYMp7YM3MzKixsVGhUEidnZ1aXV1Nu/yzZ89UVFSkiYmJfK8aABQE26FDYAGmvAZWIpFQVVWVRkZG5Pu+ent71dPT897lk8mkWltbFQqFCCwAyJLt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" /><br />
In conclusion... Sampling this way at 0.01% (or 1/10000) can return queries at 70x the speed. For larger datasets in the billions, one would probably sample even less.<br />
<br />
Remember this is poor-mans sampling! Things need to be setup at write time - although you can retrofit existing data. The HBase and Phoenix communities are working on "real" solutions. For example <a href="http://phoenix-153/">PHOENIX-153</a>.<br />
<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-86065624531316078522016-10-04T11:59:00.001-07:002016-10-04T17:01:10.906-07:00Experiments with HBase, Phoenix, and SQL at Scale<b>By Lars Hofhansl</b><br />
<br />
For a short time we have a large Hadoop/HBase/Phoenix cluster at our disposal before it will be handed off to its designated use. Many 100's of machines, many 1000's of cores, many dozen TB of aggregate ram. (not at liberty to state the exact size of the cluster, nor its exact H/W configuration).<br />
<br />
We decided to use this opportunity to perform some semi-scientific tests of Phoenix and HBase at scale to see how much of the hardware we can actually utilize and drive for single queries.<br />
<br />
For that we loaded the TPC-H LINEITEM table with 600m and 6bn rows, respectively.<br />
<br />
The 600m table uses about 372GB of data (176GB on disk after FAST_DIFF encoding), the 6bn row table measured 4.3TB (1.65TB on disk). While not a lot of data at all for this type of cluster (it all fits <i>easily</i> in the HBase block cache) it none-the-less lets us gauge how Phoenix and HBase can scale their workloads across the cluster.<br />
<br />
We performed the following queries over the data:<br />
<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">SELECT COUNT(*) FROM T;</span><br />With we measure the scan performance</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">SELECT COUNT(*) FROM T WHERE l_quantity < 1000;</span><br />Here we measure scan performance with a simple aggregate</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">SELECT * FROM T ORDER BY l_extendedprice;</span><br />Terrasort anyone? (we canceled the query as soon as the first result is returned, in to measure the sort performance)</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">SELECT COUNT(*) FROM T, J WHERE l_extendedprice = k1;</span><br />Measure how Phoenix' join operator scales</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">SELECT COUNT(*) FROM T WHERE l_extendedprice = <x>;</span><br />With and without a local index.</li>
</ul>
<div>
<br /></div>
<h4>
The Good</h4>
<div>
<ol>
<li>We were able to drive 1000's of cores by sizing Phoenix' client threadpool accordingly. HBase does not have a fully supported asynchronous client, so many threads are needed not doing any actual work, but just triggering work on the RegionServers and waiting for the results.</li>
<li>Phoenix uses guide-posts to break work down in chunks smaller then a region, and as we increased the number of threads the performance scaled linearly with it, utilizing the cores on the servers - for queries that can be scaled that way that is.</li>
<li>HBase did a good job of automatically splitting the data and distributing it over the cluster. We found that as long as the data fits into the aggregate cache it did not matter how many regions (and hence server) were involved, indicating there's a potentially for crunching _way_ larger data sets with a single client. There was room to run larger queries and multiple queries at the same time.</li>
<li>Phoenix can sort 4.3TB in 26.4s, engaging 1000's of cores on 100's of machines.</li>
<li>A LOCAL index over 4.3TB is created in 1 minute. Even with many region it was still effective in reducing the query times significantly.</li>
<li>Due to the chunking and chunk queuing when a query is executing, resource allocation is surprisingly fair.</li>
</ol>
<h4>
Numbers:</h4>
</div>
<div>
First we varied the number of a driver threads on the client for the first query.</div>
<div>
Notice that we can scan through 6bn rows, or 4.3TB of data in 6.55s.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwzZQp9pmULmFuiO2TT70EVU4onXv10u1uixC2yjthWkzvvk1_EzfKSDIJ8BPmqOg0ChFL0FXzJmIXIrthq9uGdvcqT0vsMMhw-BAoVtV1bojJwxAaeTfFU4l9rnAhbNNwBMn7kwdHUgE/s1600/select.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwzZQp9pmULmFuiO2TT70EVU4onXv10u1uixC2yjthWkzvvk1_EzfKSDIJ8BPmqOg0ChFL0FXzJmIXIrthq9uGdvcqT0vsMMhw-BAoVtV1bojJwxAaeTfFU4l9rnAhbNNwBMn7kwdHUgE/s1600/select.png" /></a></div>
<div>
<br /></div>
<div>
Same with a simple filter applied. We can search 6bn rows/4.3TB of data in 8.36s.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiDozVu4W-wc40nT9j0hT8kOewpzOfkRSj5elLzFt2fO6GS3TvgdiBCC5tsvU41L1w16K_tGSwTYeF4RpLi70AbBRStNfMwnVhtMSa6Um3c9ksspln4hd8SmeuiYSXCeWtquhdqcv6Ovc/s1600/where.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiDozVu4W-wc40nT9j0hT8kOewpzOfkRSj5elLzFt2fO6GS3TvgdiBCC5tsvU41L1w16K_tGSwTYeF4RpLi70AbBRStNfMwnVhtMSa6Um3c9ksspln4hd8SmeuiYSXCeWtquhdqcv6Ovc/s1600/where.png" /></a></div>
<div>
<br /></div>
<div>
Next we performed sorting. As soon as the query returns the first result we cancel it.</div>
<div>
(note that with an added LIMIT clause Phoenix does an O(N) scan, instead of a O(N*log(N)) sort).</div>
<div>
<br /></div>
<div>
As mentioned, a single client can drive the cluster to sort 4.3TB in 26.4s!<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhi2sCjJ8tZtfEeT9PGl6jfrpAc2DwTK92ZXE3hrSVTehgx1rCAaVBeCwWry58_GymOxCY8MayfkM9EGWtofsikfAjiLOppuPyCn2gSb0b74RfyDeQyB9qMHkqG5N_mXPfzecDSFSZ4dQ/s1600/order.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhi2sCjJ8tZtfEeT9PGl6jfrpAc2DwTK92ZXE3hrSVTehgx1rCAaVBeCwWry58_GymOxCY8MayfkM9EGWtofsikfAjiLOppuPyCn2gSb0b74RfyDeQyB9qMHkqG5N_mXPfzecDSFSZ4dQ/s1600/order.png" /></a></div>
<div>
<br /></div>
<div>
Joins... This time fixing the threadpool size around 4000, and varying the number of a join keys. In the 128k case we performed 786 trillion comparisons of a BigInt value in 26s</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpFWPjdvV3ORF3ywZOmx381XA_T4SSKzFNAe9cbvEmHNjjFj63sG2-TE-Ghr38rqc6UQQmZnRWyBtf7_2I_En4H7HIINxVMhFcrEM2_aBJBsu_aFDvR6ORs05QJDfTfTirVpNm8nn7E2c/s1600/join.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpFWPjdvV3ORF3ywZOmx381XA_T4SSKzFNAe9cbvEmHNjjFj63sG2-TE-Ghr38rqc6UQQmZnRWyBtf7_2I_En4H7HIINxVMhFcrEM2_aBJBsu_aFDvR6ORs05QJDfTfTirVpNm8nn7E2c/s1600/join.png" /></a></div>
<div>
<br /></div>
<div>
Lastly, we also created LOCAL indexes on the data. Due to their local nature they are created in just a few second, and even at many 1000 regions still were effective to reduce query times significantly.<br />
<br />
Index creation on the 6bn row/4.7TB table took almost exactly 1 minute.<br />
It brought a scan selecting a few 1000 of the 6nb rows from 8s to about 10ms - and note that this is a table with many 1000 regions, where each region needs to pinged with "do you have these keys?"<br />
<br /></div>
<h4>
The Bad</h4>
<div>
Joins naturally do not scale well. Phoenix now has a merge join option, which sorts the relations at the servers and then performs a final merge on the client. At the sizes we're talking about this can't be done realistically. Perhaps joins with highly selective filters will work, something we'll test soon.<br />
<br />
There is a lot of work to do. In order to be efficient Phoenix/HBase need to work on denormalized data - which should not really come as a surprise.</div>
<div>
<br />
So we measured joins only for situations where they can be executed as a broadcast-hashjoin. With default configuration this failed at 2^18 (256k) joins keys.<br />
<br />
LOCAL indexes of a table are mixed in the same single column family. Creating many of them make that column family the dominant one in terms of size, driving HBase's size based split decisions.<br />
<br />
Unlike MapReduce, Spark and some distributed databases, Phoenix has no resource allocation or restarting framework, other than what's provided by HBase. Phoenix is not useful choice for queries that run for more than (say) 1h, or where partial failure on some machines is likely.<br />
<br /></div>
<h4>
And the Ugly</h4>
<div>
<ul>
<li>When queries naturally do not scale, they simply "never" (as in days) return, churning the client forever until canceled or timing out, failing.</li>
<li>Some results seemed surprising at first. OFFSET queries become very slow with increasing OFFSETs. Upon inspection that makes sense</li>
<li>Distinct queries on high cardinality tables churned for a long time and then failed.</li>
<li>There is no cost based optimizer, Phoenix uses simple heuristics to determine how to execute a query. For simple queries that works well, but breaks down for complex joins.</li>
<li>Dropping a local index is very expensive as each entry is marked for deletion individually.</li>
</ul>
<div>
<br /></div>
<h4>
Summary</h4>
</div>
<div>
To drive large queries you must configure the Phoenix client accordingly:<br />
Increase <span style="font-family: "courier new" , "courier" , monospace;">phoenix.query.threadPoolSize</span> (1000, 2000, or 4000) and <span style="font-family: "courier new" , "courier" , monospace;">phoenix.query.queueSize</span> (maybe 100000).<br />
<br />
Semi- (or un-)scientific; more of a qualitative tests whether a larger cluster can actually be utilized to execute a single query. Phoenix/HBase do quite well in terms of scaling. We will continue to do more tests and drive the fixed cost down, to allow Phoenix/HBase to utilize the machines better.</div>
<div>
<br /></div>
<div>
We'll have this cluster just a little bit longer. More to come. And if you have any other Phoenix/HBase testing you'd like us to do, please comment, and I'll see what we can do.</div>
<div>
<br /></div>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com4tag:blogger.com,1999:blog-7235509382075756737.post-82203109606716060762016-02-17T23:05:00.003-08:002016-08-12T21:32:20.721-07:00HBase - Compression vs Block Encoding<b>By Lars Hofhansl</b> <br />
<div class="post-body entry-content" id="post-body-9214529542564367637" itemprop="description articleBody">
<br />
(Updated on February 28th, 2016, to correct spelling errors and clarifications, and to add section about single threaded scanning)<br />
<br />
HBase has many options to encode or compress that data on disk.<br />
<br />
In <a href="https://blogs.apache.org/hbase/entry/the_effect_of_columnfamily_rowkey">this excellent blog post</a> Doug Meil and Thomas Murphy outline the effects of block encoding and compression on the storage footprint.<br />
<br />
In this post I will explore the effects of encoding and compression options on (read) performance. I performed the Scan performance tests with the excellent <a href="http://phoenix.apache.org/">Apache Phoenix</a> the relational layer over HBase. The Get tests use a straight HBase client, without Phoenix.<br />
<br />
<h3>
Background</h3>
<br />
In short:<br />
<b>Block encoding</b> refers to ability to encode KeyValues or
Cells on-the-fly as blocks are written or read, exploiting duplicate
information between consecutive Cells. The main advantage is that the
blocks can be cached in encoded form and decoded as needed in a
streaming way. The encodings used most commonly in HBase are FAST_DIFF and (to a lesser extent) PREFIX encoding.<br />
<br />
<b>Compression </b>here means full compression of HBase blocks using
SNAPPY, GZIP, and others. Newer versions of HBase have the ability cache
block in compressed form, but I did not test this here.<br />
<br />
(Compression and block encoding for HBase are described in more detail <a href="http://archive.cloudera.com/cdh5/cdh/5/hbase-0.98.6-cdh5.3.2/book/compression.html">here</a>.)<br />
<br />
The most important property to note is that the <b>cost of decompression is proportional to the number of blocks</b> that have to be decompressed, whereas the <b>cost of decoding is proportional to the number of Cells</b> visited. Keep that in mind when looking at the numbers below.<br />
<div>
<br /></div>
<div>
<span style="font-weight: bold;"><br /></span></div>
<h3>
<span style="font-weight: bold;">The Setup</span></h3>
<div>
<br /></div>
For my test I created Phoenix tables of with the following schema:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">create table test (pk integer primary key, v1 float, v2 float);</span><br />
<div>
<br />
Then I seed the pk from a sequence, and v1/v2 with random values like so:</div>
<div>
<div>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">upsert into test values(next value for pkey, rand(), rand());</span></div>
</div>
<div>
<br />
followed by a few (doubling the size of the table each time):</div>
<div>
<div>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">upsert into test select next value for pkey, rand(), rand() from test;</span></div>
</div>
<br />
This data set, except for the monotonically increasing key, would not compress well.<br />
<br />
With that I created tables with 32m rows, or 128m Cells altogether (including the one that Phoenix creates for book-keeping), on a single machine.<br />
<br />
Let's first look at the footprint on disk:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> 595MB <b>GZIP</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></span><span style="font-family: "courier new" , "courier" , monospace;"> 875MB <b>FAST_DIFF</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 993MB <b>SNAPPY</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">173<span style="font-family: "courier new" , "courier" , monospace;">9</span></span>MB <span style="font-family: "courier new" , "courier" , monospace;"><b>PREFIX</b></span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">2922MB <b>NONE</b></span><br />
<br />
So, the first take away: You <b>have </b>to use some kind of compression or encoding.
Since every column needs to be stored as its own cell it clocks in with
about 24 bytes per column uncompressed - or about 100 bytes per "row". (In a relational database with a dense row format that entire row would only take about 12 bytes.)<br />
<div>
<br /></div>
I tested the following four scenarios:<br />
<ul>
<li>12 core machine, 3GB ram, 4 DDR3 memory channels</li>
<li>from disk (7200rpm drive, 8ms seek time or about 125 IOPS, about 120MB/s)</li>
<li>from SSD (about 800MB/s, about 2500 IOPS)</li>
<li>from OS cache</li>
<li>from HBase cache</li>
</ul>
<br />
The region server was configured with:<br />
<span style="font-family: "courier new" , "courier" , monospace;">-Xmn2g -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCompressedOops -XX:+UseCMSInitiatingOccupancyOnly -XX:MaxGCPauseMillis=5000 -XX:GCTimeLimit=90 -XX:GCHeapFreeLimit=10</span><br />
<br />
Short Circuit Reads were enabled for HDFS.<br />
<br />
<h3>
Now let's do some scanning</h3>
<div>
<br /></div>
In order to avoid caching in HBase I used the NO_CACHE hint in Phoenix that I added a while ago (<a href="https://issues.apache.org/jira/browse/PHOENIX-13">PHOENIX-13</a>) <br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> </span><span style="font-family: "courier new" , "courier" , monospace;">select /*+ NO_CACHE */ count(*) from test;</span><br />
<span style="font-size: x-small;"> (This will actually issue 11 scan requests to HBase in parallel) </span><br />
<br />
I cleared the OS Cache with<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> echo 3 | sudo tee /proc/sys/vm/drop_caches</span><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDwba2zbEYp0VKqJ_32VJ5OoJTVKamLV0TcGF2HrCDGAwtQCiSV9T3RVWoYcX2-c2MevbDvp2bLjCBHQcgKmQqZwsDYEh_3coARf88WXB8jtV3_RB7dTSrGdJ92vP27WdgXidMD6F6Wko/s1600/image.png" imageanchor="1"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIdJeBz-u8Kq1bzxMA18VHnbF6eIzp2EGSbujivrlYXpc0O7WEnU86Y7zFmDbj-juBJDUiJ3isDlzdfz95eWIqkw1m__c2uSGQt_hqEZtiBxRFLvw0Td2tWul4HYl0sy6Q7cjEZUT69_I/s1600/image-3.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIdJeBz-u8Kq1bzxMA18VHnbF6eIzp2EGSbujivrlYXpc0O7WEnU86Y7zFmDbj-juBJDUiJ3isDlzdfz95eWIqkw1m__c2uSGQt_hqEZtiBxRFLvw0Td2tWul4HYl0sy6Q7cjEZUT69_I/s1600/image-3.png" /></a><br />
<br />
We can see that reading from <b>spinning disk</b> is (not surprisingly) dominated by the amount of data to be read. Extra CPU time consumed by compression is negligible, we are clearly IO bound.<br />
We also see that in all cases - even GZIP - HBase was able to push the drive close to it's limit. In fact in all cases I saw 90-95MB/s read from disk, the
performance gain from compression is close to proportional to the
compression ratio.<br />
<br />
Let's look at the same data without the HDD numbers to see better what's going on:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLROrUbUiA7nIf9wJCReTEwSIbITNjGQsuD5buu5R5QnYvDbxmJgw0A5uHSSplqKP5ZzS7gBW0ryLXvJQAdObm7R7DkGyKE9DVMxqpEjuan95Zg3n09MXaK_15eNaNhH03gW-6mDM7wg8/s1600/image-1.png" imageanchor="1"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjru0mGuJ7BNKkCHBwsjMjM_vOYqtezq7BVAzzz-fidaPVxzS81ueHe12Ri1eIlrrHC7J2BGo2_y-G1S1Nr8IX0N-MR6vmDj21IoThCCGyUnfouKQ0kYppDi5KlZaPZwp1ym3ajXPt-z2w/s1600/image-6.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjru0mGuJ7BNKkCHBwsjMjM_vOYqtezq7BVAzzz-fidaPVxzS81ueHe12Ri1eIlrrHC7J2BGo2_y-G1S1Nr8IX0N-MR6vmDj21IoThCCGyUnfouKQ0kYppDi5KlZaPZwp1ym3ajXPt-z2w/s1600/image-6.png" /></a><br />
<br />
Here we see the fact the decoders incur per Cell overhead, the HBase block cache does not help for FAST_DIFF or PREFIX. For PREFIX encoding the HBase block cache actually does <b>worse</b> than the OS Cache, that is something I need to investigate further.<br />
<div>
<br /></div>
<div>
We also see that for <b>Scan</b>s the block cache has no/little advantage over the OS cache, or even reading straight form SSD - and in fact HBase wasn't able to keep the SSD fully busy. In other words for SSDs HBase scans are CPU bound. This is interesting, I will also investigate this part further.</div>
<div>
<br /></div>
All schemes except FAST_DIFF/PREFIX store the blocks in uncompressed form (note that newer version of HBase have the option to cache blocks in their compressed form, I did not test that). In this case the uncompressed data fits in the block cache, so it's not entirely fair to FAST_DIFF and PREFIX.<br />
<br />
So use FAST_DIFF only when you expect your working set to fit in the aggregate block cache when compressed, but <b>not</b> uncompressed.<br />
<br />
We can now also see the relative CPU cost of the compression. FAST_DIFF is actually worst(!), followed by GZIP, PREFIX, and then SNAPPY, which is most efficient.<br />
GZIP consumed to most CPU to decompress a block, but after decompressing a block scanning goes through the block without any extra work.<br />
<br />
Since for scans the HBase block cache generally does not buy much over Linux' disk block caching ("OS Cache" in the graph) as we're CPU bound anyway; in these situations it might be better to disable cacheBlocks (<span style="font-family: "courier new" , "courier" , monospace;">setCacheBlocks(false)</span>) on the Scan object - even when the entire scanned data would fit into the HBase block cache.<br />
<br />
<b>February 28, 2016</b><br />
<br />
Note that Phoenix uses parallel scans across regions and uses equal-width "guide posts" to guide how Phoenix should parallelize the work across HBase region servers. In the Scan examples Phoenix chose 11-way parallelization to execute the queries. I have since added a SERIAL hint to Phoenix to force <b>serial</b> execution of a query. See <a href="https://issues.apache.org/jira/browse/PHOENIX-2697">PHOENIX-2697</a>.<br />
<br />
How does performance look like when all scanning is single threaded?<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqmCoKDKF33rS6KC1Zbssw6QDxZGvxJePnr551bng10gVu1HpiZkAlcmQP9WRuKN_gmIKaTbfv_9EXc5vGaDPk9AUD5TeJel1nxHW0eDk0bKKh7IlDj89M7tPgQcxDLHtKT8e5mTbVM_o/s1600/image-1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqmCoKDKF33rS6KC1Zbssw6QDxZGvxJePnr551bng10gVu1HpiZkAlcmQP9WRuKN_gmIKaTbfv_9EXc5vGaDPk9AUD5TeJel1nxHW0eDk0bKKh7IlDj89M7tPgQcxDLHtKT8e5mTbVM_o/s1600/image-1.png" /></a>Now this is interesting. Without compression we still run into the spinning disk limit throughput limit. Everything else is mostly CPU bound.<br />
<br />
<h3>
Side note, memory bandwidth:</h3>
In the next chart I mapped the scan throughput out of the OS cache seen by 1 thread and by 11 threads. (I used the OS cache, and not the HBase block cache, as this shows the internal end-to-end performance of HBase.):<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO77Th7Yh9yigh7kXMQixxOKkOL48s2KNSsMMH1scc_44EmNWWdWjWQiAt0N2VwazMFbbW3Vu76wWNXvDMWnkxxcKQaIcV0AqcpJugIeU06CMQUWTgFN18qKktemeUJOzjfyQA6h2L0-s/s1600/image.png"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO77Th7Yh9yigh7kXMQixxOKkOL48s2KNSsMMH1scc_44EmNWWdWjWQiAt0N2VwazMFbbW3Vu76wWNXvDMWnkxxcKQaIcV0AqcpJugIeU06CMQUWTgFN18qKktemeUJOzjfyQA6h2L0-s/s1600/image.png" /></a> <br />
MB/s is the actual throughput seen out of the <b>OS cache</b>. "raw" indicates the throughput in terms of uncompressed data. We see that the throughput in terms of raw uncompressed bytes is very similar across all schemes.<br />
<br />
We run into some internal HBase/Phoenix limit around 710MB/s.<br />
<br />
Now look at the single threaded performance!<br />
The fastest is (of course) uncompressed scanning, which utilizes about 168MB/s of the available memory bandwidth. It seems we need throw a lot of cores at the problem to utilize the available memory bandwidth. Luckily Apache Phoenix does that automatically where possible; but this is still something to look in HBase land.<br />
<br />
In order to put this into context... According to spec this machine has 4 DDR memory channels for a total maximum bandwidth of 51.2 GB/s.<br />
<br />
I wrote a simple bandwidth tester in C++. It allocates 1GB of memory and then accesses it sequentially as bytes or as 64bit longs. (for good measure I wrote the same in Java, and came to the same numbers, within 10%). Please note that I am not hardware guy.<br />
<br />
Here's what I measured (bandwidth, GB/s):<br />
<table border="1" cellpadding="0" cellspacing="0" dir="ltr" style="border-collapse: collapse; border: 1px solid rgb(204, 204, 204); font-family: arial, sans, sans-serif; font-size: 13px; table-layout: fixed;"><colgroup><col width="100"></col><col width="100"></col><col width="100"></col></colgroup><tbody>
<tr style="height: 21px;"><td data-sheets-value="[null,2,"Type"]" style="padding: 2px 3px; vertical-align: bottom;">Measured B/W</td><td data-sheets-value="[null,2,"1 thread"]" style="padding: 2px 3px; vertical-align: bottom;">1 process</td><td data-sheets-value="[null,2,"4 threads"]" style="padding: 2px 3px; vertical-align: bottom;">4 processes</td></tr>
<tr style="height: 21px;"><td data-sheets-value="[null,2,"long"]" style="padding: 2px 3px; vertical-align: bottom;">long</td><td data-sheets-value="[null,3,null,13.3]" style="padding: 2px 3px; text-align: right; vertical-align: bottom;">13.3</td><td data-sheets-value="[null,3,null,42.6]" style="padding: 2px 3px; text-align: right; vertical-align: bottom;">42.6</td></tr>
<tr style="height: 21px;"><td data-sheets-value="[null,2,"byte"]" style="padding: 2px 3px; vertical-align: bottom;">byte</td><td data-sheets-value="[null,3,null,2.24]" style="padding: 2px 3px; text-align: right; vertical-align: bottom;">2.24</td><td data-sheets-value="[null,3,null,9.1]" style="padding: 2px 3px; text-align: right; vertical-align: bottom;">9.1</td></tr>
</tbody></table>
<br />
So the HBase numbers are quite a bit lower. We see that the maximum throughput (710MB/s) is close <b>4x</b> the single threaded throughput (168MB/s), indicating that this is probably related to memory throughput and not CPU cycles (we should have seen an 11x speed up, the machine has enough cores).<br />
<br />
Now, this is from the Linux block cache, so we need account for the fact that the blocks are copied at least 2 times (into a direct byte buffer, from there into a byte[]), but since the block cache is only marginally better, this looks to be all internal Phoenix and HBase friction.<br />
<h3>
OK. That was scanning. Let's try some random gets.</h3>
<br />
I wanted to explore the decompression cost more. Here I wrote a little tool that issues 1000 random gets. Now <b>each get will incur a block read</b> followed by decompression (if not in the block cache), or a seek + decoding.<br />
<br />
The numbers from HDDs are absolutely dominated by the seek time. In all cases this was close to 6.2s, which is close to what you would expect from doing 1000 seeks in 7200rpm drives (actually you would expect 8s for 1000 Gets, presumably it's a little faster, since some gets might hit the same blocks again).<br />
<b>Use SSDs for random Gets, or make sure that your working set fits into the OS cache or block cache. Otherwise each Get will require HBase to perform a disk seek (about 4ms for 15k drive, 8ms for 7.2k dive, 12ms for 5k drive).</b><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPag1ac9v2H6SS7WwPMhU-jWaqZfs5OpRc-GyaU2zdXQD1hZJant7oOGx-ZxawcgJrndLIjH33T9sCSLyETWY86MZgDrAxQ1FnfJyGsFjrJV3E-op5SNWfMsZPSpUqUIMB83a8WtXFL-U/s1600/image-5.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPag1ac9v2H6SS7WwPMhU-jWaqZfs5OpRc-GyaU2zdXQD1hZJant7oOGx-ZxawcgJrndLIjH33T9sCSLyETWY86MZgDrAxQ1FnfJyGsFjrJV3E-op5SNWfMsZPSpUqUIMB83a8WtXFL-U/s1600/image-5.png" /></a><br />
<br />
<br />
So here we see the cost of the decompression again. This time HBase needs to load and decompress a block for each get - unless that block is found in the HBase block cache. We can estimate that the "seek time" on the SSD is about 0.4ms, or that the drive can do about 2500 IOPS (which does seems low).<br />
<br />
We also see that FAST_DIFF is not doing as well with the data in block cache, again because it's the only scheme that stores blocks in their compressed form - and the cost of decoding is proportional to the number of Cells traversed.<br />
<br />
When the data is on SSD or in the OS Cache, we do see that encoders are doing slightly better. They do not have to decode the entire block, but only the portion needed to decode the Cells we're interested in.<br />
<br />
Most prominently for <b>Gets</b> we do see the value of the OS Cache and especially the HBase block cache - assuming the working set will likely fit into the aggregate block cache across the cluster.<br />
<h3>
TL;DR: </h3>
<h3>
</h3>
<ol>
<li><b>Not using compression or encoding is not an option.</b> I think HBase should not even allow that. Both SNAPPY and FAST_DIFF are good all around options.</li>
<li>If you regularly scan large data sets from <b>spinning disk</b>, you're best of with <b>GZIP</b>. (but watch write speed, which I haven't tested here)</li>
<li>For large scans, consider <b>not using the HBase block cache</b>. (<span style="font-family: "courier new" , "courier" , monospace;">Scan.setCacheBlocks(false)</span><span style="font-family: inherit;">), even if the whole scan could fit into the block cache.</span></li>
<li><span style="font-family: inherit;">If you mostly perform large scans you might even want to consider running HBase with a much smaller heap and size the block cache down, to only rely on the OS Cache. This will alleviate some garbage collection related issues.</span></li>
<li value="8">We need to throw a lot of cores at a Scan to utilize
the available memory bandwidth. When spec'ing machines for HBase, do not
skimp on cores, HBase needs those. <b>Apache Phoenix</b> makes it easy to utilize
more cores to increase scan performance.</li>
<li>If there is a chance that your data set would fit into the block cache, FAST_DIFF is a good option. It will allow more data to fit into the block cache, since the data is cached in its encoded form.</li>
<li>While for <b>Scans </b>the HBase block cache shows fairly little advantage, for <b>Gets </b>it is quite important to have your data set cached.</li>
<li>If you do lots of random gets, make sure you use SSDs, or that your working set fits into RAM (either OS cache or the HBase block cache), or performance will be truly terrible.</li>
</ol>
What I didn't test: <br />
<ol>
<li>CPU constrained environments.</li>
<li>Write performance</li>
</ol>
<div>
What I also didn't test:<br />
<ul>
<li>Multiple different scans in parallel. I'd expect the cached scenarios would behave similarly w.r.t. each other. Obviously scanning and Gets from rotating disks will do much worse.</li>
</ul>
</div>
</div>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com4tag:blogger.com,1999:blog-7235509382075756737.post-84594968964755537292016-01-22T21:39:00.000-08:002016-01-25T23:03:34.236-08:00HBaseCon 2016 is on!<div style="text-align: left;">
<a href="http://hbasecon.com/">HBaseCon</a> 2016 is on! <br />
<br />
I am lucky enough to be on the Program Committee again this year.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
HBaseCon will take place May 24, 2016 at</div>
<div style="text-align: left;">
The Village<br />
969 Market St.<br />
San Francisco, CA 94103</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The <a href="http://hbasecon.com/#schedule">Call For Papers</a> is open. If you have anything interesting to say about HBase, what you do with HBase, what other technologies you use with HBase, how you solved <i>XYZ</i> with HBase, how you hacked HBase, what we should improve in HBase, etc, etc, and want to talk about it at HBaseCon please let us know.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The CFP closes Feb 28th.</div>
<div style="text-align: left;">
<br /></div>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-62616934871736010092015-12-21T21:40:00.001-08:002015-12-21T21:40:18.365-08:00Yet more on HBase GC tuning with CMS<b>By Lars Hofhansl</b><br />
<b> </b> <br />
Some of my previous articles delve into <a href="http://hadoop-hbase.blogspot.com/2014/03/hbase-gc-tuning-observations.html">gc tuning</a> and <br />
<a href="http://hadoop-hbase.blogspot.com/2015/01/more-hbase-gc-tuning.html">more tuning for scanning</a>.<br />
<br />
We have since performed more tests with heavy write loads and I need revise my previous recommendation based on the findings.<br />
<br />
I wrote a simple test tool that generates 5 million random keys of approximately 200 bytes; then it starts 50 threads that each pick 100k random batches of these keys and write them to HBase. I then start multiple of these and point them to an HBase cluster.<br />
The result is that we see a lot of churn in HBase as new versions of Cells are written but the overall size of the data is kept more or less constant with compactions - so I can test very large write loads with limited disk space.<br />
<br />
We find that for these kinds of loads a young generation of <b>512MB</b> that I had recommended before is <b>hopelessly</b> <b>undersized</b>. We're seeing lots of premature promotions into tenured space, followed by minute long full pauses that eventually cause the region servers to shut down.<br />
<br />
For the tests I ran with a 16G heap and found a young gen of 2G is good.<br />
<br />
Note that in CMS the size of the young gen is one of the knobs to trade latency for throughput. The smaller the young gen is size the smaller the pauses tend to be... <b>If all short lived garbage fits into the young gen, that is</b>. If it does not, short lived objects get promoted into the tenured space and that will eventually lead to very long (minutes with 30G heaps) full collection pauses.<br />
<br />
So the goal is to size the young gen just large enough to fit the short lived objects. In HBase we do some guide posts for this. 40% of the heap (by default) is dedicated to the memstores, another 40% (again by default) to the block cache, and the rest (20%) to "day-to-day" garbage.<br />
<br />
With I now recommend the following for the young generation:<br />
<ul>
<li>at least <b>512MB</b></li>
<li>after that <b>10-15%</b> of the heap</li>
<li>but at most <b>3GB</b></li>
</ul>
<br />
For most setups the following should cover all the bases:<br />
<b> </b><br />
<b>-Xmn2g</b> - small eden space (or even <b>-Xmn3g</b> for very large heaps)<br />
<b>-XX:+UseParNewGC</b> - collect eden in parallel<br />
<b>-XX:+UseConcMarkSweepGC </b>- use the non-moving CMS collector<br />
<b>-XX:CMSInitiatingOccupancyFraction=70</b> - start collecting when 70% of the tenured gen are full to avoid collection under pressure<br />
<b>-XX:+UseCMSInitiatingOccupancyOnly</b> - do not try to adjust CMS setting<br />
<br />
<br />
In the end you have to test with your own work loads. Start with the smallest young gen size that you think you can get away with. Then watch the GC log. If you see lot's of "promotion failed" type messages, you need to increase eden (-Xmn), do that until the promotion failures stop.<br />
<br />
We'll be doing testing with G1GC soon.<br />
<br />
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com2tag:blogger.com,1999:blog-7235509382075756737.post-45978628822363815782015-05-08T17:36:00.000-07:002015-05-08T17:36:18.205-07:00My HBaseCon talk about HBase Performance Tuning<b>By Lars Hofhansl</b><br />
<br />
HBaseCon 2015 was a blast as always. All the presentations and videos will be online soon.<br />
<br />
In the meanwhile my presentation on "HBase Performance Tuning" can be found on <a href="http://www.slideshare.net/lhofhansl/h-base-tuninghbasecon2015ok">SlideShare</a>.Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-54952132967760737232015-04-20T21:30:00.002-07:002015-04-20T21:30:37.661-07:00HBaseCon 2015Don't forget to come to <a href="http://www.hbasecon.com/">HBaseCon</a>, the yearly get-together for all things HBase in San Francisco. May 7th, 2015.<br />
<br />
We have great collection of sessions this year:<br />
<br />
<ul>
<li>A highly-trafficked HBase cluster with an uptime of sixteen months</li>
<li>An HBase deploy that spans three datacenters doing master-master replication between thousands of HBase nodes in each</li>
<li>Some nuggets on how Bigtable does it (and HBase could too)</li>
<li>How HBase is being used to record patient telemetry 24/7 on behalf of the Michael J. Fox Foundation to enable breakthroughs in Parkinson Disease research</li>
<li>How Pinterest and Microsoft are doing it in the cloud, how FINRA and Bloomberg are doing it out east, and how Rocketfuel, Yahoo! and Flipboard, etc., are representing the west</li>
</ul>
<br />
<div>
Among many <a href="http://hbasecon.com/agenda/">others</a>!</div>
<div>
<br /></div>
I'll be talking about HBase Tuning and have a brief cameo in the HBase 2.0 panel, talking abount semantic versioning. Feel free to find me afterwards.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-9999892712550942562015-03-08T12:24:00.000-07:002015-03-08T22:46:21.682-07:00HBase Scanning Internals - SEEK vs SKIP<b>By Lars Hofhansl, March 8th, 2015</b><br />
<br />
Recently we ran into a problem where a mapper that scanned a region of about 10GB with a timerange that did not include any Cell (KeyValue) took upwards of 20 minutes to finish; it processed only about 8MB/s.<br />
<br />
It turns out this was a known problem that has eluded a fix for while: Deciding at the scanner level whether to SEEK ahead past potentially many Cells or whether to power through and repeatedly SKIP the next Cell until the next useful Cell is reached.<br />
<br />
<h3>
Background </h3>
Scanning forward through a file, HBase has no knowledge about how many columns are to follow for the current row or how many versions there are for the current column (remember that every version of every column in HBase has its own Cell in the HFiles).<br />
<br />
In order to deal with many columns or versions, HBase can issue SEEKs to the next row (seeking past all versions for all remaining columns for the row) or the next column (seeking past all remaining versions). HBase errs on the side of SEEK'ing frequently since SKIP'ing potentially 1000' or 100000's of times can be disastrous for performance (imagine a row with 100 columns and 10000 versions each - unlikely, but possible).<br />
<br />
The problem is: SEEK'ing is about <b>10x</b> as expensive as a single SKIP - depending on how many seek pointers into HFiles have to be reset.<br />
<br />
Yet, in many cases we have rows with only a few or even just one column and just one version each. Now the SEEKs will cause a significant slowdown.<br />
<br />
After much trying finally there is a proposed solution:<br />
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<a href="https://issues.apache.org/jira/browse/HBASE-13109">HBASE-13109</a> <b>Make better SEEK vs SKIP decisions during scanning</b></div>
(0.98.12 and later)<br />
<br />
<h3>
How does it work?</h3>
HFiles are organized like B-Trees, and it is possible to determine the start key of the next block in each file.<br />
<br />
A heuristic is now:<br />
Will the SEEK we are about to execute get us into the <b>next block</b> of the HFile that is at <b>top of the heap</b> used for the merge sorting between the HFiles?<br />
<br />
<b>If so</b>, we will definitely benefit from seeking (the repeated SKIPs would eventually exhaust the current block and load the next one anyway).<br />
<br />
<b>If not</b>, we'll <b>likely</b> benefit from repeated SKIP'ing. This is a heuristic only, the SEEK might allow us to seek past manys Cell in HFiles not at the top of the heap, but that is unlikely.<br />
<br />
In all tests I did this performs equal to or (much) better than the current behavior.<br />
<br />
The upshot is that now the HBase plumbing (filters, coprocessors, delete marker handling, skipping columns, etc) can continue to issue SEEKs where that is logically possible, and then at the scanner level it can decide whether to act upon the SEEK or to keep SKIP'ing inside the current block, with almost optimal performance.<br />
<br />
<b>TL;DR:</b><br />
<a href="https://issues.apache.org/jira/browse/HBASE-13109">HBASE-13109</a> Allows many queries against HBase to execute 2-3x faster. Especially those that select specific columns, or those that filter on timeranges, or where many deleted columns for column families are encountered.<br />
Queries that request all columns and that do not filter the data in any way will not benefit from this change.<br />
<br />
You do need to do anything to get that benefit (other than upgrading your HBase to at least the upcoming 0.98.12).<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-5022275211576145512015-01-12T22:47:00.002-08:002015-02-01T13:21:07.045-08:00More HBase GC tuning<span style="font-family: inherit;"><i><b>By Lars Hofhansl</b></i> </span><br />
<br />
<span style="font-family: inherit;"><span style="font-family: inherit;">My</span> <span style="font-family: inherit;">article on </span></span><a href="http://hadoop-hbase.blogspot.com/2014/03/hbase-gc-tuning-observations.html"><span style="font-family: inherit;">hbase-gc-tuning-observations</span></a><span style="font-family: inherit;"><span style="font-family: inherit;"> explores how to config<span style="font-family: inherit;">ure <span style="font-family: inherit;">the garbage collector for HBase.</span></span></span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">There is <span style="font-family: inherit;">actuall<span style="font-family: inherit;">y a bit more to it<span style="font-family: inherit;">, especially when <b><a href="http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/io/encoding/DataBlockEncoding.html">block encoding</a></b> <span style="font-family: inherit;">is enabled for <span style="font-family: inherit;">a column family<span style="font-family: inherit;"> and the predom<span style="font-family: inherit;">in<span style="font-family: inherit;">ant access is via the scan API with row cachin<span style="font-family: inherit;">g.</span></span></span></span></span></span></span></span></span></span><br />
<br />
<span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;">Block enc<span style="font-family: inherit;">oding currently requires HBase to </span></span></span></span></span></span></span></span></span></span><b>material</b><span style="font-family: inherit;"><b>ize</b> each KeyValue after deco<span style="font-family: inherit;">ding during scann<span style="font-family: inherit;">ing<span style="font-family: inherit;">, <span style="font-family: inherit;">and h<span style="font-family: inherit;">ence this<span style="font-family: inherit;"> has the p<span style="font-family: inherit;">otential to produce a lot of ga<span style="font-family: inherit;">r<span style="font-family: inherit;">bage <span style="font-family: inherit;">for each scan RPC, es<span style="font-family: inherit;">pec<span style="font-family: inherit;">ially when the scan re<span style="font-family: inherit;">spo<span style="font-family: inherit;">nse is lar<span style="font-family: inherit;">ge as might be the case when <span style="font-family: inherit;">scanner caching is set <span style="font-family: inherit;">to la<span style="font-family: inherit;">rger value<span style="font-family: inherit;"> (see <a href="http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html#getCaching%28%29">Scan.getCaching<span style="font-family: inherit;">()</span></a>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">My e<span style="font-family: inherit;">xperiment<span style="font-family: inherit;">s show that i<span style="font-family: inherit;">n that case it is better to run with a larger young gen of <b>512</b><span style="font-family: inherit;"><b>M<span style="font-family: inherit;">B</span></b> (-Xmn512m)</span></span></span></span> and -<span style="font-family: inherit;"> c<span style="font-family: inherit;">rucially - make sure that all per RPC g<span style="font-family: inherit;">arbage across all <span style="font-family: inherit;">handlers actively performing scans <span style="font-family: inherit;">fits into the <b>s</b><span style="font-family: inherit;"><b>urv</b><span style="font-family: inherit;"><b>i</b><span style="font-family: inherit;"><b>vor space</b>.</span></span></span></span></span></span></span></span> (Not<span style="font-family: inherit;">e that this statem<span style="font-family: inherit;">ent is true whether or not block enc<span style="font-family: inherit;">oding is used<span style="font-family: inherit;">. B<span style="font-family: inherit;">lock encoding <span style="font-family: inherit;">just</span> <span style="font-family: inherit;">produces</span> a lot more gar<span style="font-family: inherit;">ba<span style="font-family: inherit;">ge).</span></span></span></span></span></span></span></span><br />
<br />
<span style="font-family: inherit;">HBase actually has a way to<span style="font-family: inherit;"> limit the siz<span style="font-family: inherit;">e <span style="font-family: inherit;">o<span style="font-family: inherit;">f <span style="font-family: inherit;">an in<span style="font-family: inherit;">dividual scan re<span style="font-family: inherit;">sponse by <span style="font-family: inherit;">setting </span></span></span></span></span></span></span></span></span><span style="font-family: "Courier New",Courier,monospace;"><b><span style="font-weight: normal;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-weight: normal;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size">hbase.client.scanner.max.result.size</span></span></span></span></b></span>.<br />
<h4>
<span style="font-family: inherit;"> </span></h4>
<h4>
<span style="font-family: inherit;">Quick re<span style="font-family: inherit;">cap:</span></span></h4>
<span style="font-family: inherit;"><span style="font-family: inherit;">The <span style="font-family: inherit;">H</span>otspot JVM<span style="font-family: inherit;"> d<span style="font-family: inherit;">ivid<span style="font-family: inherit;">es th<span style="font-family: inherit;">e hea<span style="font-family: inherit;">p into <span style="font-family: inherit;">PermGen<span style="font-family: inherit;">, Tenu<span style="font-family: inherit;">re<span style="font-family: inherit;">d Gen, and the Youn<span style="font-family: inherit;">g<span style="font-family: inherit;">Gen</span></span></span></span></span></span></span></span></span></span></span></span>. YoungGen i<span style="font-family: inherit;">tsel<span style="font-family: inherit;">f is d<span style="font-family: inherit;">ivide<span style="font-family: inherit;">d into <span style="font-family: inherit;">E</span>d<span style="font-family: inherit;">en and two survi<span style="font-family: inherit;">vor spaces.</span></span></span></span></span></span></span><br />
<span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"> </span></span></span></span></span></span> </span><br />
<span style="font-family: inherit;">By defa<span style="font-family: inherit;">ult the su<span style="font-family: inherit;">rvivor ratio is 8 (i.e. <span style="font-family: inherit;">each su<span style="font-family: inherit;">r<span style="font-family: inherit;">v<span style="font-family: inherit;">i<span style="font-family: inherit;">vor space is 1/8 of Eden; together the<span style="font-family: inherit;">ir sizes add up to the configured <span style="font-family: inherit;">young gen size)</span></span></span></span></span></span></span></span></span> </span><br />
<h4>
<span style="font-family: inherit;"><span style="font-family: inherit;"> </span></span></h4>
<h4>
<span style="font-family: inherit;"><span style="font-family: inherit;">What to do<span style="font-family: inherit;">?</span></span> </span></h4>
<span style="font-family: inherit;"><span style="font-family: inherit;">With -Xmn</span>512m<span style="font-family: inherit;"> this comes t<span style="font-family: inherit;">o <span style="font-family: inherit;">~</span>51<span style="font-family: inherit;">M<span style="font-family: inherit;">B</span></span> for each of the two s<span style="font-family: inherit;">u<span style="font-family: inherit;">r<span style="font-family: inherit;">vivor space<span style="font-family: inherit;">s.</span></span></span></span></span></span></span><br />
<div id="yui_3_16_0_1_1421125299163_2246" role="presentation">
<br />
<span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size">Now you want <span style="font-family: inherit;">to set </span><span style="font-family: "Courier New",Courier,monospace;">hbase.client.scanner.max.result.size</span> suc<span style="font-family: inherit;">h that the expected number of a handler threads <span style="font-family: inherit;">times</span></span></span></span></span><span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"><span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"> th<span style="font-family: inherit;">e max.result.size </span>is <span style="font-family: inherit;">less than <span style="font-family: inherit;">ea<span style="font-family: inherit;">ch of the</span></span> su<span style="font-family: inherit;">rv<span style="font-family: inherit;">i<span style="font-family: inherit;">vor <span style="font-family: inherit;">spaces.</span></span></span></span></span></span></span></span></span></span></span></span></div>
<div id="yui_3_16_0_1_1421125299163_2246" role="presentation">
<br />
With 30 handlers (default in HBase as of 0.98) this comes to 1.7MB, since not all handlers will always scan using the full buffer 2MB is probably a good setting.<br />
<br />
<span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;">Make<span style="font-family: inherit;">s sense<span style="font-family: inherit;">, doesn't<span style="font-family: inherit;">?<span style="font-family: inherit;"> If per scan results across all <span style="font-family: inherit;">active hand<span style="font-family: inherit;">lers cannot <span style="font-family: inherit;">fit <span style="font-family: inherit;">int<span style="font-family: inherit;">o the surv<span style="font-family: inherit;">ivor space the <span style="font-family: inherit;">collector has no choice b<span style="font-family: inherit;">ut to promote to the tenu<span style="font-family: inherit;">red <span style="font-family: inherit;">g<span style="font-family: inherit;">enerat<span style="font-family: inherit;">ion.<span style="font-family: inherit;"> That is exactly the sc<span style="font-family: inherit;">enario <span style="font-family: inherit;">one would <span style="font-family: inherit;">l<span style="font-family: inherit;">ike to avoid</span> </span>as we would slow<span style="font-family: inherit;">ly polut<span style="font-family: inherit;">e the tenu<span style="font-family: inherit;">red <span style="font-family: inherit;">gen with per PRC garbage<span style="font-family: inherit;">, eventually <span style="font-family: inherit;">requir<span style="font-family: inherit;">ing a full GC to defragment<span style="font-family: inherit;">.</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span><br />
<span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><br /></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
A 2MB response also happens to be a good size for 1ge networks. 2MB will take at least 16ms to be transmitted, which is higher than typical intra-datacenter latency of 0.1-1ms. With 10ge this would need to reviewed as 2MB can be send over 10ge is 1.6ms.<br />
<h4>
</h4>
<h4>
TL;DR:</h4>
</div>
<div id="yui_3_16_0_1_1421125299163_2246" role="presentation">
<span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size">When using block encoding<span style="font-family: inherit;"> make sure</span></span><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"> #</span>handlers * max.results.size < survivor space</span><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;">, and use a <span style="font-family: inherit;">slightly larger young generat<span style="font-family: inherit;">ion:</span></span></span></span></span></span><br />
<br />
<span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"><span style="font-family: inherit;"><span style="font-family: inherit;"><b>-Xmn512m<span style="font-family: inherit;">b </span></b><span style="font-family: inherit;">(in hbase-e<span style="font-family: inherit;">nv.sh)</span></span></span></span></span></span></span></span></div>
<span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"><span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" id="yui_3_16_0_1_1421125299163_2245" title="hbase.client.scanner.max.result.size"><b>hbase.client.scanner.max.result.size</b><span style="font-family: inherit;"> <span style="font-family: inherit;">= <b>2097152</b></span></span> <span style="font-family: inherit;">(in hbase-site.xml)</span></span></span></span></span></span></span></span><br />
<span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"><span style="font-weight: normal;"><span style="font-family: inherit;"><span class="subject" title="hbase.client.scanner.max.result.size"><span style="font-family: inherit;"><br /></span></span></span></span></span></span></span></span>
<b><br /></b>
<b>Update, January 31st, 2015</b><br />
Since HBase versions 0.98 and later produce a little bit more garbage than 0.94 due to using protobuf, I am now generally recommending a young gen of 512mb for those versions of HBase.<br />
<br />
And the same reasoning goes for writes, when <a href="http://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/client/Table.html#put(java.util.List)">batching writes</a> make sure the batch sizes are around 2MB, so that they can temporarily fir into the survivor generation.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-3803538794415983082014-10-23T13:18:00.001-07:002014-10-23T13:18:09.708-07:00Branching - Managing Open Source and Corporate goals (HBase)<b>By Lars Hofhansl</b><br />
<b><br /></b>
Company and Open Source goals are often at odds or at least not completely aligned.<br />
Here's how we do things for HBase (and dependent projects) at Salesforce.<br />
<br />
<ol>
<li>We do not fork any of the projects. A "fork" here being a departure from the open source repository significant enough to prevent us from contributing patches back to the open source branches or to use open source updates against our repository.</li>
<li>We do (almost) all work against the open source branches (0.98 currently).</li>
<li>We have internal copies of the HBase repository and all dependent projects (Hadoop, ZooKeeper, etc).</li>
<li>We have minimal patches in our own repositories. Mostly pom changes to defined where to pull dependencies from - for example we want to build our HBase against our build of Hadoop.<br />Sometimes we have an odd patch or two that have not made it back to open source.</li>
<li>We attach internal version numbers to our builds such as 0.98.4-sfdc-2.2.1, to indicate the exact version of what we're running in production.</li>
<li>Everything we run in production is build automatically (via jenkins jobs) from source against these internal repositories. This allows to be agile in case of emergencies.</li>
<li>Updates to the internal repository are manual (by design). We do not track the open source branches automatically. At our own pace, when we are ready, we move to a new upstream version, which most of the time allows us to remove some of one-off patches we had applied locally. For example we stayed at 0.98.4 for a while with some patches on top, and recently moved to 0.98.7, to which we had contributed all of the patches.</li>
<li>All internal patches are eventually cleaned up and contributed back to open source, so that we can follow along the release train of minor version (0.98.4, 0.98.5, etc).</li>
<li>Of course we keep an eye on and spend a lot of time with the open source releases to make sure they are stable and suitable for us to use a future internal release.</li>
</ol>
With this simple model we avoid forking, tack along with the open source releases, remain agile, and remain in full control over what exactly is deployed, completely at our own pace. Open source and corporate goals do not have to be at odds.<br />
<br />
This might all be obvious; a bit of diligence is required to support both the open source goals for a project as well as the specific corporate goals.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-90764961017025863352014-08-12T14:42:00.000-07:002014-10-30T22:34:11.539-07:00HBase client response times<b>By Lars Hofhansl</b><br />
<br />
When talking about latency expectations from HBase you'll hear various anecdotes and various war- and horror-stories where latency varies from a few milliseconds to many minutes.<br />
<br />
In this blog post I will classify the latency conditions and their causes.<br />
<br />
There are five principle causes to latency in HBase:<br />
<br />
<ol>
<li><b>Normal</b> network round trip time (RTT) plus internal work that HBase has to do to retrieve or write the data. This type of latency is in the order of <b>milliseconds</b> - RTT + disk seeks, etc.</li>
<li><b>Client retries</b> due to moved regions or splits. Regions can be moved due to HBase deciding that the cluster is not balanced. As regions grow in size their are split.<br />The HBase client rides over this by retrying a few times. You should make sure you have the client retry count and interval <a href="http://hadoop-hbase.blogspot.com/2012/09/hbase-client-timeouts.html">configured</a> according to your needs. This can take in the order of <b>one second</b>. Note that this is independent on the size of the region as no data is actually moved - it remains in its location in HDFS - just the ownership is transferred to another region server.</li>
<li><b>GC</b> (see also <a href="http://hadoop-hbase.blogspot.com/2014/03/hbase-gc-tuning-observations.html">hbase-gc-tuning-observations</a>). This is an issue with nearly every Java application. HBase is no exception. A well tuned HBase install can keep this below 2s at all times, with average GC times around 50ms (this is for large heaps of 32GB)</li>
<li><b>Server outages.</b> This is were large tail end latency is caused. When a region server dies it takes - by default - 90s to detect, then that server's regions are reassigned to other servers, which then have replay logs and bring the regions online. Depending on the amount uncommitted data the region server had, this can take minutes. So in total this is in the order of <b>a few minutes</b> - if a client requests any data for any of the involved regions. Interactions with other region servers are not impacted.</li>
<li><b>Writers overwhelming the cluster.</b> Imagine a set of clients trying to write data into an HBase cluster faster than the cluster's hardware (network for 3-way replication, or disk) can absorb. HBase can buffer some spikes in memory (the memstore) but after some time of sustained write load has to force the clients to stop. In 0.94 a region server will just block any writers for a configurable maximum amount of time (90s by default). In 0.96 and later the server throws a RegionTooBusyException back to the client. The client then will have to retry until HBase has enough resource to accept the request. See also <a href="http://hadoop-hbase.blogspot.com/2014/07/about-hbase-flushes-and-compactions.html">about-hbase-flushes-and-compactions</a>. Depending on how fast HBase can compact excess HFiles this condition can last <b>minutes</b>.</li>
</ol>
All of the cases refer to any delays caused by HBase itself. Scanning large regions or writing a lot of data in bulk-write requests naturally have to adhere to physics. The data needs to loaded from disk - potentially from another machines - or it needs to be written across the network to three replicas. The time needed here depends on the particular network/disk setup.<br />
<br />
The gist is that when things are smooth (and you have disabled Nagle's, i.e. enable tcpnodelay) you'll see latency of a <b>few ms</b> if things are in the blockcache, or <b>< 20ms</b> or so when disk seeks are needed.<br />
The 99th percentile will include GCs, region splits, and region moves, and you should see something around <b>1-2s</b>.<br />
<br />
In the event of failures such as failed region servers or overwhelming the cluster with too many write requests, latency can go as high as a <b>few minutes</b> for requests to the involved regions.Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com2tag:blogger.com,1999:blog-7235509382075756737.post-91860643733395783312014-07-16T09:17:00.001-07:002014-07-16T09:26:46.820-07:00About HBase flushes and compactions<b>By Lars Hofhansl</b><br />
<br />
The topic of <b>flushes</b> and <b>compactions</b> comes up frequently when using HBase. There are somewhat obscure configuration options around this, you hear terms like "write amplification", and you might see scary messages about blocked writes in the logs until a flush has finished.<br />
<br />
Let's step back for a minute and explore what HBase is actually doing. The configuration parameters will then make more sense.<br />
<br />
Unlike most traditional databases HBase stores its data in "Log Structured Merge" (<b>LSM</b>) Trees.<br />
<br />
There are numerous academic treatments concerning LSM trees, so I won't go into details here.<br />
<br />
Basically in HBase it works something like this:<br />
<ol>
<li>Edits (Puts, etc) are collected and sorted in memory (using a skip list specifically). HBase calls this the "<b>memstore</b>"</li>
<li>When the memstore reached a certain size (<span style="font-family: "Courier New",Courier,monospace;">hbase.hregion.memstore.flush.size</span>) it is written (or <b>flushed</b>) to disk as a new "<b>HFile</b>"</li>
<li>There is one memstore per region and column family </li>
<li>Upon read, HBase performs a merge sort between all - partially sorted - memstore disk images (i.e. the HFiles)</li>
</ol>
From a correctness perspective that is all that is needed... But note that HBase would need to consider every memstore image ever written for sorting. Obviously that won't work. Each file needs to be seeked and read in order to find the next key in the sort. Hence eventually some of the HFiles need to be cleaned up and/or combined: <b>compactions</b>.<br />
<br />
<i>A <b>compaction</b> asynchronously reads two or more existing HFiles and rewrites the data into a <b>single</b> new HFile. The source HFiles are then deleted.</i><br />
<br />
This reduces the work to be done at read time at the expense of rewriting the same data multiple times - this effect is called "<b>write amplification</b>". (There are some more nuances like major and minor compaction, which files to collect, etc, but that is besides the point for this discussion)<br />
<br />
<i>This can be tweaked to optimize either reads or writes.</i><br />
<br />
If you let HBase accumulate many HFiles without compacting them, you'll achieve better <b>write performance</b> (the data is rewritten less frequently). If on the other hand you instruct HBase to compact many HFiles sooner you'll have better <b>read performance</b>, but now the same data is read and rewritten more often.<br />
<br />
HBase allows to tweak when to start compacting HFiles and what is considered the maximum limit of HFiles to ensure acceptable read performance.<br />
<br />
Generally <b>flushes</b> and <b>compaction </b>can commence in parallel. A scenario of particular interest is when clients write to HBase faster than the IO (disk and network) can absorb, i.e. faster than compactions can reduce the number of HFiles - manifested in an ever larger number of HFiles, eventually reaching the specified limit.<br />
When this happens the memstores can continue to buffer the incoming data, but they cannot grow indefinitely - RAM is limited.<br />
<br />
<span style="font-family: inherit;">What</span> should HBase do in this case? What can it do?<br />
The only option is to <b>disallow writes</b>, and that is exactly what HBase does.<br />
<br />
There are various knobs to tweak flushes and compactions:<br />
<ul>
<li><span style="font-family: "Courier New",Courier,monospace;"><b>hbase.hregion.memstore.flush.size</b><span style="font-family: inherit;"><br /><span style="font-family: Arial,Helvetica,sans-serif;">The size a single memstore is allowed to reach before it is flushed to disk.</span></span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.hregion.memstore.block.multiplier<span style="font-family: inherit;"><br /></span></span></b><span style="font-family: inherit;">A
memstore is temporarily allowed to grow to the maximum size times this
factor.</span><span style="font-family: "Courier New",Courier,monospace;"><b><br /></b></span></li>
<li><span style="font-family: "Courier New",Courier,monospace;"><b>hbase.regionserver.global.memstore.lowerLimit</b><br /><span style="font-family: inherit;"></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: inherit;">JVM global limit on aggregate memstore size before some of the memstore are force-flushed (in % of the heap).</span> </span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.regionserver.global.memstore.upperLimit</span><span style="font-family: "Courier New",Courier,monospace;"><br /></span></b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;">JVM memstore size limit before writes are blocked </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: inherit;"> (in % of the heap)</span></span></span></span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.hstore.compactionThreshold</span></b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><br />When a store (region and column family) has reach this many HFiles, HBase will start compacting HFiles</span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.hstore.blockingStoreFiles</span></b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><br />HBase disallows further flushes until compactions have reduced the number of HFiles at least to this value. That means that now the memstores need to buffer all writes and hence eventually are subject blocking clients if compactions cannot keep up.</span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.hstore.compaction.max</span></b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><br />The maximum number of HFiles a single - minor - compaction will consider.</span></span></li>
<li><b><span style="font-family: "Courier New",Courier,monospace;">hbase.hregion.majorcompaction</span></b><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;">Time interval between timed - major - compactions. HBase will trigger a compaction with this frequency even when no changes occurred.</span></span></li>
<li><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;"><b>hbase.hstore.blockingWaitTime</b></span><br />Maximum time clients are blocked. After this time writes will be allowed again.</span></span></li>
</ul>
<span style="font-family: inherit;">So when hbase.hstore.blockingStoreFiles</span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><b> </b>HFiles are reached <b>and</b> the memstores are full (reaching </span></span><br />
<span style="font-family: "Courier New",Courier,monospace;">hbase.hregion.memstore.flush.size * </span><br />
<span style="font-family: "Courier New",Courier,monospace;">hbase.hregion.memstore.block.multiplier</span><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-family: inherit;">or due their aggregate size reaching </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;">hbase.regionserver.global.memstore.upperLimit)</span><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-family: inherit;">writes are blocked for </span></span></span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;">hbase.hstore.blockingWaitTime<b> </b></span></span></span>milliseconds.</span></span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"><span style="font-family: "Courier New",Courier,monospace;"><br /></span></span></span>
<span style="font-family: inherit;">Note that this is not a flaw of HBase but simply physics. When disks/network are too slow at some point clients needs to slowed down.</span>Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-27701709652354443712014-07-08T14:15:00.000-07:002014-07-08T14:15:42.839-07:00Key note at HBaseCon 2014<b>By Lars Hofhansl</b> <br />
<br />
<a href="http://hbasecon.com/">HBaseCon</a> 2014 in May was a blast again as usual. <br />
My <a href="http://cloudera.com/content/cloudera/en/resources/library/hbasecon2014/hbasecon-2014-general-session.html">keynote</a> is now online (together with Google's and Facebook's key note - Facebook's for some reason was not recorded).<br />
<br />
(And that from somebody who just three years ago would quite literally rather have died than doing <b>any</b> public speaking - I think you can do and learn anything if you put your mind to it.)<br />
<br />
Also check out the session that actually have some contents: <a href="http://hbasecon.com/archive.html">http://hbasecon.com/archive.html</a>.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-18869366121772933672014-03-03T22:46:00.001-08:002015-01-12T22:50:10.298-08:00HBase GC tuning observations<b>By Lars Hofhansl</b><br />
<br />
Java garbage collection tuning depends heavily on the application.<br />
<br />
HBase is somewhat special: It produces a lot of short lived objects that typically does not outlive a single RPC request; at the same time most of the heap is (and should be) used for the block cache and the memstores that hold objects that typically live for a while.<br />
In most setups HBase also requires reasonably short response times, many seconds of garbage collection are not acceptable. <br />
<br />
<h4>
Quick GC primer </h4>
There is a lot of (better informed) literature out there about this topic, so here just the very basics.<br />
<ul>
<li><span style="font-family: inherit;"><span class="st">In typical applications most object "die young" (they are created and soon are no longer needed). This is certainly true for HBase. This is called the "weak generational hypothesis".</span></span><span style="font-family: inherit;"><span class="st"> Most modern garbage collectors accommodate this by organizing the heap into generations.</span></span></li>
<li><span style="font-family: inherit;"><span class="st">HotSpot: manages four generations:</span></span></li>
<ol>
<li><span style="font-family: inherit;"><span class="st"><b>Eden</b> for all new objects</span></span></li>
<li><span style="font-family: inherit;"><span class="st"><b>Survivor I and II</b> where surviving objects are promoted when eden is collected</span></span></li>
<li><span style="font-family: inherit;"><span class="st"><b>Tenured</b> space. Objects surviving a few rounds (16 by default) of eden/survivor collection are promoted into the tenured space</span></span></li>
<li><span style="font-family: inherit;"><span class="st"><b>Perm gen</b> for classes, interned strings, and other more or less permanent objects. </span></span></li>
</ol>
<li><span style="font-family: inherit;"><span class="st">The principle costs to the garbage collector are (1) tracing all objects from the "root" objects and (2) collecting all unreachable objects.<br />Obviously #1 is expensive when many objects need to be traced, and #2 is expensive when objects have to be moved (for example to reduce memory fragmentation)</span></span></li>
</ul>
<br />
<h4>
Back to HBase</h4>
So what does that mean for HBase?<br />
<br />
Most of the heap should be set aside for the memstores and the blockcache as that is the principal data that HBase manages in memory.<br />
<br />
HBase already attempts to minimize the number of objects used (see cost #1 above) and keeps them at the same size as much as possible (cost #2 above).<br />
<br />
The memstore is allocated in chunks of 2mb (by default), and the block cache stores blocks of 64k (also by default).<br />
With that HBase keeps the number of objects small and avoids heap fragmentation (since all objects are roughly the same size and hence new objects can fit into "holes" created by previously released objects).<br />
<br />
Most other objects and datastructures do not outlive a single request and can (and should) be collected quickly.<br />
<br />
That means we want to keep eden as small as possible - just big enough to handle the garbage from a few concurrent requests. That allows us to use most of the heap for the useful data and keep minor compactions short.<br />
We also want to optimize for latency rather than throughput.<br />
And we'd want GC settings where we do not move the objects in the tenured
generation around and also collect new garbage as quickly as possible. <br />
The young generation should be moving to avoid fragmentation (in fact all young gen collectors in Hotspot are moving).<br />
<br />
<b>TL;DR: </b>With that all in mind here are the typical GC settings that I would recommend:<br />
<br />
<b>-Xmn256m</b> - small eden space (maybe <b>-Xmn512m</b>, but not more than that)<br />
<b>-XX:+UseParNewGC</b> - collect eden in parallel<br />
<b>-XX:+UseConcMarkSweepGC </b>- use the non-moving CMS collector<br />
<b>-XX:CMSInitiatingOccupancyFraction=70</b> - start collecting when 70% of the tenured gen are full to avoid collection under pressure<br />
<b>-XX:+UseCMSInitiatingOccupancyOnly</b> - do not try to adjust CMS setting<br />
<br />
<br />
Those should be good settings for starters. You should find average GC times around 50ms and even 99'ile GC times around 150ms, and absolute worst case 1500ms or so; all on contemporary hardware with heaps of 32GB or less.<br />
<br />
There are efforts to move cached data off the Java to heap to reduce these pauses especially the worst case.<br />
<br />
<b>Update Jan 12, 2015:</b><br />
<b> </b><br />
Also check out "<a href="http://hadoop-hbase.blogspot.com/2015/01/more-hbase-gc-tuning.html">more-hbase-gc-tuning</a>" for more information about sizing the GC generations for HBaseLars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-5970245071060622722014-01-01T18:32:00.001-08:002014-01-07T15:12:14.390-08:00More HBase performance profiling<b>By Lars Hofhansl</b><br />
<br />
<div class="editable-field inactive" id="summary-val" title="Click to edit">
Continuing my sporadic profiling sessions I identified a few more issues in HBase.</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<h3>
</h3>
<h3>
First, a note about profiling </h3>
</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
"Instrumentating" profilers often distort the actual results and frequently lead to premature optimization.<br />
For example in HBase that lead to caching of redundant information on each KeyValue wasting heap space. Using a sampler showed that none of the optimized methods were hotspots.</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
The instrumentation is still useful, but the result should always be validated by a "sampler" or, even better, real "performance counters".</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<br /></div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
I simply used the Sampler in jVisualVM, which ships with the JDK.<br />
<br /></div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<h3>
Here are some new issues I found and fixed: </h3>
<h3>
</h3>
<a href="https://issues.apache.org/jira/browse/HBASE-9915">HBASE-9915</a> <b>Performance: isSeeked() in EncodedScannerV2 always returns false</b><br />
HBase optimizes seeks and ensures that (re)seeks that would land on a key on the current block continue scanning forward inside the block, rather than (1) consulting the HFile index again, (2) loading the block, and (3) scanning from the beginning of that block again.<br />
There was a bug in HBase where this optimization did not happen for block-encoded HFiles. Nobody noticed that this never worked.<br />
A performance improvement of 2-3x (200-300%) when block encoding is enabled.<br />
<br />
<a href="https://issues.apache.org/jira/browse/HBASE-9807">HBASE-9807</a> <b>block encoder unnecessarily copies the key for each reseek</b><br />
<span class="overlay-icon icon icon-edit-sml">Here we copied the entire row key just to compare it with the first key of the next index block when the HFile is block encoded.</span><br />
<span class="overlay-icon icon icon-edit-sml">10% improvement by itself. Much more together with HBASE-9915 mentioned above.</span><br />
<br />
<a href="https://issues.apache.org/jira/browse/HBASE-10015">HBASE-10015</a> <b>Replace intrinsic locking with explicit locks in StoreScanner</b><br />
This one was somewhat surprising. The issue is that we're locking inside the StoreScanner on each operation of next/seek/etc - millions of times per second, just so that a parallel compaction/flush can invalidate the HFile readers, which happens a few times per hour.<br />
According to conventional wisdom intrinsic locking (synchronized) should be preferred since the JVM does <a href="https://blogs.oracle.com/dave/entry/biased_locking_in_hotspot">biased locking</a>. In my tests, which were confirmed across JVMs and architectures, I found that by simply replacing intrinsic locks with ReentrantLock's there was 20-30% performance gain overall to be had.<br />
<br />
<a href="https://issues.apache.org/jira/browse/HBASE-10117">HBASE-10117</a> <b>Avoid synchronization in HRegionScannerImpl.isFilterDone</b><br />
Another issue with synchronization. As described <a href="http://hadoop-hbase.blogspot.com/2012/12/hbase-profiling.html">here</a> the synchronization penalty is not just blocked threads, but also involves memory read and write fences when the lock is completely uncontended. It turns out that in the typical case the synchronization is not needed.<br />
20-25% improvement<br />
<br />
More to come.<br />
Edit: Some spelling/grammar corrections. </div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
</div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<span class="overlay-icon icon icon-edit-sml"></span></div>
<div class="editable-field inactive" id="summary-val" title="Click to edit">
<span class="overlay-icon icon icon-edit-sml"></span></div>
Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-33329840814316544772013-07-29T23:00:00.000-07:002013-09-25T21:34:31.784-07:00HBase and data locality<b>By Lars Hofhansl</b> <br />
<br />
A quick note about data locality. <br />
<br />
In distributed systems data locality is an important property. Data locality, here, refers to the ability to move the computation close to where the data is.<br />
<br />
This is one of the key concepts of MapReduce in Hadoop. The distributed file system provides the framework with locality information, which is then used to split the computation into chunks with maximum locality.<br />
<br />
When data is written in HDFS, one copy is written locally, another is written to another node in a different rack (if possible) and a third copy is written to another node in the same rack. For all practical purposes the two extra copies are written to random nodes in the cluster.<br />
<br />
In typical HBase setups a RegionServer is co-located with an HDFS DataNode on the same physical machine. Thus every write is written locally and then to the two nodes as mentioned above. As long the regions are not moved between RegionServers there is good data locality: A RegionServer can serve most reads just from the local disk (and cache), provided short circuit reads are enabled (see <a href="https://issues.apache.org/jira/browse/HDFS-2246">HDFS-2246</a> and <a href="https://issues.apache.org/jira/browse/HDFS-347">HDFS-347</a>).<br />
<br />
When regions are moved some data locality is lost and the RegionServers in question need to request the data over the network from remote DataNodes, until the data is rewritten locally (for example by running some compactions).<br />
<br />
There are four basic events that can potentially destroy data locality:<br />
<ol>
<li>The HBase balancer decides to move a region to balance data sizes across RegionServers.</li>
<li>A RegionServer dies. All its regions need to be relocated to another server.</li>
<li>A table is disable and re-enabled.</li>
<li>A cluster is stopped and restarted.</li>
</ol>
Case #1 is a trade off. Either a RegionServer hosts an over-proportional large portion of the data, or some of the data loses its locality.<br />
<br />
In case #2 there is not much choice. That RegionServer and likely its machine died, so the regions need to be migrated to somewhere else where not all data is local (remember the "random" writes to the two other data nodes).<br />
<br />
In case #4 HBase reads the previous locality information from the .META. table (whose regions - currently only one - are assigned to an RegionServer first), and then attempts to the assign the regions of all tables to the same RegionServers (fixed with <a href="https://issues.apache.org/jira/browse/HBASE-4402">HBASE-4402</a>).<br />
<br />
In case #3 the regions are reassigned in a round-robin fashion...<br />
<br />
Wait what? If the a table is simply disabled and then re-enabled its regions are just randomly assigned?<br />
<br />
Yep. In a large enough cluster you'll end up with close to 0% data locality, which means all data for all requests is pulled remotely from another machine. In some setups that means an outage, a time of unacceptably slow read performance.<br />
<br />
This was brought up on the mailing lists again this week and we're fixing the old issue now (<a href="https://issues.apache.org/jira/browse/HBASE-6143">HBASE-6143</a>, <a href="https://issues.apache.org/jira/browse/HBASE-9080">HBASE-9080</a>).<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com2tag:blogger.com,1999:blog-7235509382075756737.post-72100459279844546832013-07-02T09:29:00.001-07:002013-07-29T22:46:39.764-07:00Protecting HBase against data center outages<b>By Lars Hofhansl</b> <br />
<br />
As HBase relies on HDFS for durability many of HDFS's idiosyncrasies need to be considered when deploying HBase into a production environment.<br />
<br />
<a href="https://issues.apache.org/jira/browse/HBASE-5954">HBASE-5954</a> is still not finished, and in any event it is not clear whether the performance penalty incurred by syncing each log entry (i.e. each individual change) to disk is an acceptable performance trade off.<br />
<br />
There are however a few practical considerations that can be applied right now.<br />
It is important to keep in mind how HBase works:<br />
<ol>
<li>new data is collected in memory</li>
<li>the memory contents are written into new immutable files (flush)</li>
<li>smaller files are combined into larger immutable files and then deleted (compaction)</li>
</ol>
#3 is interesting when it comes power outages. As described <a href="http://hadoop-hbase.blogspot.de/2012/05/hbase-hdfs-and-durable-sync.html">here</a>, data written to HDFS is typically only guaranteed to have reached N datanodes (3 by default), but not guaranteed to be persistent on disk. If the wrong N machines fail at the same time - as can happen during a data center power outage - recently written data can be lost.<br />
<br />
In case #3 above, HBase rewrites an arbitrary amount of <b>old</b> data into new files and then deletes the old files. This in turn means that during a DC outage an arbitrary amount of data can be lost and that more specifically the data loss is not limited to the newest data.<br />
<br />
Since version 1.1.1 HDFS support syncing a closed block to disk (<a href="https://issues.apache.org/jira/browse/HDFS-1539">HDFS-1539</a>). When used together with HBase this guarantees that new files are persisted to disk before the old files are deleted, and thus compactions would no longer lead to data loss following DC outages.<br />
<br />
Of course there is a price to pay. The client now needs to wait until the data is synced on the N datanodes, and more problematically this is likely to happen all at once when the datablock (64mb or larger) is closed. I found that with this setting new file creation takes between 50 and 100ms!<br />
<br />
This performance penalty can be alleviated to some extend by syncing the data to disk early and <b>asynchronously</b>. Syncing early here has no detrimental effect as the all data written by HBase is immutable (a delay is only beneficial if a block is changed multiple times).<br />
<br />
Linux/Posix can do that automatically with the proper <a href="http://linux.die.net/man/2/fadvise">fadvise</a> and <a href="http://linux.die.net/man/2/sync_file_range">sync_file_range</a> calls.<br />
HDFS supports these since version 1.1.0 (<a href="https://issues.apache.org/jira/browse/HDFS-2465">HDFS-2465</a>). Specifically, dfs.datanode.sync.behind.writes is useful here, since it will smooth out the sync cost as much as possible.<br />
<br />
So...<b> TL;DR:</b> In our cluster we enable<br />
<ul>
<li>dfs.datanode.sync.behind.writes<br />and</li>
<li>dfs.datanode.synconclose</li>
</ul>
for HDFS, in order to get some amount of safety against DC power outages with acceptable performance.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com2tag:blogger.com,1999:blog-7235509382075756737.post-6020118164233445962013-05-06T20:56:00.000-07:002013-07-29T22:46:56.140-07:00HBase durability guarantees<b>By Lars Hofhansl</b> <br />
<br />
Like most other databases HBase logs changes to a write ahead log (WAL) before applying them (i.e. making them visible). <br />
<br />
I wrote in more detail about HDFS' flush and sync semantics here: <a href="http://hadoop-hbase.blogspot.com/2012/05/hbase-hdfs-and-durable-sync.html">here</a>. Also check out <a href="https://issues.apache.org/jira/browse/HDFS-744">HDFS-744</a> and <a href="https://issues.apache.org/jira/browse/HBASE-5954">HBASE-5954</a>.<br />
<br />
Recently I got back to this area in the code and committed <a href="https://issues.apache.org/jira/browse/HBASE-7801">HBASE-7801</a> to HBase 0.94.7+, which streamlines the durability API for the HBase client.<br />
The existing API was a mess, with some settings configured only via the table on the server (such as deferred log flush) and some only via the client per each Mutation (i.e. Put or Delete) such as Mutation.setWriteToWAL(...). In addition some table settings could be overridden by a client and some could not.<br />
<br />
<a href="https://issues.apache.org/jira/browse/HBASE-7801">HBASE-7801</a> includes the necessary changes on both server and client to support a new API: Mutation.setDurablity(Durability).<br />
A client can now control durability per Mutation - via passing a Durability Enum - as follows: <br />
<ol>
<li>USE_DEFAULT: do whatever the default is for the table. This is the client default.</li>
<li>SKIP_WAL: do not write to the WAL</li>
<li>ASYNC_WAL: write to the WAL asynchronously as soon as possible</li>
<li>SYNC_WAL: write WAL synchronously</li>
<li>FSYNC_WAL: write to the WAL synchronously and guarantee that the edit is on disk (not currently supported)</li>
</ol>
Prior to this change only the equivalent of USE_DEFAULT and SKIP_WAL was supported. <br />
<br />
The changes are backward compatible. A server prior to 0.94.7 will gracefully ignore any client settings that it does not support. <br />
<br />
The HTable.setWriteToWAL(boolean) API is deprecated in 0.94.7+ and was removed in 0.95+.<br />
<br />
I filed a followup jira to do the same refactoring the table descriptors <a href="https://issues.apache.org/jira/browse/HBASE-8375">HBASE-8375</a>.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0tag:blogger.com,1999:blog-7235509382075756737.post-53650039407990828762013-04-22T12:00:00.001-07:002013-04-22T12:00:29.484-07:00HBaseCon 2013I am lucky enough to be on the HBaseCon Program Committee again this year.<br />
<br />
We received a great set of talks and we organized them into four tracks: Operations, Internals, Ecosystem, and Case Studies<br />
<br />
Today the Session List was announced: <a href="http://www.blogger.com/goog_1489624535"><br /></a><br />
<a href="http://blog.cloudera.com/blog/2013/04/hbasecon-2013-speakers-tracks-and-sessions-announced/">http://blog.cloudera.com/blog/2013/04/hbasecon-2013-speakers-tracks-and-sessions-announced/</a><br />
<br />
Obviously I am biased, but I think this will be a great event.Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-64806772421112592472013-03-01T23:55:00.003-08:002013-03-01T23:55:39.874-08:00My HUG talk on HBase performance improvements<a href="http://files.meetup.com/1350427/LarsH%20-%20HUG%20presentation.pdf">http://files.meetup.com/1350427/LarsH%20-%20HUG%20presentation.pdf</a>Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-75070521588332133662013-02-15T21:49:00.000-08:002013-02-15T21:49:06.392-08:00Managing HBase releasesLast year I (perhaps foolishly?) signed up to be the release manager for the 0.94 branch of HBase. I released 0.94.0 in Mai 2012. Since then I have learned a lot of the open source release process (which, in the end, is not that different from release proprietary software).<br />
<br />
There are no defined responsibilities per se for such a role other than actually doing the release.<br />
<br />
When I started HBase had relatively infrequent releases and there used to be many discussions and delays to a release to get some more "essential" features in.<br />
The partial cure for this is two fold:<br />
<ol>
<li>Frequent releases on a somewhat strict schedule. If a feature or fix does not get in, it'll be in the next release a few weeks later.<br />This reduces the pressure to push a feature into the next point release.<br />The only discussions now are typically around serious bugs that have been discovered during the round of release candidates.<br /> This is the "release train" model. The train stops every few weeks,
changes that are ready get on board, the other changes wait for the next
train.</li>
<li>A passing, comprehensive test suite, so that we can do the frequent releases with confidence. Problems are identified early (if the tests fail regularly nobody will check out new test failures, or these failures just drown in the noise of failing tests).</li>
</ol>
We're now on HBase 0.94.5 (released today actually!), and the pattern that emerged after some initial adjustment is one point release (0.94.0, 0.94.1, ...) about every four to six weeks (depending on how many rounds of release candidates were needed), with a relatively constant rate of change of two fixes and improvements per day (hence a point release ends up having 60-80 changes).<br />
<br />
As you can see HBase is pretty actively maintained!<br />
<br />
So to me being the release manager includes all of the following:<br />
<ul>
<li>Help decide what features or fixes should be included in the release.</li>
<li>Help channel the discussion about whether a feature in (unstable) trunk is important enough to be backported to 0.94.</li>
<li>Try to review all the changes that go into 0.94. Due to the rate of change I cannot have a detailed look at every fix (I have other responsibilities in my day time job too), but I try to at least skim the changes to see if anything risky or incorrect sticks out.</li>
<li>Make sure the <a href="https://builds.apache.org/job/HBase-0.94/">test suite</a> passes reliably. This is a pet-peeve of mine and has been especially challenging, but we're now at pass rate of about 70% (up from 20-30% a few months back, but still needs to be improved).<br />(Note that many of the failures are due to timing issues in the virtual build machines, and not due to a bug in the HBase code base. A single failing test out of over 1800 tests will make the test suite fail. So 70% is not as bad as it sounds.)</li>
<li>Keep timely releases. This my pet-peeve number two.<br />Releases should be frequent, on a semi strict schedule, and backward compatible.<br />That allows users to get features and fixes sooner and does not require cumbersome serial upgrades (where you need to upgrade from version 0.94.0 to 0.94.1 first in order to then upgrade from 0.94.1 to 0.94.2, and so on). Intermediary releases can be skipped (it is possible to upgrade from 0.94.0 to 0.94.5 directly).<br />At the same time - as mentioned above - it allows developers to finish a feature or fix correctly rather than rushing it to "get it in", just because the next release will be 6 months from now.</li>
<li>(Sometimes) coordinate with vendors (such as Cloudera and Hortonworks) to time a release or a fix with their releases. This is on a best effort basis, the Apache release is independent of any vendor; but let's be honest, a significant fraction of our users run a release from these vendors. </li>
<li>Doing the actual release:</li>
<ul>
<li>Tagging the release in SVN</li>
<li>Creating the release artifacts (currently we use the ones generated by the jenkins build for this). </li>
<li>Go through a round of one or more RCs and get other committers to test and vote for this RC. Here we need to improve with more automated integration test.</li>
<li>Uploading the release to the official Apache mirrors.</li>
<li>Pushing the release to the Maven repository (which involves a lot of black voodoo).</li>
</ul>
</ul>
0.94 is the current stable release branch of HBase. As long as the next version (0.96) does not have a stable release we will keep backporting new features to 0.94 and keep the frequent releases going.<br />
<br />
So far this has been fun (with the occasional frustration about the flaky test suite in the past).<br />
<br />
The HBase community is very friendly and invites outside patches and improvements. So <a href="http://www.apache.org/dyn/closer.cgi/hbase/">download</a> HBase 0.94.5, and start contributing :)<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com1tag:blogger.com,1999:blog-7235509382075756737.post-54125910305597584662013-01-30T15:38:00.000-08:002013-01-30T15:38:34.689-08:00SQL on HBaseMy Salesforce colleague and cubicle neighbor, James Taylor, just released <i>Phoenix</i> a SQL layer on top of HBase to the Open Source world. <br />
<br />
Phoenix is implemented as a JDBC driver. It makes use of various HBase features such as coprocessors and filters to push predicates into the server as much as possible. Queries are parallelized across RegionServers.<br />
<br />
Phoenix has a formal data model that includes making use of the row key structure for optimization.<br />
<br />
Currently Phoenix is limited to single table operations.<br />
<br />
Here's James' blog entry <a href="http://phoenix-hbase.blogspot.com/2013/01/announcing-phoenix-sql-layer-over-hbase.html">announcing</a> Phoenix.<br />
<br />Lars Hofhanslhttp://www.blogger.com/profile/17852987569207015300noreply@blogger.com0