Trước khi release software cho end-users, chúng ta thực hiện các loại test khác nhau để đảm bảo application bug-free và meet business requirements. Mặc dù chúng ta làm nhiều test, chúng ta không thể chắc software stable mà không có user thực sự dùng nó. Sau khi end-users bắt đầu dùng application, nhiều thứ có thể khiến application không behave như chúng ta expect, vì một số lý do sau:
- User behavior có thể unpredictable;
- Users distributed across different locations;
- Số lượng lớn user có thể dùng application cùng lúc.
Cho large-scale applications, những điều này rất crucial để biết trước full-fledged release. Để ensure application works as expected, chúng ta cần consider một vài điều khi roll out functionality:
- Phased rollout - Trong phased rollout, application có thể tested bởi một phần nhỏ user trước khi everyone get access. Điều này giúp determine user behavior.
- Load testing - Trong phased rollout, chúng ta có thể determine user behavior, nhưng chúng ta không thể biết platform works như thế nào khi nhiều user dùng application cùng lúc từ different locations
Load Testing Là Gì, Và Khác Với Performance Testing Như Thế Nào?
Ba thuật ngữ sau có thể nghe giống nhau, nhưng chúng khác nhau:
- Performance Testing,
- Load Testing, và
- Stress Testing.
Performance Testing là general testing mechanism dùng để assess application perform như thế nào với given input. Điều này có thể done với single-user dùng application hoặc multiple users. Nó conducted để assess certain metrics, như response time và CPU/memory usage. Load/stress testing là subset của performance testing.
Load Testing được conducted để ensure application perform as expected với specified number of users dùng application concurrently over specified length of time. Nó helps determine how many users system có thể handle.
Stress Testing và load testing closely related. Stress testing có thể done với similar mechanism như load testing, nhưng goal của testing khác. Goal của load testing là determine whether application works với specified number of users, whereas stress testing conducted để determine how application behaves và handles failure after load limit is hit.
Based on ramp-up period, performance testing có thể categorized as either spike test hoặc soak test. Sudden spike in users over short length of time là spike test, và slow ramp-up của users over longer duration là soak test.
Tại Sao Performance Testing Quan Trọng?
Trên một Rails project, chúng ta anticipate lots of growth in users in near future. Chúng ta muốn ensure application perform as expected, và crucial functionality not lost với increased number of users. Vậy, làm sao ensure này? Chúng ta performed load test và check whether application could handle given increase in users. Performance testing có thể important trong nhiều case khác:
- Nếu application expected có spike in users vào specific day, như Black Friday, spike testing application với brief ramp-up period có thể giúp tìm potential issues trong system.
- Load testing helps identify bugs trong system not visible hoặc very minimal khi chỉ vài user dùng.
- Nó allows evaluate how platform's speed bị impacted bởi increased load. Nếu application slow, chúng ta could lose customers.
- Nó helps assess how system works under increased load và if system crashes với high CPU hoặc memory usage khi có 10,000 users.
- Chi phí running application cho specific number of users có thể determined với load testing.
Chúng ta able to find bug trong Rails app khi performing load test. Tôi sẽ describe similar scenario nơi chúng ta identified issue. Một hotel booking app có open booking process, và khi chỉ vài user try book room, everything fine. Tuy nhiên, khi multiple users try book same room, two different users able book it successfully. Bằng load testing app, chúng ta able identify problem và fix it early stage, trước khi release feature.
Dùng Apache JMeter Load Test Rails App
JMeter là Apache 2.0-licensed open-source load testing tool. Nó cung cấp thread-based load testing. Với thread-based testing, chúng ta dễ dàng simulate stress system would be under khi lots of users dùng application simultaneously. JMeter cũng cung cấp good reporting của test results.
Chúng ta sẽ look into làm sao dùng Apache JMeter perform load tests để identify potential issues với system và response time của application bằng cách simulate lots of users dùng system.
JMeter có thể download từ link: https://jmeter.apache.org/download_jmeter.cgi#binaries
Một Số JMeter Terminologies Cần Biết
- Test Plan Test plan là top-level thing bên trong, chúng ta define load testing components. Global configs và variables defined here.
- Thread Group dùng để define threads và configs, như numbers of threads, ramp-up periods, delay between threads, và loops. This can be treated as number of parallel users bạn muốn run load test with.
- Sampler là gì một single thread executes. Có different types of samplers, như HTTP requests, SMTP requests, hoặc TCP requests.
- Pre/Post Processor dùng để execute something before hoặc after sampler runs. Post-processors có thể take in response data từ one API call và pass it along cho use on next one.
- Listener listen to response từ sampler và cung cấp aggregated reports của response time hoặc response từ each thread.
- Assertion có thể useful để validate response data là gì chúng ta expected từ sampler.
- Config Element define configurations, như HTTP header, HTTP cookies, hoặc CSV dataset configurations.
Để run load test, chúng ta cần first tạo JMX file nơi chúng ta define above-described JMeter terminologies.
Chuẩn Bị JMX File Cho Load Test
JMX là JMeter project file viết trong XML format. Viết JMX file manually có thể difficult, vì vậy chúng ta sẽ dùng JMeter interface để tạo file.
Mở JMeter interface và locate test plan. Bên trong test plan, chúng ta sẽ add threads và its load test configurations.
JMeter interface for creating test plans
Test plan có thể renamed theo gì chúng ta load test for. Chúng ta có thể configure thread group(Users). Bạn có thể keep default settings here và move on to create threads group.
Add -> Threads(Users) -> Thread Group
Trong thread group, mặc định sẽ có single thread specified. Thay đổi number as needed để simulate number of users accessing app.
Vì chúng ta sẽ load test web-based Rails app, chúng ta sẽ add HTTP sampler. Chúng ta có thể add sampler, which will be inside ThreadGroup. Add HTTP Sampler bằng cách navigate:
Add -> Sampler -> HTTP Request
Ở đây, chúng ta configure IP hoặc domain chúng ta load test on và HTTP method và any request body required cho HTTP endpoint.
Cuối cùng, để view report của load test, chúng ta có thể add listener to thread group.
Add -> Listener -> View Result Tree
View result tree sẽ display response time của each thread. Chúng ta có thể add other kinds of reports here as well. 'View result tree' should only be used for debugging proposes và not cho actual testing.
Theo cách này, chúng ta có thể tạo simple test plan và execute it. Chỉ cần hit play icon trong top bar của JMeter để execute test.
Điều Cần Cân Nhắc Trước Load Test Rails App
Ví dụ trên rất simple, single endpoint HTTP request. Trong case của Rails app, endpoints chúng ta muốn test locked with authentication. Do đó, chúng ta cần ensure chúng ta có following things in place:
- Web cookie - HTTP endpoints cần có cookie header trước khi chúng ta perform load test on them. JMeter cung cấp functionality để add cookie once user logged in. In next section, chúng ta sẽ look into làm sao record browser request và convert to JMX file cho load test. Chúng ta cũng sẽ cover cookie recording.
- Rails CSRF token - Rails protects app from security vulnerability bằng cách cung cấp CSRF token, vì vậy chúng ta cần ensure request có CSRF authentication trong header trước perform load test. CSRF token này present trong
headerbên trongmetatag trong HTML.
Rails CSRF Token có thể fetched trong JMeter bằng post-processor. Right-click on HTTP Request load web page containing CSRF token, và select Add -> Post Processor -> Regular Expression Extractor. Ở đây, bạn có thể add following regular expression extractor configs để read CSRF value từ header meta tag:
- Reference Name:
csrf_value - Regular Expression:
name="csrfToken" content="(.+?)" - Template:
$1$ - Match No:
1
Bây giờ, variable csrf_value có thể dùng để make request.
Recording Requests Từ Browser Tạo JMX File
Với fewer HTTP endpoints, có thể simple tạo JMX file từ JMeter interface. Tuy nhiên, cho larger test case, này có thể difficult. Cũng có chance chúng ta could miss actual requests made while user uses application. Chúng ta muốn actual requests made từ browser được recorded và JMX file created automatically.
JMeter có thể added as proxy giữa Rails app và browser. Với này, all requests sẽ forwarded to Rails server bởi JMeter. This also called MITM(man in the middle) attack.
JMeter Recording
Để tạo recording trong JMeter, go to file -> templates -> recording và click create. Specify hostname bạn recording. This will automatically generate a few things for you, including cookie manager. Cookie manager sẽ save cookie required cho authentication.
Verify HTTPs Requests Với JMeter SSL Certificate
Request này chúng ta make từ browser sẽ forwarded to JMeter, và JMeter sẽ forward it to web service và record requests để chúng ta có thể run load test từ JMeter recording. Nếu application yêu cầu https protocol cho SSL connections, thì certificate cần added to browser. Để add certificate, let us open Firefox hoặc any other browser. In Firefox, Go to settings > Privacy > Manage certificate và add JMeter certificate để browser sẽ recognize certificate generated by JMeter.
Enter cmd + sht + g và enter path /usr/local/Cellar/jmeter/5.2/libexec/bin/jmeter để add certificate
Configure Firefox Dùng JMeter Làm Proxy
Tiếp theo, chúng ta cần forward request từ Firefox đến JMeter recording script. This can be done bằng cách configure proxy trong Firefox. Open Firefox và go to Preferences -> Advanced -> Connection(settings). Ở đây, set HTTP Proxy to "localhost" và port to "8080" và check "Use this proxy server for all protocols".
Bây giờ, chúng ta có thể go to JMeter và Script recording section từ template chúng ta chose earlier. Once we hit start button, JMeter begins accepting incoming requests. Khi we go to Firefox và browse application we are load testing, this will record và convert it to JMX file, which we can run for load testing.
Distributed Load Testing Với JMeter
Khi running test, chúng ta có thể perform test từ một local machine. Làm này okay khi preparing test plan, nhưng khi running actual test, chúng ta cần change it. Performing load tests trên single machine sẽ có hardware limitations (i.e., CPU và memory) và request location limitations. These tests are run để simulate traffic của actual users dùng application. Cho purpose này, chúng ta cần distribute tests to different servers và have single place để view all results.
JMeter cung cấp primary node cho orchestrating test và multiple secondary nodes cho running test. This helps simulate real users dùng application. Chúng ta có thể distribute testing servers to different regions close to actual users.
JMeter Distributed testing
Để perform distributed test, begin by installing JMeter on both primary và secondary servers.
Things to do on secondary server:
- Go to
jmeter/binvà executejmeter-servercommand. This will start server to execute test. - Nếu any CSV input needed cho test, add these files to this server.
Things to do on primary server:
- Go to jmeter/bin directory và open
jmeter.propertiesfile. - Edit line containing
remote_hostsvà add IPs of secondary servers, separated by commasremote_hosts=<s1_ip>,<s2_ip>. - Run JMeter test.
Secondary server sẽ responsible cho running actual test, và primary server sẽ aggregate reports.
Để perform load testing, chúng ta should always use CLI command thay vì trigger test từ UI, as this can cause performance problems cho load testing servers. Chúng ta có thể dùng JMeter command specifying JMX filename:
> jmeter -n -t path/to/test.jxm -r
HOẶC
> jmeter -n -t path/to/test.jxm -R s1_ip,s2_ip,…
-r uses remote server specified in jmeter.properties
-n will run it without GUI mod
-t path to jmx file
Chuyện Chọn Puma vs. Unicorn Cho Rails Server
Puma và Unicorn là hai web server khác nhau cho Rails. Cả hai có benefits, vậy làm sao decide cái nào best? Nó depends on application. Một số application work best với Unicorn, và一些 work best với Puma. Chúng ta phải choose giữa Unicorn và Puma cho một Rails app, và chúng ta did so based on data obtained from load testing. Chúng ta performed load test trên Rails app once with Unicorn và other time using Puma. Only thing that we changed was web server on Rails app.
Chúng ta got following result from this test:
Response time different between puma and unicorn
Chúng ta found that Puma performs better cho Rails app khi có large number of users on platform. This means we will be able to handle more users với fewer number of application servers.
Note: This depends on the type of server instance you are using and what kind of business logic processing the app performs.
Một Số Common Failures Gặp Khi Stress Rails App Và Cách Khắc Phục
- Unoptimized database query
- Eliminate the n+1 query problem.
- Add an index according to the access pattern.
- Use a Redis-like caching layer in front of the database.
- Slow ruby code performance
- Memoize để optimize code.
- Figure out the o(n^2) complexity và use optimal algorithms.
- Trong micro-service architectures, có thể lots of HTTP calls giữa services. Network calls are slow.
- Reduce number of HTTP calls bằng cách dùng messaging system cho microservices.
- Same record created twice khi created concurrently.
- Add database-unique constraint.
- Utilize FIFO event(queue)-based resource creation.
- Use background processing, như Sidekiq, whenever possible.
- Define SLA cho API response times và include performance testing as part of development lifecycle.
Môi Trường Nào Nên Dùng Cho Load Testing?
Perform load test trong production environment không ideal choice vì nó could cause issues và even downtime in production. Chúng ta không want create problems in production environment, nhưng chúng ta vẫn want ensure test report reflects true data, similar to production. Cho load/stress tests, recommended to make replica environment of production. This includes things like:
- The number of application servers.
- The database server's hardware specifications, including replicas.
- Production-like data in testing database. This should include nearly equal data volume as encountered in production.
Tạo production-like environment có thể challenging và costly. Vì vậy, based on what we are load testing, infrastructure touching those components only can be upgraded to production-like. It saves cost. Better to load/stress test your app once every three months. Tuy nhiên, performance testing với single user và validating that response time is under defined standard (something like 200ms) là something we need to add to development cycle.
Khi load testing, chúng ta cũng cần data-points, như CPU/memory usage của target server. Spike in memory/CPU usage can cause application crash. Để measure hardware KPIs, add monitoring tools, như Prometheus, trước khi start load test.
Apache JMeter là powerful tool cho load testing. Chúng ta used Apache JMeter cho load testing Rails apps, nhưng nó có thể dùng để perform load/stress testing của application build on any stack. Load testing helps make data-powered decisions in application. Load testing có thể sound scary, nhưng với a little investment in the beginning, it can add a lot of stability và reliability to application in the long-term.