728x90
반응형
이전 글에 이어서 특정 endpoint를 호출하는 커스텀 성능 테스트에 대해 기록한다.
https://whitepro.tistory.com/1115
keycloak benchmark 성능 테스트 w/ kubernetes
whitepro.tistory.com
소스 코드를 까서, get 요청을 아래처럼 변경해주었다. 주석 부분이 기본으로 있던 Get 요청이다.
package keycloak.scenario.basic
import keycloak.scenario.{CommonSimulation, KeycloakScenarioBuilder}
import org.keycloak.benchmark.Config
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.core.structure.ChainBuilder
class Get extends CommonSimulation {
// setUp("Get - " + Config.basicUrl, new KeycloakScenarioBuilder()
// .basicGet(Config.basicUrl)
// .userThinkPause())
val loginChain: ChainBuilder = new KeycloakScenarioBuilder()
.openLoginPage(true)
.loginUsernamePassword("user-0", "password")
.exchangeCode()
.build()
val userInfoChain: ChainBuilder = repeat(Config.repeatCount) {
new KeycloakScenarioBuilder().userinfo().build()
}
val scenarioBuilder = scenario("UserInfo - Single User")
.exec(loginChain)
.exec(userInfoChain)
setUp(
scenarioBuilder.inject(atOnceUsers(1)) // 여기는 필요한 만큼 조정 가능
)
}
그리고 KeycloakScenarioBuilder에 들어가서 아래 부분에 아래처럼 메서드를 추가해준다. 맨 아래 basicGet 메서드 밑에 써주면 된다.
def loginUsernamePassword(username: String, password: String): KeycloakScenarioBuilder = {
chainBuilder = chainBuilder
.exec(session => session.setAll("username" -> username, "password" -> password))
.exec(http("Browser posts correct credentials")
.post("#{login-form-uri}")
.headers(KeycloakScenarioBuilder.UI_HEADERS)
.formParam("username", "#{username}")
.formParam("password", "#{password}")
.formParam("login", "Log in")
.check(
status.in(200 to 302),
header("Location").optional.saveAs("locationHeader"),
headerRegex("Location", "code=([^&]+)").optional.saveAs("code")
)
.check(bodyString.saveAs("responseBody"))
)
.exec(session => {
val existingCode = session("code").asOption[String]
val referer = session("gatling.http.referer").asOption[String]
val fallbackCode = referer
.flatMap(_.split("code=").lift(1))
.map(_.split("&").headOption.getOrElse("")).getOrElse("")
val finalCode = existingCode.getOrElse(fallbackCode)
if (finalCode.isEmpty) {
println("❌ code not found in header or referer")
} else {
println(s"✅ code extracted: $finalCode")
}
session.set("code", finalCode)
})
.exitHereIfFailed
this
}
def userinfo(): KeycloakScenarioBuilder = {
chainBuilder = chainBuilder.exec(
http("UserInfo")
.get("#{keycloakServer}/realms/#{realm}/protocol/openid-connect/userinfo")
.header("Authorization", "Bearer #{accessToken}") //accessToken으로 exchangeCode에서 받아온 key 명을 그대로 사용
.check(status.is(200))
)
this
}
요청은 아래처럼 날린다.
./kcb.sh \
--scenario=keycloak.scenario.basic.Get \
--server-url={서버 주소} \
--client-id=client-0 \
--client-secret=client-0-secret \
--user-password=password \
--log-http-on-failure \
-Drepeat-count=500
Single User로 처리하는데, 이것은 userinfo 엔드포인트는 로그인이 필요하기 때문이다. 여러 명의 유저로 동시에 요청을 할려면 모든 유저가 로그인을 해야하므로 무거운 login 요청이 테스트에 껴서 정확한 측정이 불가능하게 된다.
반복 횟수를 조정하게 되므로 초당 유저수 등을 조절할 수 없어 정확한 성능테스트가 불가한 점이 아쉽다.
여러 유저로 요청하기
혹여나 그래도 필요하다면 아래처럼 작성하여 모든 유저들이 로그인 및 userinfo endpoint를 호출하도록 하면 된다.
package keycloak.scenario.basic
import keycloak.scenario.{CommonSimulation, KeycloakScenarioBuilder}
import org.keycloak.benchmark.Config
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.core.structure.ChainBuilder
class Get extends CommonSimulation {
// setUp("Get - " + Config.basicUrl, new KeycloakScenarioBuilder()
// .basicGet(Config.basicUrl)
// .userThinkPause())
val loginChain: ChainBuilder = new KeycloakScenarioBuilder()
.openLoginPage(true)
.loginUsernamePassword("user-0", "password")
.exchangeCode()
.build()
val userInfoChain: ChainBuilder = repeat(Config.repeatCount) {
new KeycloakScenarioBuilder().userinfo().build()
}
val scenarioBuilder = scenario("UserInfo - Single User")
.exec(loginChain)
.exec(userInfoChain)
setUp(
scenarioBuilder.inject(
rampUsersPerSec(1).to(Config.usersPerSec).during(Config.rampUpPeriod)
)
)
}
이때 명령어의 인자는 기존 성능테스트에서처럼 --users-per-realm, --users-per-sec를 포함하여 주면 된다.
./kcb.sh --scenario=keycloak.scenario.basic.Get --server-url={server 주소}--client-id=client-0 --client-secret=client-0-secret --log-http-on-failure --users-per-realm=1000 --users-per-sec=50
728x90
반응형
'Programming-[Backend] > Keycloak' 카테고리의 다른 글
Keycloak Infinispan 통신 방식 정리: udp, jdbc-ping, kubernetes (0) | 2025.04.27 |
---|---|
keycloak upstream header is too big. 502 Gateway Error w/ nextAuth (0) | 2025.04.24 |
Keycloak CODE_TO_TOKEN_ERROR: cookie와 roles (0) | 2025.04.21 |
keycloak benchmark 성능 테스트 w/ kubernetes (0) | 2025.04.03 |
[TIL] Keycloak - Google IDP Social Login시 prompt 설정 (0) | 2025.03.17 |