Hiểu đúng về Remote (Distributed) Testing của JMeter

Thi thoảng có bạn nhắn tin hỏi về cách config trong JMeter để có thể làm được remote testing, hoặc giúp đỡ khi gặp lỗi trong quá trình làm remote testing. Hôm nay, mình sẽ viết thật kỹ về tất cả các thành phần và flow làm việc của Remote Testing để bạn có thể tự tin xử lý các lỗi có thể xảy ra (hoặc để chém gió lúc phỏng vấn).

Remote Testing ở JMeter là cách JMeter đẩy yêu cầu tạo load sang nhiều máy trong cùng 1 subnet để có thể tạo ra 1 lượng load lớn.

Mô hình này nhiều người thường dùng từ Master-Slave. Tuy nhiên từ sau năm 2020, hình như có vụ biểu tình của người da đen ở Mỹ thì người ta đã tránh dùng các từ ngữ có ý phân biệt chủng tộc nên Master-Slave được thay bằng nhiều cụm từ đồng nghĩa như Controller-Worker, primary-secondary. Tuy nhiên nếu bạn đọc trong docs về Remote Testing của JMeter, bạn sẽ không tìm thấy các cụm từ trên mà người ta dùng cụm từ Client-Server nên chốt lại:

Master=Controller=ClientSlave=Worker=Server

Image copied from https://www.blazemeter.com/blog/jmeter-distributed-testing-with-docker
  • Vì sao người ta lại dùng Client-Server? nghe có vẻ hơi ngược ngược.

Theo mình, nguyên nhân xuất phát từ việc JMeter là java app và nó dùng công nghệ Remote Method Invocation (RMI), giúp cho máy A có thể gọi vào method của 1 object ở máy B. RMI gồm 3 thành phần:

  • Client (máy A): nơi có nhu cầu gọi vào service
  • Server (máy B): nơi cung cấp service để làm 1 việc nào đó.
  • RMI registry (cũng ở máy B): nơi chứa thông tin các service của Server.

Trong TH của JMeter thì cả client và server đều là JMeter app nhưng run ở 2 nơi khác nhau (có thể cùng máy hoặc khác máy). Mình cứ tạm coi là 2 JMeter run ở 2 máy cho dễ hiểu.

  • Step 1: Ở máy server, JMeter nó sẽ khởi tạo 1 object có tên là RemoteJMeterEngineImpl và lưu địa chỉ tại RMI registry.
  • Step 2: từ máy client, JMeter sẽ gửi request lên RMI registry để lấy địa chỉ của object RemoteJMeterEngineImpl
  • Step 3: Khi có địa chỉ chính xác thì JMeter ở 2 máy Client và Server tự kết nối thông qua Socket và gửi nhận thông tin.

Vậy điều đầu tiên để có thể thực hiện được Remote Testing, đó là phải run được RMI registry trên máy Server máy client phải connect được vào RMI registry này.

RMI registry là 1 thứ được cung cấp bởi Java, không phải của riêng JMeter, nên mình sẽ có 2 lựa chọn:

  • Một là khởi tạo RMI registry cùng lúc với start JMeter thông qua run file jmeter-server.bat
  • Hai là tự start RMI registry riêng, rồi start JMeter sau. Follow theo hướng dẫn này.

Và RMI registry sử dụng default port là 1099. Nếu bạn run file jmeter-server.bat rồi bật powershell/CMD run lệnh netstat -ano bạn sẽ nhìn thấy như sau (đang nói ở trên máy server nhé).

  • Nếu port này đã bị sử dụng rồi (already in use) thì ta phải đổi port khác, ở file jmeter.properties hoặc user.properties. Ví dụ, mình đổi sang port 1664.
# To change the default port (1099) used to access the server:
server.rmi.port=1664

Bạn cũng có thể thay đổi rmi port thông qua setting server_port

RMI port to be used by the server (must start rmiregistry with same port)
server_port=1077

Note: chỉ sửa 1 trong 2 cái trên, vì server_port sẽ được ưu tiên hơn. Nếu cả 2 cùng được enable thì JMeter sẽ lấy giá trị của server_port trừ khi server_port=0.

  • Làm thế nào để client biết RMI registry đang ở đâu?

Bây giờ là đoạn config trên máy client, open file jmeter.properties, tìm đến config remote_hosts, sửa thành ip v4 của máy Server + port của RMI theo cú pháp host:port

# Remote Hosts - comma delimited
remote_hosts=192.168.0.30:1664

Sau đó vẫn ở trên máy client, run file jmeter.bat, bạn sẽ nhìn thấy

Tuy nhiên chỉ đến khi run thật thì mới biết là có thể connect được hay ko.

Còn 1 vấn đề nữa ở máy server, JMeter Engine (chính là cái object RemoteJMeterEngineImpl ở trên) sẽ được khởi tạo bằng default port = 0, có nghĩa là RMI sẽ dùng 1 cái dynamic port nào đó. Nếu cái port đó bị block bởi firewall thì bạn cần phải điền 1 port cố định rồi tạo rule để firewall không chặn port đó nữa.

By default, RMI uses a dynamic port for the JMeter server engine. This can cause problems for firewalls, so you can define the JMeter property server.rmi.localport to control this port number. it will be used as the local port number for the server engine.

https://jmeter.apache.org/usermanual/remote-test.html

Cách config port cho JMeter Engine ở trên Server.

# To use a specific port for the JMeter server engine, define
# the following property before starting the server:
server.rmi.localport=4000

Bài dài phết rồi đấy mà vẫn còn chưa xong đâu nhé. @@

Phía trên mới là chiều đi, từ Client đẩy thông tin đến Server để thực hiện run test, tuy nhiên còn có chiều ngược lại nữa, Server cần đẩy lại kết quả test cho Client nữa. Thực ra thì vẫn là flow như vậy thôi, chỉ có 1 điểm khác. Server sẽ gọi vào 2 objects của client: RemoteSampleListenerImpl & RemoteThreadsListenerImpl và 2 object này bạn có thể setting port cho chúng.

# Parameter that controls the base for RMI ports used by RemoteSampleListenerImpl and RemoteThreadsListenerImpl (The Controller)
# Default value is 0 which means ports are randomly assigned
# If you specify a base port, JMeter will (at the moment) use the ports that start one after the given base.
# You may need to open Firewall port on the Controller machine
client.rmi.localport=1234

Chốt lại, sơ đồ như sau:

Cuối cùng, Client và Server connect với nhau thông qua Socket, từ bản JMeter 4.0 thì connection này mặc định dùng SSL, do đó bạn cần phải setup keys và certificate để có thể connect được. Tuy nhiên, vì đều là máy trong mạng nội bộ nên mình thường tắt bỏ SSL luôn. Mình sẽ viết bài chi tiết về SSL, keys và certificate sau.

# Set this if you don't want to use SSL for RMI
server.rmi.ssl.disable=true

Ngoài ra còn 1 vài điểm mà bạn cần phải follow nếu không muốn gặp nhiều error trong lúc setup:

  • OS của các máy là giống nhau
  • Java version giống nhau
  • JMeter version giống nhau
  • Tắt firewall

Những lỗi thường gặp:

1. Sai version của JMeter

Error in rconfigure() method java.lang.ClassCastException: cannot assign instance of java.util.HashMap to field org.apache.jorphan.collections.HashTree.data of type java.util.IdentityHashMap in instance of org.apache.jorphan.collections.ListedHashTree

Ví dụ máy client là JMeter 5.5 còn máy server JMeter 5.6.

Cách fix: để 2 máy client và server đúng version JMeter.

2. Refuse to connect

Nguyên nhân là do Firewall block connection, 2 máy không connection được.

Cách fix:

  • Tắt firewall của cả 2 máy
  • Hoặc mở port như phía trên đã có nói

Cách ping theo port, mở powershell:

Test-Netconnection <ip> -p <port>

Ví dụ:
Test-Netconnection 10.69.40.113 -p 1099

Nếu máy client là laptop của bạn, firewall bị quản lý bởi công ty thì việc điều chỉnh firewall là không khả thi. Mình đã thử ở máy mình, mở port được vài phút là mọi thứ lại bị clear.

3. Đã start test bên máy server, nhưng jmeter bên máy client bị treo, không kết thúc test.

Nguyên nhân là máy client gửi được lệnh cho server nhưng server thì không tìm thấy client để gửi lại kết quả. Vì máy hostname của máy client khi start mặc định là 127.0.0.1 –> máy server không tìm thấy client.

Cách fix: luôn luôn đặt hostname cho rmi của máy server và máy client theo ip.

  • Cách 1:

Thêm key sau vào trong file user.properties (recommended) hoặc jmeter.properties

java.rmi.server.hostname=<ip_server_machine>
  • Cách 2: điền trực tiếp ip lúc start jmeter.

Máy server:

.\jmeter-server.bat -Djava.rmi.server.hostname=<ip_server_machine>

Ví dụ:
.\jmeter-server.bat -Djava.rmi.server.hostname=10.69.40.113

Máy client:

.\jmeter.bat -Djava.rmi.server.hostname=<ip_client_machine>

Ví dụ:
.\jmeter.bat -Djava.rmi.server.hostname=10.69.40.90

Kết luận, mình nghĩ đó là tất cả những gì mà bạn cần phải biết về Remote (distributed) testing, cách nó hoạt động và cách config. Nếu cần tăng load thì cứ tăng số lượng máy server và connect thôi. Chúc bạn thành công và đừng quên 1 like cho người viết bài. (tui đã mất 1 ngày để đọc code và viết bài này T__T )

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments