Skip to content

Commit

Permalink
mysql 데드락 발생 이슈 해결 정리, 서블릿 에러 처리 정리
Browse files Browse the repository at this point in the history
  • Loading branch information
YonghoChoi committed Jul 4, 2017
1 parent f0d40c9 commit b2a519e
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 2 deletions.
83 changes: 83 additions & 0 deletions md/Database/트랜잭션_처리_중_데드락_발생_이슈.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## 트랜잭션 처리 중 데드락 발생 이슈

### 원인

* 트랜잭션 처리 중 중첩하여 connection 요청
* 클라이언트가 동시에 접속하여 request를 날리는 경우 설정해 놓은 트랜잭션을 모두 사용
* 이 때 트랜잭션 내에서 connection을 또다시 요청하는 경우 이미 커넥션을 모두 사용한 상태에서 커넥션을 반환하길 대기하게 되므로 데드락 발생



### 재연 코드

```java
private void transaction(int i) {
try(Connection conn = DBHelper.getInstance().getConnection()) {
ZonedDateTime dt = ZonedDateTime.now();
System.out.println(String.format("[%d] %s", i, dt));

conn.setAutoCommit(false);
// CommunityInfoDao.getInstance().insert(conn, 1, (short) 1);
AccountInfoTable info = new AccountInfoTable();
info.uid = 1423523412;
info.cid = "test";
info.nickname = "test";
AccountInfoDao.getInstance().insert(conn, info);

Thread.sleep(10000);

conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

@Test
public void connectionTest() throws Exception {
for (int i = 0; i < 6; ++i) {
final int idx = i;
Thread e = new Thread(() -> transaction(idx));
e.start();
}

try(Connection conn = DBHelper.getInstance().getConnection()) {
conn.setAutoCommit(false);
// CommunityInfoDao.getInstance().insert(conn, 1, (short) 1);
try(Connection conn2 = DBHelper.getInstance().getConnection()) {
AccountInfoTable info = new AccountInfoTable();
info.uid = 1423523412;
info.cid = "test";
info.nickname = "test";
AccountInfoDao.getInstance().insert(conn, info);
}

conn.rollback();
}
}
```



### MariaDB 트랜잭션 확인

* 프로세스 리스트

```mariadb
MariaDB> show processlist;
```

* 트랜잭션 확인

```mariadb
MariaDB> SHOW ENGINE INNODB STATUS;
```



### 해결

* 트랜잭션 처리 중에는 중첩해서 connection 요청을 하지 않는다.
27 changes: 27 additions & 0 deletions md/Jsp/servlet_error_handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
기본 웹 컨테이너가 예외를 수신하면 예외를 발생시키는 JSP 페이지에 언급 된 오류 페이지가 있는지 여부를 먼저 확인합니다. (물론 예외가 JSP의 try-catch 블록 내에서 발생하면 해당 catch 블록의 우선순위가 더 높습니다.) JSP에 대해 오류 페이지가 지정되면 'Exception' 오브젝트가 해당 오류 페이지로 전달됩니다.

JSP 페이지가 오류 페이지를 지정하지 않고 try 구문을 사용한 경우 catch 블록에도 명시되지 않았다면, 웹 컨테이너는 Deployment Descriptor(web.xml)에서 해당 예외에 대한 오류 페이지를 찾기 시작합니다. 해당 예외에 대한 오류 페이지가 발견되지 않으면 컨테이너는 예외의 수퍼 클래스에 대한 오류 페이지를 찾고 컨테이너가 적절한 오류 페이지를 찾을 때까지 또는 Throwable 클래스 (Java의 전체 예외 처리 메커니즘의 최상위 수퍼 클래스)에 도달 할 때까지 계속됩니다.

JSP의 에러 페이지는 아래와 같이 web.xml 파일에 지정할 수 있습니다.

```xml
<!-- redirecting an error to a servlet -->
<error-page>
<error-code>404</error-code>
<location>/errorServlet</location>
</error-page>
...
```

Servlet에서 에러 처리 시에 Exception 클래스 대신 그보다 상위 클래스인 Throwable 클래스를 사용하는데 그 이유는 드물긴 하지만 JVM 오류나 native 메소드 오류는 Exception으로는 처리할 수 없기 때문입니다.

error handler (JSP / Servlet)로 전달 된 모든 JSP 예외는 실제로 웹 컨테이너에 의해 "javax.servlet.jsp.jspException"라는 객체가 request의 attribute로 저장되어 handler로 request 객체가 전달됩니다. JspException 클래스의 생성자는 다음과 같습니다.

* public JspException (java.lang.String msg) - 일반적으로 사용자 정의 메시지를 서버 로그에 기록하거나 이를 사용자에게 표시하기 위한 것입니다.
* public JspException (java.lang.String message, java.lang.Throwable rootCause) - 'Exception' 암시적 객체가 not null이면 rootCause 매개 변수로 전달됩니다.
* public JspException (java.lang.Throwable rootCause) - null 이외의 'Exception' 암시적 객체가 매개 변수로 전달됩니다.

생성자의 예외 객체의 타입을 보면 위에서 설명한 것과 같이 Throwable 타입으로 선언되어 있는 것을 볼 수 있습니다.

이렇게 예외를 던지는데 JspException 클래스로 한번더 래핑할 이유가 있을까? 꼭 그럴 필요는 없지만 몇가지 이유를 생각해보면 조건에 따라 예외를 생성할 수 있는 유연성이 생깁니다. 예를 들어 예외 객체 없이 사용자가 원하는 메시지만 전달을 하는 경우 이를 통해 메시지를 가공하여 로그를 작성하거나 사용자에게 표시할 수 있습니다. 또한 오류 조건에 대해 추가 텍스트를 쉽게 사용할 수 있다는 장점이 있습니다. 오류를 사용자가 더 이해하기 쉽도록 사용자 정의 메시지를 지정할 수 있습니다. 결국 반드시 사용해야만 하는 이유는 없지만 약간의 유연성을 제공한다는 것입니다.

20 changes: 20 additions & 0 deletions md/Pinpoint/pinpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,26 @@ pinpoint-web:



## Beanstalk 구성

* beanstalk에서는 tomcat8 디렉토리에 pinpoint-agent를 두지않으면 javaagent 옵션을 통해 수행이 불가능.

* 정확한 원인은 알아내지 못함.

* .ebextensions 설정을 통해서 JVM Options에 javaagent 경로를 지정하면 구동시 무시됨.

* 콘솔에서 Software Configuration을 통해 JVM Option 지정

```
-javaagent:/usr/share/tomcat8/pinpoint-agent/pinpoint-bootstrap-1.6.2.jar
```
* environment 옵션은 ebextensions를 통해 전달 가능.
## TODO
* hbase의 각 노드들과 zookeeper는 전부 같은 네트워크 안에서 서로 통신할 수 있어야 한다.
Expand Down
4 changes: 2 additions & 2 deletions md/aws/Docker_for_AWS_Demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
3. docker service create 명령으로 visualizer 실행

```shell
$ docker service create \
$ docker service create -d \
--name=viz \
--publish=5000:8080/tcp \
--constraint=node.role==manager \
Expand Down Expand Up @@ -86,7 +86,7 @@

10. 생성한 서비스로 접속(아까와 같이 ELB 주소에 3000번 포트로)해보면 아래와 같은 페이지가 출력된다.

![](images/cloudformation_4.png)
![](images/cloudformation_4.png)

11. 현재 이 웹페이지를 출력하기 위해 한대의 서버(컨테이너)를 사용하고 있는데 scale 명령으로 간단히 3대로 늘려본다.

Expand Down

0 comments on commit b2a519e

Please sign in to comment.