'SQL Server'에 해당되는 글 2건

  1. 2017.07.17 모니터링 시스템 시작
  2. 2017.06.12 SQL Server DeadLock 1편

서비스 시점이 다가오면서 열심히 개발한 서비스에 대한 관리는 어떻게 할것인가에 대한 고민이 생겼습니다. 일단 어떤 항목을 우선순위로 관리를 할 것인지에 대한 고민부터 시작하였습니다. Feedly에서 아래 글을 보게 되어 참고하였습니다.


https://indexoutofrange.com/Choosing-centralized-logging-and-monitoring-system/

=> 대부분 상용 서비스(Saas)를 비교하였고 글쓴이의 요구사항에 맞춰서 선택기준을 제시하고 있습니다.


Google Analytics vs. ELK +Graphite/Grafana vs. NewRelic vs. Retrace vs. Application Insights vs. Raygun vs. Datadog


저의 요구사항 우선순위는 아래와 같습니다.

1. 커스터마이징

2. 중앙에서 로그 관리

3. 알람

4. 서버의 성능 카운터

5. 실시간 모니터링

=> 아무래도 모니터링과 관련된 부분이다 보니 성능보다는 기능이나 수정이 용이한지가 더 중요하게 생각됩니다.


그러던 중에 아래의 OneTrueError라는 오픈 소스를 알게 되었고 대부분 제가 생각하는 요구사항을 만족하였습니다.


https://www.codeproject.com/Articles/1126297/OneTrueError-Automated-exception-handling


기술검토를 하기 전에 혹시 더 좋은 건 없나 찾아보던 중에 Opserver라는 Stack Exchange에서 사용하는 모니터링 시스템을 보게 되었습니다.


https://github.com/opserver/Opserver


 Opserver is a monitoring system by the team at Stack Exchange, home of Stack Overflow. It is a tool for monitoring:

  • Servers/Switches & anything supported by Bosun, Orion, or direct WMI monitoring
  • SQL Clusters & Single Instances
  • Redis
  • Elasticsearch
  • Exception Logs (from StackExchange.Exceptional)
  • HAproxy
  • PagerDuty
  • CloudFlare DNS
  • ... and more as we go

=> DB 서버에 대한 모니터링도 제공해주고 차후에 적용할 Redis, HAProxy, Elasticsearch에 대한 모니터링 기능도 지원이 가능하며 .NET으로 만든 오픈소스라 커스터마이징도 유용할 것으로 보였습니다.


Opserver에서 사용한 오픈소스 리스트는 아래와 같습니다.

StackExchange.Redis by Marc Gravell

Dapper by Stack Exchange

JSON.Net by James Newton-King

MiniProfiler by Stack Exchange

StackExchange.Exceptional by Nick Craver

TeamCitySharp by Paul Stack

d3.js by Michael Bostock

ColorBrewer by Cynthia Brewer and Mark Harrower

HTML Query Plan by Justin Pealing

isotope by Metafizzy

jQuery by The jQuery Foundation

jQuery cookie plugin by Klaus Hartl

jQuery autocomplete by Jörn Zaefferer

prettify by Google

TableSorter by Christian Bach

Toastr by John Papa and Hans Fjällemark

=> 저희 프로젝트에서 사용하고 있는 오픈소스인 Dapper, StackExchange.Redis, JSON.NET 등등이 보이고 HTML Query Plan이 보이는 것으로 봐서는 SQL Server에서 제공해주는 쿼리 플랜까지 제공해주는 것으로 보입니다.

=> Exceptional을 통해서 DB에 로그 데이터를 쌓고 해당 로그를 화면에서 보여주는 방식입니다.


Opserver SQL탭에 대한 화면은 아래와 같습니다.


추가적으로 아래와 같은 기능이 필요할 것으로 보입니다.

1. WMI를 활용하여 프로세스 단위로 모니터링

2. 알람 => 실시간 모니터링이 가능하지만 계속 화면을 보고 있을수는 없으므로 중요한 내용에 대한 알람이 필요해보이는데 알람 기능은 없는 것으로 보입니다.

Opserver에서 참조 중인 StackExchange.Exceptional에 메일 발송 기능이 있습니다. 다만 CPU가 Warning, Critical 상태일 경우의 발송이 되는 것은 아니고 Exceptional을 통해서 로그를 남기는 부분에 대한 메일 발송 기능입니다. (2017-08-19)


검토 단계여서 기능 위주로 확인해보았으며 소스 분석을 통해서 구조나 추가 기능을 구현해보려고 합니다. 혹시 비슷한 고민을 하고 계시는 분들이 있으시다면 Opserver 한번 검토해보세요. ㅎㅎ

Posted by resisa
,

개발자가 할줄은 알지만 은근히 모르는 DB개발과 관련된 글을 쓰려고 합니다. 저도 SP를 실제 프로젝트에 사용한 것이 얼마 안되었고 프로그램 개발에 더 많은 시간을 투자하였습니다. 그래서인지 신선한?! DB개발을 하니 신입때 첫 프레임워크를 사용하는 느낌입니다.

구글에서 DeadLock과 관련된 글들을 보고 제가 이해한 것을 기반으로 설명을 해보려고 합니다. 틀린 부분이 있다면 댓글을 달아주시면 좋습니다. (댓글이 없어서 사실 아무말이나 좋습니다 ㅎㅎ)

먼저 DeadLock이기 때문에 트랜잭션과 Lock 이야기로 시작해보겠습니다.
이전 글에서 이야기 했듯이 트랜잭션(IsolationLevel)에 대해서 일반적으로 ReadUncommitted로 설정을 하고 사용할 것이라고 하였습니다. 그렇게 생각하는 이유는 ReadCommitted나 RepeatableRead, Serializable 등등은 만족할만한 성능을 얻기가 힘들며 Lock을 잠그는 시간이 길어지면서 DeadLock이 발생할 확률도 높습니다.

당연한 사실이지만 트랜잭션이 발생한 상태에서 Lock도 발생하는 것입니다. 트랜잭션이 없다면 Lock도 없습니다. 그렇다고 트랜잭션이 있다고 Lock이 꼭 있는건 아닙니다. 바로 트랜잭션 IsolationLevel 옵션을 ReadUncommitted를 사용(일반적으로 Select구문일 경우)할 때입니다. ReadUncommitted는 그 이름처럼 다른 트랜잭션에서 커밋이 되기 전의 데이터를 읽을 수 있습니다. Lock없이 읽기 때문에 성능적인 측면이나 DeadLock이 발생하는 것을 방지하려는 의도로 사용되는 것입니다. 다만 커밋되기 전의 데이터 읽게 되므로 데이터의 무결성이 깨질 수 있습니다.
=> 위의 Lock이 없다는 말은 잘못된 표현이네요. 아무리 짧은 SQL 구문이라도 Lock이 발생합니다. 저 말의 의미는 실행시간이 매우 짧은 Select 구문일 경우 트랜잭션 내에서 ReadUncommitted일 경우 실행 후 Lock이 해제된다는 사실에 대한 강조하려다 보니 잘못된 표현을 한 것으로 보입니다. (2017-08-20)

하나 더 살펴보아야 할 IsolationLevel은 Snapshot입니다. 아래처럼 DB에 설정이 필요합니다.

-- 1. Snapshot 허용
ALTER DATABASE [DB명]
SET ALLOW_SNAPSHOT_ISOLATION ON

-- 2. ReadCommitted 옵션을 사용할 경우 Snapshot옵션으로 처리
ALTER DATABASE [DB명]
SET READ_COMMITTED_SNAPSHOT ON

=> 1번이 DB에 Snapshot옵션을 설정하는 명령어입니다. 2번 명령어는 SQL Server의 IsolationLevel ReadCommitted기본값이므로 해당 옵션을 사용할 때 Snapshot으로 처리하기 위한 명령어입니다. (확실한 것은 아니지만 2번으로 명령어를 사용하여 ReadCommitted로 테스트할 때와 1번 명령어만 사용하여 Snpashot옵션을 주어 처리할 때의 결과가 다른 적이 있어서 2번 명령어는 사용하지 않고 명시적으로 Snapshot옵션을 주는 것이 바람직해보입니다.)

그럼 Shapshot옵션을 주면 트랜잭션 사이의 격리성을 어떻게 관리하게 되는 것일까요? 트랜잭션이 시작되면 별도 DB(temp)에 트랜잭션 시퀀스 번호를 관리하여 트랜잭션 사이에 경합이 발생하면 경합이 발생한 트랜잭션 중 하나를 롤백(낙관적 동시성 모델)시켜서 데이터의 무결성을 보장하고 DeadLock을 방지해줍니다. 자세한 내용은 아래 MSDN을 참고하시면 됩니다. 여기서 중요한 것은 경합이 발생할 때 트랜잭션을 취소시키기 때문에 실패하는 트랜잭션이 발생하지만 동시성(성능)은 높은 옵션이라고 말할 수 있습니다. 다만 동시성이 높아지면 높아질수록 성공률은 낮아지게 되는 문제점이 있습니다.

https://msdn.microsoft.com/ko-kr/library/tcbchxcb(v=vs.110).aspx

그럼 정리를 해보면 트랜잭션 IsolationLevel중 성능을 고려하면 아래 2가지 중 하나를 선택할 수 밖에 없습니다.
1. ReadUncommitted => 단점은 더티 데이터로 인하여 데이터 무결성이 깨질 수 있습니다.
2. Snapshot => 동시성이 높아지면 성공률이 낮아집니다.

기본적으로는 ReadUncommitted를 사용하고 복잡한 트랜잭션에 대한 Lock을 관리하여 데이터의 무결성을 유지해야 합니다. Snapshot옵션은 동시성(DB)이 그렇게 높지 않은 시스템에서 안전하게 운영을 하고 싶을 경우에 사용하면 좋지 않을까 싶습니다.

DB Lock의 종류는 아래와 같습니다.
1. X-Lock(Exclusive, 배타) : Insert, Update, Delete와 같이 데이터 수정하는 작업을 말하며 같은 리소스에 대해서 동시에 실행될 수 없습니다. 즉 하나의 트랜잭션에서 X-Lock으로 잠금을 설정하면 다른 트랜잭션에서는 어떠한 잠금도 설정할 수 없습니다.
2. S-Lock(Shared, 공유) : 일반적으로 Select로 대표되며 데이터 읽기 작업을 합니다. 하나의 트랜잭션에서 S-Lock 잠금을 설정하면 다른 트랜잭션에서도 U-Lock, S-Lock 잠금이 가능합니다.
3. U-Lock(Update, 업데이트) : 설명을 짭게 하기가 힘들지만 U-Lock 잠금이 걸려 있어도 S-Lock만은 걸 수 있다 정도로 알면 될것 같습니다.
(이외에도 I-Lock, Schema, Bulk Update, Key-Range가 있지만 너무 많은 정보는 이해하는데 장애물이 되므로 패스하는 것이 좋습니다.)

일단은 이정도만 대략적으로 이해한 상태에서 간단한 예제를 통해서 DeadLock 상황을 만들어보고 원인과 해결 방법을 통해서 이해력을 높이면 충분히 DB도 아는 괜찮은 개발자라고 할 수 있을 것 같습니다. 저는 이미 괜찮은 개발자! ㅋㅋㅋ

참고 : Lock과 관련되어 상세하게 정리되어 있는 사이트입니다.
http://www.dbguide.net/db.db?cmd=view&boardUid=148215&boardConfigUid=9&categoryUid=216&boardIdx=138&boardStep=1


Posted by resisa
,