크리에이티브 커먼즈 라이선스
Creative Commons License

DeadLock 시리즈는 끝났지만 실제 프로젝트에서 경험을 통해서 알게된 내용과 해결 과정을 공유하려고 합니다. 이번 글 제목처럼 Insert구문만으로도 DeadLock이 발생하는 경우입니다. 하나의 테이블에 단순히 Insert만 한다고 발생하는 경우는 당연히 아닙니다. 실제 프로젝트에서의 내용을 공유할 수는 없어서 DeadLock이 발생하는 상황을 단순화하여 재현을 해보고자 합니다.

먼저 테이블은 아래와 같습니다.


/****** Object:  Table [dbo].[Master]    Script Date: 2017-07-20 오후 1:15:55 ******/

CREATE TABLE [dbo].[Master](

[MasterId] [bigint] IDENTITY(1,1) NOT NULL,

[MasterName] [nvarchar](50) NULL,

 CONSTRAINT [PK_Master] PRIMARY KEY CLUSTERED 

(

[MasterId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]


GO

/****** Object:  Table [dbo].[Slave]    Script Date: 2017-07-20 오후 1:15:55 ******/

CREATE TABLE [dbo].[Slave](

[SlaveId] [bigint] IDENTITY(1,1) NOT NULL,

[MasterId] [bigint] NOT NULL,

[SlaveName] [nvarchar](50) NULL,

 CONSTRAINT [PK_Slave_1] PRIMARY KEY CLUSTERED 

(

[SlaveId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]


GO

ALTER TABLE [dbo].[Slave]  WITH CHECK ADD  CONSTRAINT [FK_Slave_Master] FOREIGN KEY([MasterId])

REFERENCES [dbo].[Master] ([MasterId])

GO

ALTER TABLE [dbo].[Slave] CHECK CONSTRAINT [FK_Slave_Master]

GO

=> 테이블은 2개입니다. Master, Slave라는 테이블이고 1:N의 관계를 가지는 구조입니다.

=> 노란색으로 표시한 부분이 외래키(FK) 관련 설정입니다.


DeadLock 상황을 설명하기 위한 표입니다.


 시간순서

 프로세스1

 프로세스2 

 비고

 1

 Insert : Master 테이블

 

 

 2

 

 Insert : Master 테이블

 

 3

 

 Select : Slave FK 관계 확인

 Insert : Slave 테이블 전에

 4

 Select : Slave FK 관계 확인 

 Insert : Slave 테이블 전에

=> DeadLock이 2개의 프로세스에서 Master테이블에 X, S Lock이 순환되어 발생합니다.

=> Lock 관점에서 보면 X, S Lock 호환이 되지 않는 Insert Select 구문으로 인한 것이며 여기서 Select에 해당 하는 부분이 FK 관계에 대한 확인이라는 점입니다. FK 확인 때문에 Master에 S Lock으로 블럭이 발생한다는 점이 의문입니다.

=> 어쨌든 FK와 관련된 것으로 보여 FK를 삭제하니 해결은 되었습니다. 일반적으로 테이블에 대한 관계, 제약조건을 빼고 하는 경우도 실전에서 은근히 많이 보게되어서 잠시 접어두었습니다. 

=> 고도화 하는 과정에서 다시 해당 내용을 살펴보았는데 DeadLock graph 내용을 보아도 특이한 점을 발견할 수가 없었습니다. 

=> SQL Server DeadLock 3편(http://resisa.tistory.com/187)에서 소개해드렸던 테스트 코드에서 특이한 점을 발견하였습니다.


Task.WaitAll(Enumerable.Range(0, 3).Select(t =>

   Task.Run(() =>

    {

        // 비지니스 로직

    })).ToArray()); 

=> 일반적인 상황에서는 2개만 돌려도 DeadLock이 발생하였는데 2개에서는 나오지 않고 3개 이상이 될 경우에 발생하였습니다. 다음으로 SP를 2개의 세션에서 커밋하지 않고 실행을 하니 잠금이 발생하는 부분이 있다는 것을 알 수 있었습니다. 잠금이 발생한다는 상황이 이해는 되지 않았지만 Select에서 잠금이 발생하고 3번째 프로세스에서 DeadLock이 발생하는 것 같다는 추측 정도는 되었습니다.


잠금이 발생하는 부분과 이유는 무엇일까 확인을 해보기 위해서 SP의 내용을 확인해보았습니다.


BEGIN TRAN


-- 실제로는 파라미터로 TVP로 받았지만 테스트를 위해서 임시 테이블로 가정

-- 1. Master테이블에 넣을 데이터

DECLARE @MasterTemp AS TABLE

(

MasterName nvarchar(100) NOT NULL

)


INSERT INTO @MasterTemp VALUES (N'resisa')


INSERT INTO [dbo].[Master]

SELECT T.MasterName

FROM @MasterTemp AS T


DECLARE @MasterId bigint = CAST(SCOPE_IDENTITY() AS bigint)


-- 2. Slave에 넣을 데이터

DECLARE @SlaveTemp AS TABLE

(

JoinId bigint NOT NULL,

SlaveName nvarchar(100) NOT NULL

)


INSERT INTO @SlaveTemp VALUES (1, N'sisatoss')

INSERT INTO @SlaveTemp VALUES (2, N'resisa1982')


DECLARE @SlaveTemp2 AS TABLE

(

JoinId bigint NOT NULL,

MasterId bigint NOT NULL

)


INSERT INTO @SlaveTemp2 VALUES (1, @MasterId)

INSERT INTO @SlaveTemp2 VALUES (2, @MasterId)


-- 3. SlaveTemp와 SlaveTemp2를 조인하여 Slave 테이블에 데이터를 넣어준다.

INSERT INTO [dbo].[Slave] (SlaveName, MasterId)

SELECT T1.SlaveName, T2.MasterId

FROM @SlaveTemp AS T1

INNER JOIN @SlaveTemp2 AS T2

ON T1.JoinId = T2.JoinId


ROLLBACK TRAN

=> 문제의 원인이 될것이라고 생각한 부분은 3번 주석의 Slave에 데이터를 넣기 위해서 2개의 임시 테이블을 조인하고 그 결과를 넣어주는 부분이였습니다. 그래서 INNER JOIN을 사용하지 않고 실행을 해보니 DeadLock이 사라졌습니다;;

=> 왜 이러한 현상이 발생하는 알기 위해서 예상실행 계획을 살펴보았습니다.


1. 잠금 현상 없음



2. 잠금 발생


=> 차이점이 보이시나요? 결국 Loop Join과  Merge Join에 대한 차이점으로 보입니다.

=> 잠금이 발생하는 상황을 유추해보면 Insert Select INNER JOIN에서 Sort로 인하여 Master테이블(아마 PAG)에 S Lock을 획득하려고 하기 때문입니다. Loop Join일 경우에는 Master테이블에 KEY에 S Lock을 획득하려고 합니다. 결국 차이점은 FK에 대한 Select에 대하여 어떤 리소스에 S Lock를 획득하려고 하느냐이며 전자의 경우에는 다른 트랜잭션에서 접근하는 리소스에 S Lock을 획득하려고 하기 때문에 블럭이 발생하는 것입니다.

=> 리소스를 PAG라고 예상하는 이유는 Slave Insert구문에 WITH(PAGLOCK) 힌트를 주면 해당 문제가 해결되기 때문입니다. 하지만 당연히 성능이 느려지기 때문에 첨언 정도로 봐주시면 될 것 같습니다.


정리를 해보면 아래와 같습니다.

- 상황 : Insert 구문으로 인한 DeadLock

- 조건

1. 2개의 테이블이 관계(FK)를 가지고 있다.

2. Slave 테이블에 Insert하는 구문에 Join 구문을 사용한다.

- 해결

1. Slave 테이블에 Insert하는 구문에 조인 힌트(OPTION (LOOP JOIN))를 사용한다.

2. Slave 테이블에 Insert하는 구문에 Join을 사용하지 않는다. (임시테이블을 사용하여 단순히 Insert한다)

3. FK 제약 조건을 제거한다.


조인을 할 경우에 OPTION (LOOP JOIN)처럼 힌트를 줄 수 있다는 것을 배웠습니다. 하지만 역시나 힌트는 정확하게 알고 써야한다는 것과 SQL 옵티마이저가 해당 임시테이블에 대한 조인 구문에서 Merge Join 비용이 Loop Join보다 높음에도 불구하고 Merge Join으로 판단한 근거(아니면 다른 이유 때문에???)는 무엇일까를 생각하며 잘 볼줄은 모르지만 예상 실행 계획을 통해서 추측을 해보니 DB 전문가?!가 된 느낌입니다. ㅎㅎ

저작자 표시 비영리 변경 금지
신고
Posted by resisa
크리에이티브 커먼즈 라이선스
Creative Commons License

서비스 시점이 다가오면서 열심히 개발한 서비스에 대한 관리는 어떻게 할것인가에 대한 고민이 생겼습니다. 일단 어떤 항목을 우선순위로 관리를 할 것인지에 대한 고민부터 시작하였습니다. 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 한번 검토해보세요. ㅎㅎ

저작자 표시 비영리 변경 금지
신고
Posted by resisa
크리에이티브 커먼즈 라이선스
Creative Commons License

중국 출장을 다녀온 이후로 크롬(사파리도) 브라우저에서 자동으로 redirect(광고, 바이러스 관련 프로그램 설치 등등) 되는 페이지가 탭으로 추가되는 현상이 지속적으로 발생하였습니다. 이런 부분에 예민한 편은 아니라 별다른 생각이 없었는데 2주 정도 시간이 흐르니 언제까지 이렇게 닫아줘야 할까 귀찮기도 하고 로그인(개인정보)를 할때 불안감도 들어서 삭제하기로 마음을 먹고 검색을 해보았습니다.

네이버에서 먼저 검색을 해보았는데 윈도우에 관련(제 노트북은 MAC이라는)된 내용들만 많이 나와서 구글에서 검색을 하였습니다.


구글 크롬 고객센터에서 해결방법을 알려주고 있습니다.

https://support.google.com/chrome/answer/2765944?hl=ko


MalwareBytes라는 프로그램을 설치하고 Scan한 이후에 재부팅, 브라우저 초기화, 다시 Scan하고 재부팅을 하였습니다.

https://www.malwarebytes.com/


멀웨어라는 용어가 악성 소프트웨어였군요 ㅎㅎㅎ;;;

아래와 같이 정의되어 있습니다.


바이러스나 트로이 목마와 같이 시스템에 해를 입히거나 시스템을 방해하기 위해 특별히 설계된 소프트웨어, 또는 데이터ㆍ컴퓨터ㆍ네트워크를 위험에 노출시킬 수 있는 코드. 악성 소프트웨어(malicious software), 또는 악성 코드(malicious code)에서 나온 말로, 남에게 피해를 입히기 위해 개발된 소프트웨어를 의미한다. 최근의 멀웨어는 첨부 파일을 열어 보거나, 소프트웨어를 다운받아 설치하는 종래의 통념을 벗어나 단지 유명 검색 페이지의 링크나 이미지를 클릭하기만 해도 원하지 않는 소프트웨어가 설치되고, 시스템이 하이재킹당할 수 있어 주의가 필요한다.

[네이버 지식백과] 멀웨어 [malicious software, malware] (IT용어사전, 한국정보통신기술협회) 


http://terms.naver.com/entry.nhn?docId=864358&cid=42346&categoryId=42346


최근 블로그 통계를 보면 유입 로그와 구글 분석에 비해서 방문자 수치가 많이 잡혀 이상하다고 생각하였는데 멀웨어 때문이였는지 의심스럽기도 합니다. 시간이 좀 더 지나보면 알겠죠? ㅎㅎ

저작자 표시 비영리 변경 금지
신고
Posted by resisa


티스토리 툴바