gitlab 인터페이스에 대한 동시 요청이 오류 500 내부 서버 오류를 보고합니다.

구성 환경

Gitalb 14.9
는 docker에 의해 구축되었으며 사용되는 데이터베이스는 내장 postgresql입니다.
여기에 이미지 설명 삽입

문제 배경

최근에 자체 개발한 시스템에서 gitlab의 api 인터페이스 호출을 요청하면, 특히 같은 리소스를 동시에 요청하는 경우 여기에서 subgroup 리소스를 동시에 생성하고 있는데 500 오류가 나는 것을 발견했습니다. 처음에 저는 제가 개발한 시스템 코드인줄 알았는데 부정확한 데이터로 인한 500 에러는 크게 신경쓰이지 않습니다. 그런데 최근 이런 현상이 다시 나타나니 오류 원인을 확인해 보시기 바랍니다.

오류 발생 환경 시뮬레이션

그런 다음 스트레스 테스트를 통해 실제로 동시 호출로 인한 문제인지 확인하십시오. 먼저 0.01초 이내에 5개의 스레드를 동시에 시작하여 하위 그룹 리소스 생성을 요청합니다.

여기에 이미지 설명 삽입

이 오류는 소량의 동시성에서 직접 재현되었습니다. 첫 번째 요청만 정상적으로 결과를 반환하고 나머지 4개의 요청은 500 Internal Error를 보고한 것을 알 수 있습니다.
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

오류의 원인 찾기

자체 시스템 오류
여기에 이미지 설명 삽입

/var/log/gitlab/nginx/gitlab_access.log에 있는 gitlab의 nginx 로그에서 이 요청이 실제로 500으로 반환됨을 알 수 있습니다.
여기에 이미지 설명 삽입

gitlab에는 gitlab-rails 모듈이 있으며,
이 모듈 아래의 api_json.log 로그 파일에서 오류 원인을 찾았습니다.
여기에 이미지 설명 삽입

{
	"time": "2023-07-19T05:19:06.173Z",
	"severity": "INFO",
	"duration_s": 0.08902,
	"db_duration_s": 0.0557,
	"view_duration_s": 0.03332,
	"status": 500,
	"method": "POST",
	"path": "/api/v4/groups",
	"params": [{
		"key": "path",
		"value": "gcptest071902"
	}, {
		"key": "name",
		"value": "gcptest071902"
	}, {
		"key": "parent_id",
		"value": 234
	}],
	"host": "wx8vm00001.apac.bosch.com",
	"remote_ip": "10.4.103.206, 127.0.0.1",
	"ua": "python-requests/2.28.1",
	"route": "/api/:version/groups",
	"user_id": 1,
	"username": "root",
	"exception.class": "ActiveRecord::RecordNotUnique",
	"exception.message": "PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint \"index_namespaces_name_parent_id_type\"\nDETAIL:  Key (name, parent_id, type)=(gcptest071902, 234, Group) already exists.\n",
	"exception.backtrace": ["lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:67:in `block (2 levels) in <class:ConnectionProxy>'", "lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:77:in `transaction'", "app/services/groups/create_service.rb:39:in `block in execute'", "lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:77:in `transaction'", "lib/gitlab/database.rb:309:in `block in transaction'", "lib/gitlab/database.rb:308:in `transaction'", "app/models/concerns/cross_database_modification.rb:99:in `transaction'", "app/services/groups/create_service.rb:38:in `execute'", "lib/api/groups.rb:63:in `create_group'", "lib/api/groups.rb:207:in `block (2 levels) in <class:Groups>'", "lib/api/api_guard.rb:213:in `call'", "lib/gitlab/metrics/elasticsearch_rack_middleware.rb:16:in `call'", "lib/gitlab/middleware/rails_queue_duration.rb:33:in `call'", "lib/gitlab/middleware/memory_report.rb:13:in `call'", "lib/gitlab/middleware/speedscope.rb:13:in `call'", "lib/gitlab/request_profiler/middleware.rb:17:in `call'", "lib/gitlab/database/load_balancing/rack_middleware.rb:23:in `call'", "lib/gitlab/metrics/rack_middleware.rb:16:in `block in call'", "lib/gitlab/metrics/web_transaction.rb:46:in `run'", "lib/gitlab/metrics/rack_middleware.rb:16:in `call'", "lib/gitlab/jira/middleware.rb:19:in `call'", "lib/gitlab/middleware/go.rb:20:in `call'", "lib/gitlab/etag_caching/middleware.rb:21:in `call'", "lib/gitlab/middleware/query_analyzer.rb:11:in `block in call'", "lib/gitlab/database/query_analyzer.rb:46:in `within'", "lib/gitlab/middleware/query_analyzer.rb:11:in `call'", "lib/gitlab/middleware/multipart.rb:173:in `call'", "lib/gitlab/middleware/read_only/controller.rb:50:in `call'", "lib/gitlab/middleware/read_only.rb:18:in `call'", "lib/gitlab/middleware/same_site_cookies.rb:27:in `call'", "lib/gitlab/middleware/handle_malformed_strings.rb:21:in `call'", "lib/gitlab/middleware/basic_health_check.rb:25:in `call'", "lib/gitlab/middleware/handle_ip_spoof_attack_error.rb:25:in `call'", "lib/gitlab/middleware/request_context.rb:21:in `call'", "lib/gitlab/middleware/webhook_recursion_detection.rb:15:in `call'", "config/initializers/fix_local_cache_middleware.rb:11:in `call'", "lib/gitlab/middleware/compressed_json.rb:26:in `call'", "lib/gitlab/middleware/rack_multipart_tempfile_factory.rb:19:in `call'", "lib/gitlab/middleware/sidekiq_web_static.rb:20:in `call'", "lib/gitlab/metrics/requests_rack_middleware.rb:77:in `call'", "lib/gitlab/middleware/release_env.rb:13:in `call'"],
	"exception.sql": "/*application:web,correlation_id:01H5P9CWAR3B4123CHYQSZKYH5,endpoint_id:POST /api/:version/groups,db_config_name:main*/ INSERT INTO \"namespaces\" (\"name\", \"path\", \"created_at\", \"updated_at\", \"type\", \"visibility_level\", \"description_html\", \"parent_id\", \"cached_markdown_version\") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING \"id\"",
	"queue_duration_s": 0.009978,
	"redis_calls": 5,
	"redis_duration_s": 0.001121,
	"redis_read_bytes": 609,
	"redis_write_bytes": 304,
	"redis_cache_calls": 3,
	"redis_cache_duration_s": 0.000656,
	"redis_cache_read_bytes": 609,
	"redis_cache_write_bytes": 198,
	"redis_shared_state_calls": 2,
	"redis_shared_state_duration_s": 0.000465,
	"redis_shared_state_write_bytes": 106,
	"db_count": 15,
	"db_write_count": 3,
	"db_cached_count": 0,
	"db_replica_count": 0,
	"db_primary_count": 15,
	"db_main_count": 15,
	"db_main_replica_count": 0,
	"db_replica_cached_count": 0,
	"db_primary_cached_count": 0,
	"db_main_cached_count": 0,
	"db_main_replica_cached_count": 0,
	"db_replica_wal_count": 0,
	"db_primary_wal_count": 0,
	"db_main_wal_count": 0,
	"db_main_replica_wal_count": 0,
	"db_replica_wal_cached_count": 0,
	"db_primary_wal_cached_count": 0,
	"db_main_wal_cached_count": 0,
	"db_main_replica_wal_cached_count": 0,
	"db_replica_duration_s": 0.0,
	"db_primary_duration_s": 0.056,
	"db_main_duration_s": 0.056,
	"db_main_replica_duration_s": 0.0,
	"cpu_s": 0.043004,
	"mem_objects": 15895,
	"mem_bytes": 1253816,
	"mem_mallocs": 4559,
	"mem_total_bytes": 1889616,
	"pid": 413885,
	"correlation_id": "01H5P9CWAR3B4123CHYQSZKYH5",
	"meta.user": "root",
	"meta.client_id": "user/1",
	"meta.caller_id": "POST /api/:version/groups",
	"meta.remote_ip": "10.4.103.206",
	"meta.feature_category": "subgroups",
	"content_length": "68",
	"request_urgency": "default",
	"target_duration_s": 1
}

동시에 이 오류는 이 모듈 아래의 exceptions_json.log 로그 파일에서도 찾을 수 있습니다.

{
	"severity": "ERROR",
	"time": "2023-07-19T05:19:06.171Z",
	"correlation_id": "01H5P9CWAR3B4123CHYQSZKYH5",
	"exception.class": "ActiveRecord::RecordNotUnique",
	"exception.message": "PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint \"index_namespaces_name_parent_id_type\"\nDETAIL:  Key (name, parent_id, type)=(gcptest071902, 234, Group) already exists.\n",
	"exception.backtrace": ["lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:67:in `block (2 levels) in \u003cclass:ConnectionProxy\u003e'", "lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:77:in `transaction'", "app/services/groups/create_service.rb:39:in `block in execute'", "lib/gitlab/database/load_balancing/connection_proxy.rb:126:in `block in write_using_load_balancer'", "lib/gitlab/database/load_balancing/load_balancer.rb:112:in `block in read_write'", "lib/gitlab/database/load_balancing/load_balancer.rb:172:in `retry_with_backoff'", "lib/gitlab/database/load_balancing/load_balancer.rb:110:in `read_write'", "lib/gitlab/database/load_balancing/connection_proxy.rb:125:in `write_using_load_balancer'", "lib/gitlab/database/load_balancing/connection_proxy.rb:77:in `transaction'", "lib/gitlab/database.rb:309:in `block in transaction'", "lib/gitlab/database.rb:308:in `transaction'", "app/models/concerns/cross_database_modification.rb:99:in `transaction'", "app/services/groups/create_service.rb:38:in `execute'", "lib/api/groups.rb:63:in `create_group'", "lib/api/groups.rb:207:in `block (2 levels) in \u003cclass:Groups\u003e'", "lib/api/api_guard.rb:213:in `call'", "lib/gitlab/metrics/elasticsearch_rack_middleware.rb:16:in `call'", "lib/gitlab/middleware/rails_queue_duration.rb:33:in `call'", "lib/gitlab/middleware/memory_report.rb:13:in `call'", "lib/gitlab/middleware/speedscope.rb:13:in `call'", "lib/gitlab/request_profiler/middleware.rb:17:in `call'", "lib/gitlab/database/load_balancing/rack_middleware.rb:23:in `call'", "lib/gitlab/metrics/rack_middleware.rb:16:in `block in call'", "lib/gitlab/metrics/web_transaction.rb:46:in `run'", "lib/gitlab/metrics/rack_middleware.rb:16:in `call'", "lib/gitlab/jira/middleware.rb:19:in `call'", "lib/gitlab/middleware/go.rb:20:in `call'", "lib/gitlab/etag_caching/middleware.rb:21:in `call'", "lib/gitlab/middleware/query_analyzer.rb:11:in `block in call'", "lib/gitlab/database/query_analyzer.rb:46:in `within'", "lib/gitlab/middleware/query_analyzer.rb:11:in `call'", "lib/gitlab/middleware/multipart.rb:173:in `call'", "lib/gitlab/middleware/read_only/controller.rb:50:in `call'", "lib/gitlab/middleware/read_only.rb:18:in `call'", "lib/gitlab/middleware/same_site_cookies.rb:27:in `call'", "lib/gitlab/middleware/handle_malformed_strings.rb:21:in `call'", "lib/gitlab/middleware/basic_health_check.rb:25:in `call'", "lib/gitlab/middleware/handle_ip_spoof_attack_error.rb:25:in `call'", "lib/gitlab/middleware/request_context.rb:21:in `call'", "lib/gitlab/middleware/webhook_recursion_detection.rb:15:in `call'", "config/initializers/fix_local_cache_middleware.rb:11:in `call'", "lib/gitlab/middleware/compressed_json.rb:26:in `call'", "lib/gitlab/middleware/rack_multipart_tempfile_factory.rb:19:in `call'", "lib/gitlab/middleware/sidekiq_web_static.rb:20:in `call'", "lib/gitlab/metrics/requests_rack_middleware.rb:77:in `call'", "lib/gitlab/middleware/release_env.rb:13:in `call'"],
	"exception.sql": "/*application:web,correlation_id:01H5P9CWAR3B4123CHYQSZKYH5,endpoint_id:POST /api/:version/groups,db_config_name:main*/ INSERT INTO \"namespaces\" (\"name\", \"path\", \"created_at\", \"updated_at\", \"type\", \"visibility_level\", \"description_html\", \"parent_id\", \"cached_markdown_version\") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING \"id\"",
	"user.username": "root",
	"tags.program": "web",
	"tags.locale": "en",
	"tags.feature_category": "subgroups",
	"tags.correlation_id": "01H5P9CWAR3B4123CHYQSZKYH5"
}

초기 분석

오류 메시지는 GitLab의 데이터베이스 부하 분산 문제와 관련이 있습니다. GitLab의 데이터베이스 로드 밸런싱은 데이터베이스 연결의 고가용성과 성능을 처리하도록 설계되었습니다. 그러나 로드 밸런싱을 사용할 때 때때로 이 오류와 함께 데이터베이스 연결이 실패하는 문제가 발생할 수 있습니다.
로그에서도 GitLab의 데이터베이스 트랜잭션 문제가 표시되는 것 같습니다. 트랜잭션은 데이터베이스 작업의 원자성, 일관성, 격리 및 내구성을 보장하는 데 사용되는 메커니즘입니다. GitLab에서는 데이터 일관성과 무결성을 보장하기 위해 데이터베이스 트랜잭션이 사용됩니다.

이 오류는 일반적으로 다음과 같은 원인으로 발생할 수 있습니다.

  • 데이터베이스 연결 문제: 데이터베이스 연결에 문제가 있어 GitLab이 데이터베이스에 정상적으로 연결되지 않을 수 있습니다. 이는 데이터베이스 서버 오류, 네트워크 문제 또는 잘못된 구성 때문일 수 있습니다.

  • 데이터베이스 잠금: 동일한 데이터베이스 리소스에서 여러 트랜잭션이 동시에 작동하고 잠금 경쟁이 발생하면 트랜잭션 중 하나가 실패할 수 있습니다.

  • 데이터베이스 교착 상태: 여러 트랜잭션이 서로 잠금 해제를 기다리며 순환 대기를 형성하면 데이터베이스 교착 상태가 발생하여 트랜잭션 중 하나가 실패합니다.

  • 트랜잭션 시간 초과: 트랜잭션 실행 시간이 너무 길어 데이터베이스에서 설정한 트랜잭션 시간 초과 기간을 초과하면 트랜잭션이 실패할 수 있습니다.

가능한 해결책:

  • 외부 데이터베이스 사용, 데이터베이스 트랜잭션 관련 설정 조정

  • 데이터베이스 서버의 상태와 성능을 확인하여 데이터베이스 서버가 제대로 작동하고 있는지 확인하십시오.

  • GitLab 서버가 데이터베이스에 제대로 연결할 수 있도록 데이터베이스 연결의 구성 및 설정을 확인하십시오.

  • 데이터베이스 잠금 및 교착 상태의 가능성을 줄이기 위해 데이터베이스 인덱스 및 쿼리 문을 확인하고 최적화합니다.

  • 더 긴 트랜잭션 처리 시간을 수용하기 위해 트랜잭션 제한 시간 증가와 같은 데이터베이스 트랜잭션 설정을 조정합니다.

  • 데이터베이스 서버 및 GitLab 서버의 로그에서 트랜잭션 실패를 유발할 수 있는 다른 오류 메시지를 확인하십시오.


위의 분석은 우리가 변경 사항을 포함할 수 없을 가능성이 더 높으며 이 문제가 새 버전의 gitlab에서 수정되었는지 확실하지 않습니다. gitlab 버전을 업데이트하여 해결할 수 있는지 확인하거나 비즈니스 계층 또는 분산 아키텍처에 전역 잠금을 추가하여 밀리초 수준에서 동일한 리소스를 작동하는 동시 동시 요청을 금지하여 이 문제를 해결할 수 있습니다.

추천

출처blog.csdn.net/weixin_44388689/article/details/131806512