जबकि अंतिम-उपयोगकर्ता अनुप्रयोगों के निर्माण के लिए Apache HBase को अपनाना आसमान छू गया है, उनमें से कई एप्लिकेशन (और आमतौर पर कई ऐप) का अच्छी तरह से परीक्षण नहीं किया गया है। इस पोस्ट में, आप कुछ ऐसे तरीकों के बारे में जानेंगे जिनसे यह परीक्षण आसानी से किया जा सकता है।
हम जुनीट के माध्यम से यूनिट परीक्षण के साथ शुरू करेंगे, फिर मॉकिटो और अपाचे एमआरयूनीट का उपयोग करने के लिए आगे बढ़ेंगे, और फिर एकीकरण परीक्षण के लिए एचबीएएस मिनी-क्लस्टर का उपयोग करने के लिए आगे बढ़ेंगे। (एचबीएएस कोडबेस का परीक्षण मिनी-क्लस्टर के माध्यम से किया जाता है, तो क्यों न अपस्ट्रीम अनुप्रयोगों के लिए भी उसमें टैप किया जाए?)
चर्चा के आधार के रूप में, मान लें कि आपके पास एक HBase डेटा एक्सेस ऑब्जेक्ट (DAO) है जो HBase में निम्नलिखित सम्मिलित करता है। तर्क बेशक अधिक जटिल हो सकता है लेकिन उदाहरण के लिए, यह काम करता है।
public class MyHBaseDAO {
public static void insertRecord(HTableInterface table, HBaseTestObj obj)
throws Exception {
Put put = createPut(obj);
table.put(put);
}
private static Put createPut(HBaseTestObj obj) {
Put put = new Put(Bytes.toBytes(obj.getRowKey()));
put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1"),
Bytes.toBytes(obj.getData1()));
put.add(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2"),
Bytes.toBytes(obj.getData2()));
return put;
}
}
HBaseTestObj एक बुनियादी डेटा ऑब्जेक्ट है जिसमें रोकी, डेटा1 और डेटा2 के लिए गेटर्स और सेटर्स होते हैं।
InsertRecord CF के कॉलम परिवार के खिलाफ HBase तालिका में CQ-1 और CQ-2 के साथ क्वालीफायर के रूप में एक इंसर्ट करता है। createPut विधि केवल एक पुट को पॉप्युलेट करती है और उसे कॉलिंग विधि में वापस कर देती है।
जुनीट का उपयोग करना
JUnit, जो इस समय अधिकांश जावा डेवलपर्स के लिए जाना जाता है, आसानी से कई HBase अनुप्रयोगों पर लागू होता है। सबसे पहले, निर्भरता को अपने पोम में जोड़ें:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
अब, टेस्ट क्लास के भीतर:
public class TestMyHbaseDAOData {
@Test
public void testCreatePut() throws Exception {
HBaseTestObj obj = new HBaseTestObj();
obj.setRowKey("ROWKEY-1");
obj.setData1("DATA-1");
obj.setData2("DATA-2");
Put put = MyHBaseDAO.createPut(obj);
assertEquals(obj.getRowKey(), Bytes.toString(put.getRow()));
assertEquals(obj.getData1(), Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-1")).get(0).getValue()));
assertEquals(obj.getData2(), Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-2")).get(0).getValue()));
}
}
आपने यहां जो किया वह यह सुनिश्चित करने के लिए था कि आपकी createPut विधि अपेक्षित मानों के साथ एक पुट ऑब्जेक्ट बनाता है, पॉप्युलेट करता है और देता है।
मॉकिटो का उपयोग करना
तो आप उपरोक्त insertRecord विधि के यूनिट परीक्षण के बारे में कैसे जाते हैं? मॉकिटो के साथ ऐसा करना एक बहुत प्रभावी तरीका है।
सबसे पहले, मॉकिटो को अपने पोम पर निर्भरता के रूप में जोड़ें:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
फिर, टेस्ट क्लास में:
@RunWith(MockitoJUnitRunner.class)
public class TestMyHBaseDAO{
@Mock
private HTableInterface table;
@Mock
private HTablePool hTablePool;
@Captor
private ArgumentCaptor putCaptor;
@Test
public void testInsertRecord() throws Exception {
//return mock table when getTable is called
when(hTablePool.getTable("tablename")).thenReturn(table);
//create test object and make a call to the DAO that needs testing
HBaseTestObj obj = new HBaseTestObj();
obj.setRowKey("ROWKEY-1");
obj.setData1("DATA-1");
obj.setData2("DATA-2");
MyHBaseDAO.insertRecord(table, obj);
verify(table).put(putCaptor.capture());
Put put = putCaptor.getValue();
assertEquals(Bytes.toString(put.getRow()), obj.getRowKey());
assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-1")));
assert(put.has(Bytes.toBytes("CF"), Bytes.toBytes("CQ-2")));
assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-1")).get(0).getValue()), "DATA-1");
assertEquals(Bytes.toString(put.get(Bytes.toBytes("CF"),
Bytes.toBytes("CQ-2")).get(0).getValue()), "DATA-2");
}
}
यहां आपने HBaseTestObj को "ROWKEY-1", "DATA-1", "DATA-2" मानों के साथ पॉप्युलेट किया है। फिर आपने रिकॉर्ड डालने के लिए नकली तालिका और डीएओ का उपयोग किया। आपने पुट पर कब्जा कर लिया है कि डीएओ ने डाला होगा और सत्यापित किया होगा कि पंक्ति, डेटा 1 और डेटा 2 वही हैं जो आप उनसे होने की उम्मीद करते हैं।
यहां कुंजी डीएओ के बाहर एचटेबल पूल और एचटेबल इंस्टेंस निर्माण का प्रबंधन करना है। यह आपको ऊपर दिखाए गए अनुसार सफाई से उनका मजाक उड़ाने और पुट का परीक्षण करने की अनुमति देता है। इसी तरह, अब आप अन्य सभी कार्यों जैसे गेट, स्कैन, डिलीट, आदि में विस्तार कर सकते हैं।
MRUnit का उपयोग करना
नियमित डेटा एक्सेस यूनिट टेस्टिंग के कवर के साथ, आइए MapReduce नौकरियों की ओर मुड़ें जो HBase तालिकाओं के विरुद्ध जाती हैं।
HBase के विरुद्ध जाने वाली MR जॉब का परीक्षण करना उतना ही सरल है जितना कि नियमित MapReduce जॉब का परीक्षण करना। MRUnit HBase सहित MapReduce नौकरियों का परीक्षण करना वास्तव में आसान बनाता है।
कल्पना कीजिए कि आपके पास एक MR जॉब है जो एक HBase टेबल, "MyTest" को लिखता है, जिसमें एक कॉलम परिवार है, "CF"। ऐसी नौकरी का रिड्यूसर कुछ इस तरह दिख सकता है:
public class MyReducer extends TableReducer<Text, Text, ImmutableBytesWritable> {
public static final byte[] CF = "CF".getBytes();
public static final byte[] QUALIFIER = "CQ-1".getBytes();
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
//bunch of processing to extract data to be inserted, in our case, lets say we are simply
//appending all the records we receive from the mapper for this particular
//key and insert one record into HBase
StringBuffer data = new StringBuffer();
Put put = new Put(Bytes.toBytes(key.toString()));
for (Text val : values) {
data = data.append(val);
}
put.add(CF, QUALIFIER, Bytes.toBytes(data.toString()));
//write to HBase
context.write(new ImmutableBytesWritable(Bytes.toBytes(key.toString())), put);
}
}
अब आप MRUnit में उपरोक्त रेड्यूसर का यूनिट-परीक्षण कैसे करेंगे? सबसे पहले, MRUnit को अपने पोम पर निर्भरता के रूप में जोड़ें।
<dependency> <groupId>org.apache.mrunit</groupId> <artifactId>mrunit</artifactId> <version>1.0.0 </version> <scope>test</scope> </dependency>
फिर, परीक्षण वर्ग के भीतर, MRUnit द्वारा प्रदान किए गए ReduceDriver का उपयोग करें:
public class MyReducerTest {
ReduceDriver<Text, Text, ImmutableBytesWritable, Writable> reduceDriver;
byte[] CF = "CF".getBytes();
byte[] QUALIFIER = "CQ-1".getBytes();
@Before
public void setUp() {
MyReducer reducer = new MyReducer();
reduceDriver = ReduceDriver.newReduceDriver(reducer);
}
@Test
public void testHBaseInsert() throws IOException {
String strKey = "RowKey-1", strValue = "DATA", strValue1 = "DATA1",
strValue2 = "DATA2";
List<Text> list = new ArrayList<Text>();
list.add(new Text(strValue));
list.add(new Text(strValue1));
list.add(new Text(strValue2));
//since in our case all that the reducer is doing is appending the records that the mapper
//sends it, we should get the following back
String expectedOutput = strValue + strValue1 + strValue2;
//Setup Input, mimic what mapper would have passed
//to the reducer and run test
reduceDriver.withInput(new Text(strKey), list);
//run the reducer and get its output
List<Pair<ImmutableBytesWritable, Writable>> result = reduceDriver.run();
//extract key from result and verify
assertEquals(Bytes.toString(result.get(0).getFirst().get()), strKey);
//extract value for CF/QUALIFIER and verify
Put a = (Put)result.get(0).getSecond();
String c = Bytes.toString(a.get(CF, QUALIFIER).get(0).getValue());
assertEquals(expectedOutput,c );
}
}
मूल रूप से, MyReducer में प्रसंस्करण के एक समूह के बाद, आपने सत्यापित किया कि:
- आउटपुट वह है जिसकी आप अपेक्षा करते हैं।
- HBase में जो पुट डाला जाता है, उसमें "RowKey-1" रोकी के रूप में होता है।
- “DATADATA1DATA2” CF कॉलम फ़ैमिली और CQ कॉलम क्वालिफ़ायर का मान है।
आप मैपरड्राइवर का उपयोग करके एचबीएएस से डेटा प्राप्त करने वाले मैपर्स का परीक्षण भी कर सकते हैं, या एचबीएएस से पढ़ने वाले एमआर जॉब्स का परीक्षण कर सकते हैं, डेटा प्रोसेस कर सकते हैं और एचडीएफएस को लिख सकते हैं।
HBase मिनी-क्लस्टर का उपयोग करना
अब हम देखेंगे कि एकीकरण परीक्षण के बारे में कैसे जाना है। HBase HBaseTestingUtility के साथ आता है, जो HBase मिनी-क्लस्टर के साथ लेखन एकीकरण परीक्षण को सरल बनाता है। सही पुस्तकालयों को खींचने के लिए, आपके पोम में निम्नलिखित निर्भरताएँ आवश्यक हैं:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.0.0-cdh4.2.0</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
<version>0.94.2-cdh4.2.0</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.0.0-cdh4.2.0</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.0.0-cdh4.2.0</version>
<scope>test</scope>
</dependency>
अब, आइए देखें कि परिचय में वर्णित MyDAO इंसर्ट के लिए एकीकरण परीक्षण कैसे चलाया जाए:
public class MyHBaseIntegrationTest {
private static HBaseTestingUtility utility;
byte[] CF = "CF".getBytes();
byte[] QUALIFIER = "CQ-1".getBytes();
@Before
public void setup() throws Exception {
utility = new HBaseTestingUtility();
utility.startMiniCluster();
}
@Test
public void testInsert() throws Exception {
HTableInterface table = utility.createTable(Bytes.toBytes("MyTest"),
Bytes.toBytes("CF"));
HBaseTestObj obj = new HBaseTestObj();
obj.setRowKey("ROWKEY-1");
obj.setData1("DATA-1");
obj.setData2("DATA-2");
MyHBaseDAO.insertRecord(table, obj);
Get get1 = new Get(Bytes.toBytes(obj.getRowKey()));
get1.addColumn(CF, CQ1);
Result result1 = table.get(get1);
assertEquals(Bytes.toString(result1.getRow()), obj.getRowKey());
assertEquals(Bytes.toString(result1.value()), obj.getData1());
Get get2 = new Get(Bytes.toBytes(obj.getRowKey()));
get2.addColumn(CF, CQ2);
Result result2 = table.get(get2);
assertEquals(Bytes.toString(result2.getRow()), obj.getRowKey());
assertEquals(Bytes.toString(result2.value()), obj.getData2());
}}
यहां आपने एक HBase मिनी-क्लस्टर बनाया और इसे शुरू किया। फिर आपने एक कॉलम परिवार, "सीएफ" के साथ "माईटेस्ट" नामक एक टेबल बनाई। आपने परीक्षण के लिए आवश्यक डीएओ का उपयोग करके एक रिकॉर्ड डाला, उसी तालिका से प्राप्त किया, और सत्यापित किया कि डीएओ ने रिकॉर्ड सही ढंग से डाला है।
ऊपर दिखाए गए एमआर नौकरियों के साथ-साथ अधिक जटिल उपयोग के मामलों के लिए भी ऐसा ही किया जा सकता है। आप HBase वन बनाते समय बनाए गए HDFS और ZooKeeper मिनी-क्लस्टर तक भी पहुंच सकते हैं, MR जॉब चला सकते हैं, HBase को आउटपुट कर सकते हैं, और सम्मिलित रिकॉर्ड्स को सत्यापित कर सकते हैं।
सावधानी का एक त्वरित नोट:एक मिनी-क्लस्टर को शुरू करने में 20 से 30 सेकंड का समय लगता है और इसे सिगविन के बिना विंडोज पर नहीं किया जा सकता है। हालांकि, क्योंकि उन्हें केवल समय-समय पर चलाया जाना चाहिए, लंबे समय तक चलने का समय स्वीकार्य होना चाहिए।
आप उपरोक्त उदाहरणों के लिए https://github.com/sitaula/HBaseTest पर नमूना कोड पा सकते हैं। हैप्पी टेस्टिंग!