What Are The Advanced Apache Hadoop MapReduce Features?

ພາບ​ລວມ: The basic MapReduce programming explains the work flow details. But it does not cover the actual working details inside the MapReduce programming framework. ບົດຄວາມນີ້ຈະອະທິບາຍການເຄື່ອນໄຫວຂໍ້ມູນຜ່ານສະຖາປັດຕະ MapReduce ແລະໂທ API ທີ່ໃຊ້ໃນການເຮັດການປະມວນຜົນທີ່ແທ້ຈິງ. ພວກເຮົາຍັງຈະປຶກສາຫາລືເຕັກນິກການປັບແຕ່ງແລະການທໍາງານທີ່ສຸດສໍາລັບຄວາມຕ້ອງການສະເພາະໃດຫນຶ່ງຄໍາຮ້ອງສະຫມັກ.

ການ​ນໍາ​ສະ​ເຫນີ: ລັກສະນະກ້າວຫນ້າທາງດ້ານ MapReduce ອະທິບາຍການປະຕິບັດແລະລາຍລະອຽດໃນລະດັບຕ່ໍາ. ໃນການດໍາເນີນໂຄງ MapReduce ປົກກະຕິ, APIs ພຽງແຕ່ຮູ້ແລະການນໍາໃຊ້ຂອງເຂົາເຈົ້າແມ່ນພຽງພໍທີ່ຈະຂຽນຄໍາຮ້ອງສະຫມັກ. ແຕ່ລາຍລະອຽດໃນການ MapReduce ເປັ​​ນຕ້ອງການທີ່ຈະເຂົ້າໃຈລາຍລະອຽດການເຮັດວຽກຕົວຈິງແລະໄດ້ຮັບຄວາມເຊື່ອຫມັ້ນ.

ໃນປັດຈຸບັນໃຫ້ພວກເຮົາປຶກສາຫາລືລັກສະນະກ້າວຫນ້າທາງດ້ານໃນພາກສ່ວນດັ່ງຕໍ່ໄປນີ້.

ປະເພດລູກຄ້າ (Data): ສໍາຫລັບຜູ້ໃຊ້ບໍລິ Mapper ແລະ Reducer, ໂຄງຮ່າງການ Hadoop MapReduce ສະເຫມີການນໍາໃຊ້ຂໍ້ມູນປະເພດ. ຂໍ້ມູນເຊິ່ງ passes ໂດຍຜ່ານ Mapper ແລະລົດຂະຫນາດແມ່ນເກັບຮັກສາໄວ້ໃນວັດຖຸ Java.

  • ສາມາດຂຽນໄດ້ Interface: ໃນການໂຕ້ຕອບມາດຂຽນເປັນຫນຶ່ງຂອງການໂຕ້ຕອບທີ່ສໍາຄັນທີ່ສຸດ. ວັດຖຸທີ່ສາມາດໄດ້ຮັບການຮວບຮວມກັບ / ຈາກໄຟລ໌ແລະໃນໄລຍະການນໍາໃຊ້ເຄືອຂ່າຍການໂຕ້ຕອບນີ້. Hadoop ຍັງໄດ້ນໍາໃຊ້ໃນການໂຕ້ຕອບນີ້ເພື່ອສົ່ງຂໍ້ມູນໃນຮູບແບບຕໍ່ເນື່ອງ. ບາງສ່ວນຂອງຫ້ອງການທີ່ປະຕິບັດໃນການໂຕ້ຕອບສາມາດຂຽນໄດ້ທີ່ໄດ້ກ່າວມາຂ້າງລຸ່ມນີ້
  1. ລະດັບຄວາມ(ມັນເກັບຂໍ້ມູນ String)
  2. LongWritable
  3. FloatWritable
  4. IntWritable
  5. BooleanWritable

ຊະນິດຂໍ້ມູນລູກຄ້າຍັງສາມາດໄດ້ຮັບການເຮັດໄດ້ໂດຍການປະຕິບັດ ສາມາດຂຽນໄດ້ interface. Hadoop ສາມາດສົ່ງປະເພດຂອງຂໍ້ມູນລູກຄ້າ (ທີ່ເຫມາະກັບຄວາມຕ້ອງຂອງທ່ານ) ທີ່ປະຕິບັດໃນການໂຕ້ຕອບສາມາດຂຽນໄດ້.

ຕໍ່ໄປນີ້ແມ່ນການໂຕ້ຕອບສາມາດຂຽນໄດ້ທີ່ຈະມີສອງວິທີການ READFIELD ແລະຂຽນ. ວິທີທໍາອິດ (READFIELD) ກຽມຂໍ້ມູນຂອງວັດຖຸຈາກຂໍ້ມູນທີ່ໄດ້ທີ່ມີຢູ່ໃນໃນ’ ນ້ໍາຄູ່. ວິທີທີ່ສອງ (ຂຽນ) ຖືກນໍາໃຊ້ເພື່ອສ້າງວັດຖຸທີ່ຈະນ້ໍາຄູ່ 'ອອກ'. ສັນຍາທີ່ສໍາຄັນທີ່ສຸດຂອງຂະບວນການທັງຫມົດແມ່ນວ່າຄໍາສັ່ງຂອງອ່ານແລະຂຽນນ້ໍາຄູ່ຄືກັນ.

Listing1: ສະແດງໃຫ້ເຫັນໃນການໂຕ້ຕອບສາມາດຂຽນໄດ້

ການໂຕ້ຕອບສາທາລະນະສາມາດຂຽນໄດ້ {

READFIELD void(DataInput ໃນ);

void ຂຽນ(DataOutput ອອກ);

}

ປະເພດລູກຄ້າ (ທີ່ສໍາຄັນ): ໃນພາກກ່ອນນັ້ນພວກເຮົາໄດ້ປຶກສາຫາລືກ່ຽວກັບປະເພດຂໍ້ມູນທີ່ກໍາຫນົດເອງເພື່ອຕອບສະຫນອງຄວາມຮຽກຮ້ອງຕ້ອງຂໍ້ມູນສະເພາະ. ມັນຄຸ້ມຄອງສ່ວນຫນຶ່ງມູນຄ່າພຽງແຕ່. ໃນປັດຈຸບັນພວກເຮົາຍັງຈະປຶກສາຫາລືກ່ຽວກັບປະເພດທີ່ສໍາຄັນທີ່ກໍາຫນົດເອງ. ໃນ Hadoop MapReduce, ການ Reducer ຂະບວນການທີ່ສໍາຄັນໃນຄໍາສັ່ງທີ່ການຈັດລຽງ. ດັ່ງນັ້ນປະເພດທີ່ສໍາຄັນທີ່ກໍາຫນົດເອງຕ້ອງການທີ່ຈະປະຕິບັດໃນການໂຕ້ຕອບທີ່ເອີ້ນວ່າ WritableComparable. ປະເພດທີ່ສໍາຄັນຍັງຄວນປະຕິບັດ hashCode ().

ຕໍ່ໄປນີ້ແມ່ນສະແດງໃຫ້ເຫັນ WritableComparable interface. ມັນເປັນຕົວແທນເປັນ ສາມາດຂຽນໄດ້ ເຊິ່ງແມ່ນຍັງ ເມື່ອທຽບກັບ.

Listing2: ສະແດງໃຫ້ເຫັນ WritableComparable interface

WritableComparable ການໂຕ້ຕອບສາທາລະນະ<T>

ຂະຫຍາຍສາມາດຂຽນໄດ້, ເມື່ອທຽບກັບ<T>

ວິທີການນໍາໃຊ້ປະເພດລູກຄ້າ: ພວກເຮົາໄດ້ສົນທະນາແລ້ວມູນຄ່າການລູກຄ້າແລະປະເພດທີ່ສໍາຄັນທີ່ສາມາດໄດ້ຮັບການປຸງແຕ່ງໂດຍການ Hadoop. ໃນປັດຈຸບັນພວກເຮົາຈະປຶກສາຫາລືກົນໄກເພື່ອໃຫ້ Hadoop ສາມາດເຂົ້າໃຈມັນ. ຈຸດປະສົງ JobConf (ເຊິ່ງໄດ້ກໍານົດວຽກເຮັດງານທໍາ) ມີສອງວິທີທີ່ເອີ້ນວ່າ setOutputKeyClass () ແລະ setOutputValueClass () ແລະວິທີການເຫຼົ່ານີ້ແມ່ນໄດ້ຖືກນໍາໃຊ້ເພື່ອຄວບຄຸມຄ​​່າແລະປະເພດຂໍ້ມູນທີ່ສໍາຄັນ. ຖ້າຫາກວ່າ Mapper ການຜະລິດປະເພດທີ່ແຕກຕ່າງກັນທີ່ບໍ່ມີຄໍາວ່າ Reducer ຫຼັງຈາກນັ້ນ JobConf ຂອງ setMapOutputKeyClass () ແລະ setMapOutputValueClass () ວິທີການສາມາດຖືກນໍາໃຊ້ເພື່ອກໍານົດປະເພດການປ້ອນຂໍ້ມູນຕາມທີ່ຄາດໄວ້ໂດຍການຫຼຸດຜ່ອນ.

ການປະຕິບັດໄດ້ໄວຂຶ້ນ: ຂະບວນການການຄັດເລືອກໃນຕອນຕົ້ນແມ່ນນ້ອຍຊ້າຍ້ອນວ່າມັນທໍາອິດອ່ານປະເພດທີ່ສໍາຄັນຈາກນ້ໍາຫຼັງຈາກນັ້ນແຍກນ້ໍາ byte ໄດ້ (ການນໍາໃຊ້ READFIELD() ວິ​ທີ​ການ) ແລະຫຼັງຈາກນັ້ນສຸດທ້າຍໂທຫາ compareTo () ວິທີການຂອງລະດັບທີ່ສໍາຄັນ. ວິທີການໄວຈະໄດ້ຮັບການຕັດສິນໃຈຄໍາສັ່ງລະຫວ່າງທີ່ໃຊ້ໂດຍການກວດສອບນ້ໍາ byte ໂດຍບໍ່ມີການແຍກທີ່ກໍານົດໄວ້ຂໍ້ມູນທັງຫມົດ. ເພື່ອປະຕິບັດກົນໄກການປຽບທຽບນີ້ໄວຂຶ້ນ, WritableComparator ລະດັບສາມາດໄດ້ຮັບການຂະຫຍາຍທີ່ມີການປຽບທຽບສະເພາະກັບຊະນິດຂໍ້ມູນຂອງທ່ານ. ຕໍ່ໄປນີ້ແມ່ນການປະກາດຫ້ອງຮຽນ.

Listing3: ສະແດງໃຫ້ເຫັນ WritableComparator ທີ່ຫ້ອງຮຽນ

WritableComparator ລະດັບສາທາລະນະ

ຂະຫຍາຍຈຸດປະສົງ

ປະຕິບັດ RawComparator

ດັ່ງນັ້ນຂໍ້ມູນລູກຄ້າແລະປະເພດທີ່ສໍາຄັນອະນຸຍາດໃຫ້ການນໍາໃຊ້ໂຄງສ້າງຂໍ້ມູນໃນລະດັບສູງໃນຂອບ Hadoop. ໃນຄໍາຮ້ອງສະຫມັກພາກປະຕິບັດ Hadoop ຊະນິດຂໍ້ມູນຂອງລູກຄ້າເປັນຫນຶ່ງໃນຄວາມຕ້ອງການສໍາຄັນທີ່ສຸດ. ດັ່ງນັ້ນຄຸນນະສົມບັດນີ້ອະນຸຍາດໃຫ້ການນໍາໃຊ້ປະເພດສາມາດຂຽນໄດ້ custom ແລະການສະຫນອງການປັບປຸງການປະຕິບັດທີ່ສໍາຄັນ.

ຮູບແບບການປ້ອນຂໍ້ມູນ: The InputFormat ເປັນຫນຶ່ງຂອງການໂຕ້ຕອບຂອງຄວາມສໍາຄັນທີ່ສຸດທີ່ກໍານົດຂໍ້ມູນປະກອບການຂອງວຽກເຮັດງານທໍາ MapReduce ເປັ​​ນ. Hadoop ມີບໍລິການປະເພດທີ່ແຕກຕ່າງກັນຂອງ InputFormat ສໍາລັບການຕີລາຄາຂອງປະເພດຕ່າງໆຂອງການປ້ອນຂໍ້ມູນ. ເລີ່ມຕົ້ນທົ່ວໄປທີ່ສຸດແລະເປັນ TextInputFormat ທີ່ໃຊ້ໃນການອ່ານຂອງສາຍຈາກໄຟລ໌ຂໍ້ຄວາມ. ເຊັ່ນດຽວກັນ SequenceFileInputFormat ຖືກນໍາໃຊ້ເພື່ອອ່ານຮູບແບບເອກະສານຄູ່.

ວຽກງານພື້ນຖານຂອງ InputFormat ຄືການອ່ານຂໍ້ມູນຈາກເອກະສານປະກອບ. ການປະຕິບັດຂອງລູກຄ້າ InputFormat ກໍເປັນໄປໄດ້ຕາມຄວາມຕ້ອງການຄໍາຮ້ອງສະຫມັກຂອງທ່ານ. ສໍາລັບການເລີ່ມຕົ້ນ TextInputFormat ການປະຕິບັດທີ່ສໍາຄັນແມ່ນ byte ຊົດເຊີຍຂອງອອນໄລນ໌ແລະມູນຄ່າແມ່ນເນື້ອໃນຂອງອອນໄລນ໌ລະງັບໂດຍ ' n ໄດ້’ character. ສໍາລັບການປະຕິບັດທີ່ກໍາຫນົດເອງ, ແຍກຕ່າງຫາກສາມາດລັກສະນະໃດແລະ InputFormat ຈະແຍກຕາມຄວາມເຫມາະສົມ.

ວຽກເຮັດງານທໍາຂອງ InputFormat ເປັນທີ່ຈະແບ່ງປັນໄຟລ໌ວັດຖຸດິບ (ແຫລ່ງຂໍ້ມູນ) ເຂົ້າໄປໃນ fragments ທີ່ມີການປ້ອນຂໍ້ມູນໃນແຜນທີ່ວຽກງານ. fragments ເຫຼົ່ານີ້ / splits ແມ່ນຫໍ່ຫຸ້ມຢູ່ໃນກໍລະນີຂອງການໂຕ້ຕອບ InputSplit ໄດ້. ແຫຼ່ງກອບມີຂໍ້ມູນສາມາດຈະມີສິ່ງໃດຄືຕາຕະລາງຖານຂໍ້ມູນ, file xml ຫຼືເອກະສານອື່ນໆ. ດັ່ງນັ້ນການແບ່ງປັນຈະໄດ້ຮັບການປະຕິບັດໂດຍອີງໃສ່ຄວາມຕ້ອງການຄໍາຮ້ອງສະຫມັກ. ຈຸດທີ່ສໍາຄັນທີ່ສຸດແມ່ນວ່າການດໍາເນີນງານການແບ່ງປັນຄວນຈະເປັນໄວແລະລາຄາຖືກ.

ຫຼັງຈາກແຕກອອກເອງໄຟລ໌, ອ່ານການດໍາເນີນງານຈາກການແບ່ງປັນສ່ວນບຸກຄົນມີຄວາມສໍາຄັນຫຼາຍ. The RecordReader ແມ່ນຮັບຜິດຊອບສໍາລັບການອ່ານຂໍ້ມູນຈາກການແບ່ງປັນ. The RecordReader ຄວນຈະປະສິດທິພາບພຽງພໍທີ່ຈະຈັດການຄວາມຈິງທີ່ວ່າການແບ່ງປັນບໍ່ສະເຫມີໄປໃນທີ່ສຸດ neatly ຢູ່ໃນຕອນທ້າຍຂອງເສັ້ນໄດ້. The RecordReader ສະເຫມີໄປອ່ານ till ໃນຕອນທ້າຍຂອງອອນໄລນ໌ເຖິງແມ່ນວ່າຖ້າຫາກວ່າມັນຂ້າມທີ່ສຸດທິດສະດີຂອງການແບ່ງປັນທີ່. ຄຸນນະສົມບັດນີ້ເປັນສິ່ງສໍາຄັນຫຼາຍເພື່ອຫຼີກເວັ້ນການຂາດຫາຍໄປຂອງການບັນທຶກການທີ່ອາດຈະໄດ້ຂ້າມເຂດແດນ InputSplit.

  • InputFormat Custom: ໃນຄໍາຮ້ອງສະຫມັກຂັ້ນພື້ນຖານ InputFormat ຖືກນໍາໃຊ້ໂດຍກົງ. ແຕ່ສໍາລັບການທີ່ກໍາຫນົດເອງອ່ານວິທີທີ່ດີທີ່ສຸດຄືການຄາດ FileInputFormat. ນີ້ລະດັບບໍ່ມີຕົວຕົນໃຫ້ເຮັດວຽກໃນການຈັດການໄຟລ໌ເປັນຄວາມຕ້ອງການຄໍາຮ້ອງສະຫມັກ. ສໍາລັບການວິເຄາະ custom, the getRecordReader () ວິທີການຕ້ອງໄດ້ຮັບການແທນທີ່ຈະກັບຄືນມາຍົກຕົວຢ່າງຂອງ RecordReader. ນີ້ RecordReader ແມ່ນຄວາມຮັບຜິດຊອບສໍາລັບການອ່ານແລະການວິເຄາະ.
  • ແຫລ່ງຂ່າວອື່ນອີກ (Data): The InputFormat ອະທິບາຍທັງສອງສິ່ງທີ່, ທໍາອິດແມ່ນການນໍາສະເຫນີຂອງຂໍ້ມູນທີ່ Mapper ໄດ້ແລະຄັ້ງທີສອງແມ່ນແຫລ່ງຂໍ້ມູນ. ທີ່ສຸດຂອງການປະຕິບັດແມ່ນອີງໃສ່ການ FileInputFormat, ບ່ອນທີ່ແຫລ່ງຂໍ້ມູນທີ່ເປັນລະບົບໄຟພາຍໃນປະເທດຂອງ HDFS (Hadoop Distributed File System).ແຕ່ສໍາລັບການປະເພດອື່ນໆຂອງແຫຼ່ງຂໍ້ມູນ, ການປະຕິບັດການລູກຄ້າຂອງ InputFormat ຈໍາເປັນຕ້ອງມີ. For example, ຖານຂໍ້ມູນ NoSQL ຄື HBase ໃຫ້ TableInputFormat ສໍາລັບການອ່ານຂໍ້ມູນຈາກຕາຕະລາງຖານຂໍ້ມູນ. ດັ່ງນັ້ນແຫລ່ງຂໍ້ມູນທີ່ສາມາດຈະມີສິ່ງໃດທີ່ສາມາດໄດ້ຮັບການຈັດການໂດຍການປະຕິບັດທີ່ກໍາຫນົດເອງ.

ຮູບແບບການຜະລິດ: The OutputFormat ແມ່ນຄວາມຮັບຜິດຊອບສໍາລັບການດໍາເນີນງານການຂຽນ. ພວກເຮົາໄດ້ສົນທະນາແລ້ວວ່າ InputFormat ແລະ RecordReader ການໂຕ້ຕອບມີຄວາມຮັບຜິດຊອບສໍາລັບການອ່ານຂໍ້ມູນເຂົ້າໄປໃນໂຄງການ MapReduce. ຫຼັງຈາກການປຸງແຕ່ງຂໍ້ມູນ, ການດໍາເນີນງານການຂຽນເພື່ອການເກັບຮັກສາຖາວອນແມ່ນການຄຸ້ມຄອງໂດຍ OutputFormat ແລະ RecordWriter ການໂຕ້ຕອບ. ຮູບແບບໃນຕອນຕົ້ນແມ່ນ TextOutputFormat ທີ່ຂຽນທີ່ສໍາຄັນ / ຄູ່ມູນຄ່າເປັນສະຕິງການເອກະສານຜົນຜະລິດ. ຮູບແບບການຜະລິດອື່ນໆເປັນ SequenceFileOutputFormat ແລະມັນເຮັດໃຫ້ຂໍ້ມູນໃນຮູບແບບໄບນາລີ. ຫ້ອງຮຽນທັງຫມົດເຫຼົ່ານີ້ນໍາໃຊ້ ຂຽນ () ແລະ READFIELD () ວິທີການຂອງ ສາມາດຂຽນໄດ້ ຫ້ອງຮຽນ.

The OutputFormat ການປະຕິບັດຕ້ອງໄດ້ຮັບການປັບແຕ່ງໃຫ້ຂຽນຂໍ້ມູນໃນຮູບແບບທີ່ກໍາຫນົດເອງ. The FileOutputFormat ລະດັບບໍ່ມີຕົວຕົນຕ້ອງໄດ້ຮັບການຂະຫຍາຍໄປເຮັດໃຫ້ລູກຄ້າ. The JobConf.setOutputFormat () ວິທີການຕ້ອງໄດ້ຮັບການແກ້ໄຂການນໍາໃຊ້ຮູບແບບທີ່ກໍາຫນົດເອງທີ່ແຕກຕ່າງກັນ.

ຂໍ້ມູນການແຍກ: ການແບ່ງປັນສາມາດຖືກກໍານົດເປັນຂະບວນການທີ່ກໍາຫນົດການຍົກຕົວຢ່າງ Reducer ຈະໄດ້ຮັບທີ່ລະດັບປານກາງທີ່ສໍາຄັນ / ຄູ່ມູນຄ່າ. ແຕ່ລະ Mapper ຄວນຈະກໍານົດ Reducer ຈຸດຫມາຍປາຍທາງສໍາລັບການທັງຫມົດທີ່ສໍາຄັນຜົນຜະລິດຂອງຕົນ / ຄູ່ຄ່າ. ຈຸດທີ່ສໍາຄັນທີ່ສຸດແມ່ນວ່າສໍາລັບການທີ່ສໍາຄັນໂດຍບໍ່ຄໍານຶງຂອງການຍົກຕົວຢ່າງ Mapper ຂອງຕົນຢ່າງໃດ, ການແບ່ງປັນຈຸດຫມາຍປາຍທາງຢ່າງດຽວກັນ. ສໍາລັບການປະຕິບັດວຽກຂໍ້ມູນເຫດຜົນບໍ່ເຄີຍຕິດຕໍ່ສື່ສານກັບແຕ່ລະຄົນອື່ນໆທີ່ຈະມີການແບ່ງປັນທີ່ສໍາຄັນໂດຍສະເພາະເປັນການ.

The ແບ່ງປັນ ໃນການໂຕ້ຕອບໄດ້ຖືກນໍາໃຊ້ໂດຍລະບົບການ Hadoop ການກໍານົດການແບ່ງປັນຈຸດຫມາຍປາຍທາງສໍາລັບການທີ່ສໍາຄັນຄູ່ມູນຄ່າ /. ຈໍານວນຂອງການແບ່ງປັນທີ່ຄວນຈະມີຄໍາທີ່ມີຈໍານວນຂອງລົດວຽກງານ. ໂຄງຮ່າງການ MapReduce ຕັດສິນກໍານົດຈໍານວນຂອງການແບ່ງປັນໃນເວລາທີ່ວຽກເຮັດງານທໍາເລີ່ມຕົ້ນ.

ຕໍ່ໄປນີ້ແມ່ນລາຍເຊັນຂອງການໂຕ້ຕອບການແບ່ງປັນການ.

Listing 4: ສະແດງໃຫ້ເຫັນໃນການໂຕ້ຕອບການແບ່ງປັນ

ການແບ່ງປັນການໂຕ້ຕອບສາທາລະນະ<K2, V2>

ຂະຫຍາຍ JobConfigurable

ສະ​ຫຼຸບ: ໃນການສົນທະນານີ້ພວກເຮົາໄດ້ກວມເອົາທີ່ສໍາຄັນທີ່ສຸດຄຸນນະສົມບັດ Hadoop MapReduce. ຄຸນນະສົມບັດເຫຼົ່ານີ້ແມ່ນມີປະໂຫຍດສໍາລັບຈຸດປະສົງການລູກຄ້າ. ໃນຄໍາຮ້ອງສະຫມັກພາກປະຕິບັດ MapReduce, ການເລີ່ມຕົ້ນຂອງ APIs ບໍ່ໄດ້ມີການນໍາໃຊ້ຫຼາຍ. Rather, ຄຸນນະສົມບັດທີ່ກໍາຫນົດເອງ (ເຊິ່ງແມ່ນອີງໃສ່ APIs ຮັບການ) ມີຜົນກະທົບທີ່ສໍາຄັນ. ລູກຄ້າທັງຫມົດເຫຼົ່ານີ້ສາມາດເຮັດໄດ້ຢ່າງງ່າຍດາຍເມື່ອແນວຄວາມຄິດມີຄວາມຊັດເຈນ. ຫວັງວ່າບົດຄວາມນີ້ຈະເປັນປະໂຫຍດສໍາລັບຄວາມເຂົ້າໃຈລັກສະນະກ້າວຫນ້າທາງດ້ານແລະການປະຕິບັດຂອງເຂົາເຈົ້າ.

 

Tagged on:
============================================= ============================================== Buy best TechAlpine Books on Amazon
============================================== ---------------------------------------------------------------- electrician ct chestnutelectric
error

Enjoy this blog? Please spread the word :)

Follow by Email
LinkedIn
LinkedIn
Share