HBase
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> HBase

Apache HBase + Apache Hadoop + Xceivers

Giới thiệu

Một số thuộc tính cấu hình được tìm thấy trong Apache Hadoop có ảnh hưởng trực tiếp đến các máy khách, chẳng hạn như Apache HBase. Một trong những thuộc tính đó được gọi là “dfs.datanode.max.xcievers” và thuộc dự án con HDFS. Nó xác định số luồng phía máy chủ và - ở một mức độ nào đó - các ổ cắm được sử dụng cho các kết nối dữ liệu. Đặt con số này quá thấp có thể gây ra vấn đề khi bạn phát triển hoặc tăng việc sử dụng cụm của mình. Bài đăng này sẽ giúp bạn hiểu điều gì xảy ra giữa máy khách và máy chủ cũng như cách xác định một con số hợp lý cho thuộc tính này.

Vấn đề

Vì HBase đang lưu trữ mọi thứ nó cần bên trong HDFS, nên giới hạn trên cứng được áp đặt bởi thuộc tính cấu hình “dfs.datanode.max.xcievers” có thể dẫn đến việc HBase có quá ít tài nguyên, biểu hiện là IOExceptions ở một trong hai phía của kết nối. Dưới đây là một ví dụ từ danh sách gửi thư HBase [1], trong đó các thư sau được ghi ban đầu ở phía Máy chủ của Vùng:

2008-11-11 19:55:52.451 INFO org.apache.hadoop.dfs.DFSClient:Ngoại lệ trong createBlockOutputStream java.io.IOException:Không thể đọc từ luồng
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient:Bỏ qua khối blk_-5467014108758633036_595771
2008-11- 11 19:55:58,455 WARN org.apache.hadoop.dfs.DFSClient:DataStreamer Exception:java.io.IOException:Không thể tạo khối mới.
2008-11-11 19:55:58,455 WARN org.apache .hadoop.dfs.DFSClient:Khôi phục lỗi cho khối blk_-5467014108758633036_595771 bad datanode [0]
2008-11-11 19:55:58.482 FATAL org.apache.hadoop.hbase.regionserver.Flusher:Yêu cầu phát lại hlog . Buộc tắt máy chủ

Tương quan điều này với nhật ký Hadoop DataNode cho thấy mục nhập sau:

ERROR org.apache.hadoop.dfs.DataNode:DatanodeRegistration (10.10.10.53:50010, storageID =DS-1570581820-10.10.10.53-50010-1224117842339, infoPort =50075, ipcPort =50020):DataXceiver:java.io.IOException:xceiverCount 258 vượt quá giới hạn 256 xciever đồng thời

Trong ví dụ này, giá trị thấp của “dfs.datanode.max.xcievers” cho DataNodes đã khiến toàn bộ Máy chủ Vùng ngừng hoạt động. Đây là một tình huống thực sự tồi tệ. Thật không may, không có quy tắc cứng và nhanh nào giải thích cách tính giới hạn bắt buộc. Thông thường, bạn nên tăng số từ mặc định là 256 thành 4096 (xem [1], [2], [3], [4] và [5] để tham khảo). Điều này được thực hiện bằng cách thêm thuộc tính này vào tệp hdfs-site.xml của tất cả các Mã dữ liệu (lưu ý rằng nó bị sai chính tả):

dfs.datanode.max.xcievers
4096

Lưu ý:Bạn sẽ cần khởi động lại DataNodes của mình sau khi thực hiện thay đổi này đối với tệp cấu hình.

Điều này sẽ giúp giải quyết vấn đề trên, nhưng bạn vẫn có thể muốn biết thêm về cách tất cả điều này hoạt động cùng nhau và HBase đang làm gì với những tài nguyên này. Chúng tôi sẽ thảo luận về vấn đề này trong phần còn lại của bài đăng này. Nhưng trước khi thực hiện, chúng tôi cần phải nói rõ lý do tại sao bạn không thể đặt con số này quá cao, chẳng hạn như 64K và hoàn thành với nó.

Có một lý do cho ranh giới trên và nó gấp đôi:thứ nhất, các luồng cần ngăn xếp của riêng chúng, có nghĩa là chúng chiếm bộ nhớ. Đối với các máy chủ hiện tại, điều này có nghĩa là 1MB cho mỗi luồng [6] theo mặc định. Nói cách khác, nếu bạn sử dụng hết 4096 luồng DataXceiver, bạn cần khoảng 4GB heap để chứa chúng. Điều này cắt giảm không gian bạn đã chỉ định cho các kho lưu trữ và bộ nhớ đệm khối, cũng như tất cả các phần chuyển động khác của JVM. Trong trường hợp xấu nhất, bạn có thể gặp phải OutOfMemoryException và quá trình RegionServer là bánh mì nướng. Bạn muốn đặt thuộc tính này thành một số cao hợp lý, nhưng cũng không quá cao.

Thứ hai, có nhiều luồng này hoạt động, bạn cũng sẽ thấy CPU của mình ngày càng được tải nhiều hơn. Sẽ có nhiều trường hợp chuyển đổi ngữ cảnh xảy ra để xử lý tất cả các công việc đồng thời, điều này làm mất đi tài nguyên cho công việc thực sự. Đối với mối quan tâm về bộ nhớ, bạn muốn số lượng luồng không tăng lên vô hạn, nhưng cung cấp một ranh giới trên hợp lý - và đó chính là mục đích của “dfs.datanode.max.xcievers”.

Chi tiết hệ thống tệp Hadoop

Từ phía máy khách, thư viện HDFS đang cung cấp phần trừu tượng được gọi là Đường dẫn. Lớp này đại diện cho một tệp trong hệ thống tệp được hỗ trợ bởi Hadoop, được đại diện bởi lớp FileSystem. Có một vài cách triển khai cụ thể của lớp FileSystem trừu tượng, một trong số đó là lớp DistributedFileSytem, ​​đại diện cho HDFS. Đến lượt nó, lớp này bao bọc lớp DFSClient thực tế xử lý tất cả các tương tác với các máy chủ từ xa, tức là NameNode và nhiều DataNodes.

Khi một ứng dụng khách, chẳng hạn như HBase, mở một tệp, chẳng hạn, nó sẽ làm như vậy bằng cách gọi các phương thức open () hoặc create () của lớp FileSystem, đây là các hóa thân đơn giản nhất

public DFSInputStream open (String src) ném IOException
public FSDataOutputStream create (Path f) ném IOException

Phiên bản luồng trả về là thứ cần một luồng và ổ cắm phía máy chủ, được sử dụng để đọc và ghi các khối dữ liệu. Chúng tạo thành một phần của hợp đồng để trao đổi dữ liệu giữa máy khách và máy chủ. Lưu ý rằng có những giao thức dựa trên RPC khác đang được sử dụng giữa các máy khác nhau, nhưng vì mục đích của cuộc thảo luận này, chúng có thể bị bỏ qua.

Cá thể luồng được trả về là một lớp DFSOutputStream hoặc DFSInputStream chuyên biệt, lớp này xử lý tất cả các tương tác với NameNode để tìm ra vị trí các bản sao của các khối và giao tiếp dữ liệu cho mỗi khối trên mỗi DataNode.

Ở phía máy chủ, DataNode bao bọc một phiên bản của DataXceiverServer, là lớp thực sự đọc khóa cấu hình ở trên và cũng ném ngoại lệ ở trên khi vượt quá giới hạn.

Khi DataNode khởi động, nó sẽ tạo một nhóm luồng và bắt đầu phiên bản DataXceiverServer được đề cập như sau:

this.threadGroup =new ThreadGroup (“dataXceiverServer”);
this.dataXceiverServer =new Daemon ( threadGroup,
new DataXceiverServer (ss, conf, this));
this.threadGroup.setDaemon (true); // tự động hủy khi trống

Lưu ý rằng luồng DataXceiverServer đã chiếm một vị trí của nhóm luồng. DataNode cũng có lớp nội bộ này để truy xuất số luồng hiện đang hoạt động trong nhóm này:

/ ** Số bộ thu phát đồng thời trên mỗi nút. * /
int getXceiverCount () {
trả về threadGroup ==null? 0:threadGroup.activeCount ();
}

Các khối đọc và ghi, do máy khách khởi tạo, là nguyên nhân tạo ra kết nối, được bao bọc bởi luồng DataXceiverServer thành một phiên bản DataXceiver. Trong quá trình này, một chủ đề được tạo và đăng ký trong nhóm chủ đề trên. Vì vậy, đối với mỗi hoạt động đọc và ghi đang hoạt động, một luồng mới được theo dõi ở phía máy chủ. Nếu số luồng trong nhóm vượt quá mức tối đa đã định cấu hình thì ngoại lệ đã nói sẽ được ném và ghi lại trong nhật ký của DataNode:

if (curXceiverCount> dataXceiverServer.maxXceiverCount) {
ném IOException mới (“xceiverCount” + curXceiverCount
+ ”vượt quá giới hạn số xciever đồng thời”
+ dataXceiverServer.maxXceiverCount);
}

Hàm ý cho Khách hàng

Bây giờ, câu hỏi là, việc đọc và ghi của máy khách liên quan như thế nào đến các luồng phía máy chủ. Trước khi đi vào chi tiết, hãy sử dụng thông tin gỡ lỗi mà lớp DataXceiver ghi lại khi nó được tạo và đóng

LOG.debug (“Số lượng kết nối đang hoạt động là:” + datanode.getXceiverCount ());

LOG.debug (datanode.dnRegistration + “:Số lượng kết nối đang hoạt động là:” + datanode.getXceiverCount ());

và theo dõi trong khi bắt đầu HBase những gì được ghi trên DataNode. Để đơn giản, điều này được thực hiện trên một thiết lập phân tán giả với một phiên bản DataNode và RegionServer duy nhất. Phần sau hiển thị đầu trang trạng thái của Máy chủ khu vực.

Phần quan trọng là trong phần "Chỉ số", nơi có nội dung "storefiles =22". Vì vậy, giả sử rằng HBase có ít nhất nhiều tệp cần xử lý, cộng với một số tệp bổ sung cho nhật ký ghi trước, chúng ta sẽ thấy trạng thái thông báo nhật ký ở trên rằng chúng ta có ít nhất 22 “kết nối đang hoạt động”. Hãy bắt đầu HBase và kiểm tra tệp nhật ký DataNode và RegionServer:

Dòng lệnh:

$ bin / start-hbase.sh

Nhật ký mã dữ liệu:

2012-03-05 13:01:35,309 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Số lượng kết nối đang hoạt động là:1
2012-03-05 13:01:35.315 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS- 1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:2
12/03/05 13:01:35 INFO regionerver.MemStoreFlusher:globalMemStoreLimit =396,7m, globalMemStoreLimitLowMark =347.1m, maxHeap =991.7m
12/03/05 13:01:39 INFO http.HttpServer:Cổng được trả về bởi webServer.getConnectors () [0] .getLocalPort () trước khi mở () là -1 . Mở trình nghe vào 60030
2012-03-05 13:01:40,003 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:1
12/03/05 13:01:40 INFO regionerver.HRegionServer:Đã nhận được yêu cầu mở vùng:-ROOT - ,, 0,70236052
2012-03-05 13:01:40,882 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode :Số lượng kết nối đang hoạt động là:3
2012-03-05 13:01:40,884 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448 -10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:4
2012-03-05 13:01:40,888 DEBUG org.apache.hadoop.hdfs.server. datanode.DataNode:Số lượng kết nối đang hoạt động là:3

12/03/05 13:01:40 INFO regionerver.HRegion:Onlined -ROOT - ,, 0,70236052; next sequid =63083
2012-03-05 13:01:40,982 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:3
2012-03-05 13 :01:40,983 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:4

12/03/05 13:01:41 Máy chủ vùng INFO.HRegionServer:Đã nhận yêu cầu mở vùng:.META. ,, 1.1028785192
2012-03 -05 13:01:41,026 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:3
2012-03-05 13:01:41,027 DEBUG org.apache.hadoop. hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:4

12/03/05 13:01:41 Máy chủ vùng INFO.HRegion:Onlined .META. ,, 1.1028785192; next sequenceid =63082
2012-03-05 13:01:41,109 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:3
2012-03-05 13 :01:41,114 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:4
2012-03-05 13:01:41,117 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:Số lượng kết nối đang hoạt động là:5
12/03/05 13:01:41 Máy chủ vùng INFO.HRegionServer:Đã nhận được yêu cầu mở 16 vùng
12/03/05 13 :01:41 INFO regionerver.HRegionServer:Đã nhận yêu cầu mở vùng:usertable ,, 1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.
12/03/05 13:01:41 INFO regionerver.HRegionServer:Đã nhận yêu cầu mở vùng:có thể sử dụng được, người dùng1120311784, 1330944810191.90d287473fe223f0ddc137020efda25d.

2012-03-05 13:01:41,246 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Số lượng kết nối đang hoạt động là:6
2012-03-05 13:01:41,248 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:7

2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772 , infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:10
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0. 0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:9

12/03/05 13:01:41 Máy chủ vùng INFO.HRegion:Onlined có thể sử dụng được, người dùng1120311784,1330944810191.90d287473fe223f0ddc137020efda25d .; next sequid =62917
12/03/05 13:01:41 INFO regionerver.HRegion:Onlined usertable ,, 1330944810191.62a312d67981c86c42b6bc02e6ec7e3f .; next sequid =62916

12/03/05 13:01:41 INFO regionerver.HRegion:Onlined usertable, user1361265841,1330944811370.80663fcf291e3ce00080599964f406ba .; next sequid =62919
2012-03-05 13:01:41,474 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:6
2012-03-05 13 :01:41.491 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:7
2012-03-05 13:01:41.495 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:8
2012-03 -05 13:01:41.508 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:7

12/03/05 13:01:41 INFO máy chủ vùng .HRegion:Onlined có thể sử dụng được, người dùng1964968041,1330944848231.dd89596e9129e1caa7e07f8a491c9734 .; next sequid =62920
2012-03-05 13:01:41,618 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:6
2012-03-05 13 :01:41.621 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:7

2012-03-05 13:01:41.829 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:7
12/03/05 13:01:41 Máy chủ vùng INFO. , người dùng515290649,1330944849739.d23924dc9e9d5891f332c337977af83d .; next sequid =62926
2012-03-05 13:01:41,832 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:6
2012-03-05 13 :01:41.838 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là:7
12/03/05 13:01:41 INFO regionerver.HRegion:Onlined usertable, user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f .; next sequid =62929

2012-03-05 14:01:39,711 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:4
2012 -03-05 22:48:41,945 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:4
12/03/05 22:48:41 Máy chủ vùng INFO.HRegion:Onlined usertable, user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5d6c6c6b9f .; next sequid =62929
2012-03-05 22:48:41,963 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64 -50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:4

Bạn có thể thấy cách các vùng được mở lần lượt, nhưng điều bạn cũng có thể nhận thấy là số lượng kết nối đang hoạt động không bao giờ tăng lên 22 - thậm chí gần như không đạt 10. Tại sao vậy? Để hiểu rõ hơn điều này, chúng ta phải xem cách các tệp trong HDFS ánh xạ tới phiên bản của DataXceiver phía máy chủ - và các chuỗi thực tế mà chúng đại diện.

Lặn sâu Hadoop

DFSInputStream và DFSOutputStream nói trên thực sự là những mặt tiền xung quanh các khái niệm luồng thông thường. Chúng bao bọc giao tiếp máy khách-máy chủ vào các giao diện Java tiêu chuẩn này, trong khi định tuyến nội bộ lưu lượng truy cập đến một DataNode đã chọn - là một trong đó chứa một bản sao của khối hiện tại. Nó có quyền tự do để mở và đóng các kết nối này khi cần thiết. Khi máy khách đọc tệp trong HDFS, các lớp thư viện máy khách chuyển đổi rõ ràng từ khối này sang khối khác và do đó từ DataNode sang DataNode, vì vậy nó phải mở và đóng các kết nối khi cần thiết.

DFSInputStream có một thể hiện của lớp DFSClient.BlockReader, mở kết nối với DataNode. Cá thể luồng gọi blockSeekTo () cho mọi lệnh gọi read () sẽ đảm nhận việc mở kết nối, nếu chưa có. Khi một khối được đọc hoàn toàn, kết nối sẽ bị đóng. Tất nhiên, việc đóng luồng cũng có tác dụng tương tự.

DFSOutputStream có một lớp trợ giúp tương tự, DataStreamer. Nó theo dõi kết nối đến máy chủ, được khởi tạo bởi phương thức nextBlockOutputStream (). Nó có thêm các lớp bên trong giúp ghi dữ liệu khối ra ngoài, chúng tôi bỏ qua ở đây vì mục đích ngắn gọn.

Cả khối ghi và đọc đều yêu cầu một luồng để giữ ổ cắm và dữ liệu trung gian ở phía máy chủ, được bao bọc trong cá thể DataXceiver. Tùy thuộc vào những gì khách hàng của bạn đang làm, bạn sẽ thấy số lượng kết nối dao động xung quanh số lượng tệp hiện đang được truy cập trong HDFS.

Quay lại câu đố HBase ở trên:lý do bạn không thấy tối đa 22 (và hơn thế nữa) kết nối trong khi khởi động là trong khi các khu vực mở, dữ liệu bắt buộc duy nhất là khối thông tin của HFile. Khối này được đọc để lấy thông tin chi tiết quan trọng về từng tệp, nhưng sau đó bị đóng lại. Điều này có nghĩa là tài nguyên phía máy chủ được phát hành liên tiếp nhanh chóng. Bốn kết nối còn lại khó xác định hơn. Bạn có thể sử dụng JStack để kết xuất tất cả các luồng trên DataNode, trong ví dụ này hiển thị mục nhập này:

“DataXceiver cho khách hàng /127.0.0.1:64281 [khối gửi blk_5532741233443227208_4201]” daemon prio =5 tid =7fb96481d000 nid =0x1178b4000 runnable [1178b3000]
java.lang.Thread.State:RUNNABLE

“DataXceiver cho client /127.0.0.1:64172 [khối nhận blk_-2005512129579433420_4199 client =DFSClient_hb_rs_10.0.0.29 , 60020,1330984111693_1330984118810] ”daemon prio =5 tid =7fb966109000 nid =0x1169cb000 runnable [1169ca000]
java.lang.Thread. Trạng thái:RUNNABLE

Đây là các mục nhập DataXceiver duy nhất (trong ví dụ này), vì vậy số lượng trong nhóm chủ đề có một chút sai lệch. Nhớ lại rằng luồng daemon DataXceiverServer đã chiếm một mục bổ sung, kết hợp với hai mục trên cho ba kết nối đang hoạt động - trên thực tế có nghĩa là ba luồng đang hoạt động. Thay vào đó, lý do nhật ký ghi bốn, là nó ghi lại số lượng từ một chuỗi hoạt động sắp kết thúc. Vì vậy, ngay sau khi số lượng bốn được ghi lại, nó thực sự ít hơn một, tức là ba và do đó khớp với số lượng chủ đề đang hoạt động của chúng tôi.

Cũng lưu ý rằng các lớp trợ giúp nội bộ, chẳng hạn như PacketResponder chiếm một luồng khác trong nhóm khi đang hoạt động. Đầu ra JStack chỉ ra thực tế đó, liệt kê chuỗi như vậy:

“PacketResponder 0 for Block blk_-2005512129579433420_4199” daemon prio =5 tid =7fb96384d000 nid =0x116ace000 trong Object.wait () [116acd000]
java.lang.Thread.State:TIMED_WAITING (trên trình theo dõi đối tượng)
tại java.lang.Object.wait (Native Method)
tại org.apache.hadoop. hdfs.server.datanode.BlockReceiver $ PacketResponder \
.lastDataNodeRun (BlockReceiver.java:779)
- bị khóa (a org.apache.hadoop.hdfs.server.datanode.BlockReceiver $ PacketResponder)
tại org.apache.hadoop.hdfs.server.datanode.BlockReceiver $ PacketResponder.run (BlockReceiver.java:870)
tại java.lang.Thread.run (Thread.java:680)

Chủ đề này hiện đang ở trạng thái TIMED_WAITING và không được coi là hoạt động. Đó là lý do tại sao số lượng được phát ra bởi các câu lệnh nhật ký DataXceiver không bao gồm các loại luồng này. Nếu chúng trở nên hoạt động do máy khách gửi dữ liệu gửi, số luồng hoạt động sẽ tăng trở lại. Một điều khác cần lưu ý là luồng này không cần kết nối hoặc ổ cắm riêng biệt giữa máy khách và máy chủ. PacketResponder chỉ là một chuỗi ở phía máy chủ để nhận dữ liệu khối và truyền nó đến DataNode tiếp theo trong đường dẫn ghi.

Lệnh Hadoop fsck cũng có một tùy chọn để báo cáo những tệp nào hiện đang được mở để viết:

$ hadoop fsck / hbase -openforwrite
FSCK bắt đầu bởi larsgeorge từ /10.0.0.29 cho đường dẫn / hbase lúc Thứ Hai, ngày 05 tháng 3 22:59:47 CET 2012
…… / hbase / .logs / 10.0.0.29.60020,1330984111693 / 10.0.0.29% 3A60020.1330984118842 0 byte, 1 khối, OPENFORWRITE:……………………………… ..Tình trạng:KHỎE MẠNH
Tổng kích thước:2088783626 B
Tổng số:54
Tổng số tệp:45

>

Điều này không liên quan ngay đến luồng phía máy chủ bị chiếm dụng, vì chúng được phân bổ bởi ID khối. Nhưng bạn có thể thu thập được từ nó, rằng có một khối mở để viết. Lệnh Hadoop có các tùy chọn bổ sung để in ra các tệp thực và ID khối mà chúng bao gồm:

$ hadoop fsck / hbase -files -blocks
FSCK bắt đầu bởi larsgeorge từ /10.0.0.29 cho path / hbase lúc Thứ Ba, 06 Tháng Ba 10:39:50 CET 2012


/hbase/.META./1028785192/.tmp


/hbase/.META./1028785192/info
/hbase/.META./1028785192/info/4027596949915293355 36517 byte, 1 khối:OK
0. blk_5532741233443227208_4201 len =36517 repl =1


Tình trạng:KHỎE MẠNH
Tổng kích thước:2088788703 B
Tổng số dirs :54
Tổng số tệp:45 (Các tệp hiện đang được viết:1)
Tổng số khối (đã xác thực):64 (kích thước khối trung bình 32637323 B) (Tổng số khối tệp đang mở (chưa được xác thực):1)
Khối được sao chép tối thiểu:64 (100,0%)

Điều này mang lại cho bạn hai điều. Đầu tiên, bản tóm tắt nói rằng có một khối tệp đang mở tại thời điểm lệnh chạy - khớp với số lượng được báo cáo bởi tùy chọn “-openforwrite” ở trên. Thứ hai, danh sách các khối bên cạnh mỗi tệp cho phép bạn khớp tên luồng với tệp chứa khối đang được truy cập. Trong ví dụ này, khối có ID “blk_5532741233443227208_4201” được gửi từ máy chủ đến máy khách, ở đây là Máy chủ vùng. Khối này thuộc về HBase .META. bảng, như được hiển thị bằng đầu ra của lệnh Hadoop fsck. Sự kết hợp giữa JStack và fsck có thể đóng vai trò như một sự thay thế kém hiệu quả cho lsof (một công cụ trên dòng lệnh Linux để "liệt kê các tệp đang mở").

JStack cũng báo cáo rằng có một luồng DataXceiver, với PacketResponder đi kèm, cho ID khối “blk_-2005512129579433420_4199”, nhưng ID này bị thiếu trong danh sách các khối được fsck báo cáo. Điều này là do khối vẫn chưa hoàn thành và do đó không có sẵn cho người đọc. Nói cách khác, Hadoop fsck chỉ báo cáo về các khối hoàn chỉnh (hoặc được đồng bộ hóa [7] [8], đối với phiên bản Hadoop hỗ trợ tính năng này).

Quay lại HBase

Việc mở tất cả các vùng không cần nhiều tài nguyên trên máy chủ như bạn mong đợi. Nếu bạn quét toàn bộ bảng HBase, bạn buộc HBase phải đọc tất cả các khối trong tất cả các tệp HF:

Vỏ HBase:

hbase (main):003:0> scan 'usertable'

1000000 (các) hàng trong 1460,3120 giây

Nhật ký mã dữ liệu:

2012-03-05 14:42:20,580 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Số lượng kết nối đang hoạt động là:6
2012-03-05 14:43:23,293 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:7
2012 -03-05 14:43:23.299 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:8

2012-03-05 14:49:24,332 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0. 0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:11
2012-03-05 14:49:24.332 DEBUG org .apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:10
2012-03-05 14:49:59,987 DEBUG org.apache.hadoop.hdfs.server.datanod e.DataNode:Số lượng kết nối đang hoạt động là:11
2012-03-05 14:51:12.603 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:12
2012-03-05 14:51:12,605 DEBUG org.apache.hadoop.hdfs .server.datanode.DataNode:Số lượng kết nối đang hoạt động là:11
2012-03-05 14:51:46,473 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối hiện hoạt là:12

2012-03-05 14:56:59,420 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:15
2012-03-05 14:57:31,722 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:16
2012-03-05 14:58:24.909 DEBUG org.apache.hadoop.hdfs. server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số hành động kết nối ive là:17
2012-03-05 14:58:24,910 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:16

2012-03-05 15:04:17.688 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:21
2012-03-05 15:04:17.689 DEBUG org.apache .hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số kết nối đang hoạt động là:22
2012-03-05 15:04:54.545 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:21
2012-03-05 15:05:55.901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration (127.0.0.1:50010, storageID =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort =50075, ipcPort =50020):Số lượng kết nối đang hoạt động là :22
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Số lượng kết nối đang hoạt động là:21

Hiện tại, số lượng kết nối đang hoạt động đạt đến con số khó nắm bắt là 22. Lưu ý rằng số lượng này đã bao gồm chuỗi máy chủ, vì vậy chúng tôi vẫn còn thiếu một chút so với những gì chúng tôi có thể coi là tối đa lý thuyết - dựa trên số lượng tệp HBase phải xử lý.

Tất cả những điều đó có nghĩa là gì?

Vì vậy, bạn cần bao nhiêu “xciever (sic)”? Với việc bạn chỉ sử dụng HBase, bạn có thể chỉ cần theo dõi số liệu "lưu trữ" ở trên (bạn cũng nhận được thông qua Ganglia hoặc JMX) và thêm một vài phần trăm cho các tệp nhật ký trung gian và ghi trước. Điều này sẽ hoạt động đối với các hệ thống đang chuyển động. Tuy nhiên, nếu bạn xác định con số đó trên một hệ thống không hoạt động, được nén hoàn toàn và cho rằng đó là số tối đa, bạn có thể thấy con số này quá thấp khi bạn bắt đầu thêm nhiều tệp lưu trữ hơn trong quá trình nhấp nháy kho lưu trữ thông thường, tức là ngay sau khi bạn bắt đầu thêm dữ liệu vào các bảng HBase. Hoặc nếu bạn cũng sử dụng MapReduce trên cùng một cụm đó, tổng hợp nhật ký Flume, v.v. Bạn sẽ cần tính đến các tệp bổ sung đó và quan trọng hơn là mở các khối để đọc và ghi.

Lưu ý một lần nữa rằng các ví dụ trong bài đăng này đang sử dụng một Mã dữ liệu duy nhất, điều mà bạn sẽ không có trên một cụm thực. Để đạt được điều đó, bạn sẽ phải chia tổng số tệp lưu trữ (theo chỉ số HBase) cho số Mã dữ liệu bạn có. Ví dụ:nếu bạn có số tệp lưu trữ là 1000 và cụm của bạn có 10 Mã dữ liệu, thì bạn nên chấp nhận với mặc định là 256 luồng thu phát cho mỗi Mã dữ liệu.

Trường hợp xấu nhất sẽ là số lượng tất cả người đọc và người viết đang hoạt động, tức là những người hiện đang gửi hoặc nhận dữ liệu. Nhưng vì điều này khó xác định trước thời hạn, bạn có thể muốn xem xét xây dựng trong một khu dự trữ kha khá. Ngoài ra, vì quá trình viết cần thêm một chuỗi - mặc dù tồn tại ngắn hơn - (cho PacketResponder) nên bạn cũng phải tính đến điều đó. Vì vậy, một công thức hợp lý, nhưng khá đơn giản có thể là:

Công thức này tính đến việc bạn cần khoảng hai luồng cho một người viết đang hoạt động và một luồng khác cho một người đọc tích cực. Sau đó, giá trị này được tổng hợp và chia cho số DataNode, vì bạn phải chỉ định “dfs.datanode.max.xcievers” cho mỗi DataNode.

Nếu bạn quay lại ảnh chụp màn hình HBase RegionServer ở trên, bạn thấy rằng có 22 tệp lưu trữ. These are immutable and will only be read, or in other words occupy one thread only. For all memstores that are flushed to disk you need two threads – but only until they are fully written. The files are finalized and closed for good, cleaning up any thread in the process. So these come and go based on your flush frequency. Same goes for compactions, they will read N files and write them into a single new one, then finalize the new file. As for the write-ahead logs, these will occupy a thread once you have started to add data to any table. There is a log file per server, meaning that you can only have twice as many active threads for these files as you have RegionServers.

For a pure HBase setup (HBase plus its own HDFS, with no other user), we can estimate the number of needed DataXceiver’s with the following formula:

Since you will be hard pressed to determine the active number of store files, flushes, and so on, it might be better to estimate the theoretical maximum instead. This maximum value takes into account that you can only have a single flush and compaction active per region at any time. The maximum number of logs you can have active matches the number of RegionServers, leading us to this formula:

Obviously, the number of store files will increase over time, and the number of regions typically as well. Same for the numbers of servers, so keep in mind to adjust this number over time. In practice, you can add a buffer of, for example, 20%, as shown in the formula below – in an attempt to not force you to change the value too often.

On the other hand, if you keep the number of regions fixed per server[9], and rather split them manually, while adding new servers as you grow, you should be able to keep this configuration property stable for each server.

Final Advice &TL;DR

Here is the final formula you want to use:

It computes the maximum number of threads needed, based on your current HBase vitals (no. of store files, regions, and region servers). It also adds a fudge factor of 20% to give you room for growth. Keep an eye on the numbers on a regular basis and adjust the value as needed. You might want to use Nagios with appropriate checks to warn you when any of the vitals goes over a certain percentage of change.

Note:Please make sure you also adjust the number of file handles your process is allowed to use accordingly[10]. This affects the number of sockets you can use, and if that number is too low (default is often 1024), you will get connection issues first.

Finally, the engineering devil on one of your shoulders should already have started to snicker about how horribly non-Erlang-y this is, and how you should use an event driven approach, possibly using Akka with Scala[11] – if you want to stay within the JVM world. Bear in mind though that the clever developers in the community share the same thoughts and have already started to discuss various approaches[12][13].

Links:

  • [1] http://old.nabble.com/Re%3A-xceiverCount-257-exceeds-the-limit-of-concurrent-xcievers-256-p20469958.html
  • [2] http://ccgtech.blogspot.com/2010/02/hadoop-hdfs-deceived-by-xciever.html
  • [3] https://issues.apache.org/jira/browse/HDFS-1861 “Rename dfs.datanode.max.xcievers and bump its default value”
  • [4] https://issues.apache.org/jira/browse/HDFS-1866 “Document dfs.datanode.max.transfer.threads in hdfs-default.xml”
  • [5] http://hbase.apache.org/book.html#dfs.datanode.max.xcievers
  • [6] http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom
  • [7] https://issues.apache.org/jira/browse/HDFS-200 “In HDFS, sync() not yet guarantees data available to the new readers”
  • [8] https://issues.apache.org/jira/browse/HDFS-265 “Revisit append”
  • [9] http://search-hadoop.com/m/CBBoV3z24H1 “HBase, mail # user – region size/count per regionserver”
  • [10] http://hbase.apache.org/book.html#ulimit “ulimit and nproc”
  • [11] http://akka.io/ “Akka”
  • [12] https://issues.apache.org/jira/browse/HDFS-223 “Asynchronous IO Handling in Hadoop and HDFS”
  • [13] https://issues.apache.org/jira/browse/HDFS-918 “Use single Selector and small thread pool to replace many instances of BlockSender for reads”


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Apache HBase + Apache Hadoop + Xceivers

  2. Cách thực hiện:Kiểm tra các ứng dụng HBase bằng các công cụ phổ biến

  3. Giới thiệu về Apache HBase Snapshots

  4. Hadoop InputFormat &Các loại InputFormat trong MapReduce

  5. Điểm dừng tiếp theo - Xây dựng đường ống dữ liệu từ Edge đến Insight