728x90
반응형

링크 : https://www.whatap.io/ko/blog/38/

최근 많은 웹서비스들이 HTTP/2로 이루어지고 있습니다. 와탭 모니터링 SaaS 서비스 또한 AWS의 ALB를 통해 HTTP/2 프로토콜로 서비스되고 있는데요. HTTP/2는 기존의 HTTP/1.x에 비해 성능이 좋습니다.HTTP/2는 기존의 HTTP/1.x 프로토콜의 모든 핵심 개념들을 그대로 유지하면서 큰 성능 개선을 보여줍니다. 그래서 지금 서비스 중인 웹서비스가 HTTP/1.1로 통신되고 있다면 HTTP/2에 필요한 옵션과 기능들을 추가하는 것 만으로 많은 성능 개선을 볼 수 있습니다. 그럼 HTTP/2의 핵심 내용을 간략히 알아보고 실제 톰캣으로 HTTP/2 통신을 적용해 보겠습니다.

HTTP/1.x

HTTP/2(이하 H2)와 HTTP/1.x(이하 H1)와의 가장 큰 변화는 속도 향상입니다. H1의 성능 저하 부분과 비효율적인 것들을 개선되어 탄생한 것이 H2라고 생각하면 쉽습니다. H1에서 문제가 되는 부분을 보고 H2에서는 어떻게 해결하였는지 보겠습니다.

HTTP/1.1

HTTP는 TCP 연결 기반 위에서 동작하는 프로토콜입니다. 신뢰성 확보를 위해 연결을 맺고 끊는 데 있어서 핸드 셰이크가 이루어집니다. 거기에다 HTTP는 비연결성 프로토콜이기 때문에 한 번 연결로 한 번의 요청과 응답을 하고 응답이 끝나면 연결을 끊어 버립니다. 연결을 맺고 끊을 때마다 핸드 셰이크를 하기 때문에 비연결성 프로토콜에선 오버헤드가 생깁니다. 특히 요즘 웹서비스들은 하이퍼 텍스트라기보다는 많은 정적 데이터로 이루어진 하이퍼 미디어로 발전했기 때문에 오버헤드가 커질 수 있습니다. 그래서 HTTP/1.1에서 Keep-alive 기능이 추가되어 한 번 맺어졌던 연결을 끊지 않고 지속적으로 유지하여 불필요한 핸드 셰이크를 줄여 성능을 개선할 수 있습니다. 이런 식으로 웹페이지가 예전의 텍스트 위주와는 다르게 점점 미디어들이 추가되고 상태(쿠키, 세션 등)를 유지하려는 기술들이 요구되다 보니 성능 개선이 반드시 필요하게 되었고 이를 위해 부가적인 기능들이 추가되다 H2까지 발전하게 된 것입니다.

HTTP/1.1에서 성능 개선을 위해 파이프라이닝이라는 기술이 도입되었습니다. 하나의 커넥션에서 한 번에 순차적인 여러 요청을 연속적으로 하고 그 순서에 맞춰 응답을 받는 방식으로 지연 시간을 줄이는 방법입니다. 순차적으로 데이터를 요청하고 받아야 하다 보니 먼저 받은 요청이 끝나지 않으면 그 뒤에 있는 요청의 처리가 아무리 빨리 끝나도 먼저 온 요청이 끝날 때까지 기다려야 합니다. 이를 HTTP의 HOL(Head Of Line) Blocking 문제라고 하고 파이프라이닝의 큰 문제입니다. 그래서 모던 브라우저들은 대부분은 파이프라이닝을 사용하지 못하도록 막아 놓았습니다. 그래서 H1으로 통신할 때 클라이언트(브라우저)가 요청을 병렬로 하기 위해서 6-8개(브라우저마다 다름)의 커넥션을 이용해 데이터를 가져오는 방식으로 성능을 개선하고 있습니다.

HTTP/1.1 파이프라이닝
크롬 개발자 도구로 확인한 HTTP/1.1의 데이터 요청 응답 과정에서 6개의 커넥션 ID가 사용됐다.

HTTP/2의 바이너리 프레임과 멀티플렉싱

H2의 핵심은 바이너리 프레이밍 계층을 사용해 요청과 응답의 멀티플렉싱을 지원한다는 것입니다. HTTP 메시지를 바이너리 형태의 프레임으로 나누고 이를 전송 후 받은 쪽에서 다시 조립합니다. 요청과 응답이 동시에 이루어지니 하나의 연결에 여러 요청과 응답이 뒤섞여 있습니다. 프레이밍 작업은 서버와 클라이언트(브라우저)에서 해주기 때문에 큰 변경사항을 고려하지 않아도 됩니다. 바이너리 프레이밍과 멀티플렉싱을 이용해 여러 개의 연결 없이 병렬 처리도 할 수 있고 파이프라이닝과 달리 HOL문제를 해결한 것입니다.

또한 그 외에도 요청 우선순위를 지정할 수 있고 헤더를 압축하여 헤더 오버헤드를 줄이고 클라이언트가 명시적 요청을 하지 않아도 필요한 리소스를 미리 푸시하여 응 답 시간을 줄이는 서버 푸시 기능이 추가되었습니다. H2의 발전 과정과 목표, 자세한 기술적인 내용은 구글 개발자 페이지에서 볼 수 있습니다.

바이너리 프레이밍 계층 출처 : 구글
  • 스트림 : 구성된 연결 내에서 전달되는 바이트의 양방향 흐름이며, 하나 이상의 메시지가 전달될 수 있습니다.
  • 메시지 : 논리적 요청 또는 응답 메시지에 매핑되는 프레임의 전체 시퀀스입니다.
  • 프레임 : HTTP/2에서 통신의 최소 단위이며 각 최소 단위에는 하나의 프레임 헤더가 포함됩니다. 이 프레임 헤더는 최소한으로 프레임이 속하는 스트림을 식별합니다.

이제 실제 톰캣을 이용해서 H2를 위한 설정을 해보고 간단한 WAS를 만들어HTTP/1.1과 HTTP/2의 페이지 로드 시간을 비교해보겠습니다.

톰캣으로 H2를 설정하여 H1과 단순 비교 해보기

톰캣은 8.5 버전 이상부터 H2를 지원합니다. 단 8.5에서는 APR(Tomcat Native)를 설치해야 H2가 작동합니다. 또한 H2로 통신하기 위해서는 TLS가 적용되어야 작동합니다. TLS 적용은 H2의 표준은 아니지만 대부분의 브라우저에서 TLS 설정이 안 되어 있으면 H2로 통신이 불가능하도록 되어 있습니다.

톰캣 8.5 버전에서 HTTPS와 APR을 설정하고 와탭 로고를 225개의 이미지로 나누어 이를 전송하는 WAS를 만들었습니다. 그리고 톰캣 서버는 로컬 VM에서 설치되어 있기 때문에 육안으로도 성능 차이를 가늠할 수 있게 하기위해 강제로 네트워크 쓰로틀링을 걸어 레이턴시를 30ms로 설정하였고고 브라우저 캐싱 기능을 껐습니다. HTTP/2를 위한 톰캣에서의 Tomcat Native 설치와 아래와 같은 커넥터 설정이 전부입니다. 그럼 브라우저에서 H2를 지원하면 H2로 통신이 되고 그렇지 않을 경우 H1으로 통신이 됩니다.

톰캣 HTTP/2 설정 커넥터 설정
HTTPS/1.1 이미지 로드 시간
HTTP/2 이미지 로드 시간

위 이미지를 보면 H2가 같은 조건에서 2배에 가까운 성능 개선을 보여주고 있습니다. 이 성능 차이는 레이턴시가 나쁜 환경에서 더 명확해집니다. 또한 전체 전송 데이터 크기도 줄어드니 네트워크 부하도 줄어듭니다. H2를 위한 설정만 해준다면 전체 성능을 쉽게 개선할 수 있습니다.

그럼 다음 글에서는 여기서 만든 톰캣 WAS를 이용해 패킷을 수집하여 헤더 프레임과 데이터 프레임이 어떻게 주고 받아지는지 조금 더 알아보겠습니다.

반응형

'IT Info' 카테고리의 다른 글

LHR 채굴락 풀기  (0) 2022.05.19
PowerToys  (0) 2022.05.11
[펌] HTTP2  (0) 2022.05.03
원격 데스크톱 연결 접속 IP 정보 삭제  (0) 2022.04.27
Tistory 코드블럭 복사시 개행되지 않을 때  (0) 2022.04.23
[펌] 제페토와 게더타운  (0) 2022.04.11
728x90
반응형

레지스트리 창에서
컴퓨터\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Terminal Server Client\Default 으로 이동

레지스트리 창에서
컴퓨터\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Terminal Server Client\Servers 으로 이동

Servers 아래 내용들 제거

DropDown List 에서는 사라졌지만 최근 접속한 ip 가 입력되어 있다.


내 PC -> 문서 -> Default.rdp 파일 삭제

삭제 완료!

 

반응형

'IT Info' 카테고리의 다른 글

PowerToys  (0) 2022.05.11
[펌] HTTP2  (0) 2022.05.03
원격 데스크톱 연결 접속 IP 정보 삭제  (0) 2022.04.27
Tistory 코드블럭 복사시 개행되지 않을 때  (0) 2022.04.23
[펌] 제페토와 게더타운  (0) 2022.04.11
유용한 단축키  (0) 2022.04.08
728x90
반응형
DXSplashScreen.Show(
    (o) =>
    new Window
    {
        Focusable = true,
        WindowStyle = System.Windows.WindowStyle.None,
        AllowsTransparency = false,
        ShowInTaskbar = false,
        ShowActivated = false,
        Topmost = false,
        Background = Brushes.Transparent,
        SizeToContent = System.Windows.SizeToContent.WidthAndHeight,
        ResizeMode = System.Windows.ResizeMode.NoResize
    },

    (o) =>
    new LoadingDialogControl(),
    new object[] { new SplashScreenOwner(Application.Current.MainWindow), WindowStartupLocation.CenterOwner },
    null);

DXSplashScreen.Show() 쓰게 되면 가장 상단에 떠서 MessageBox 로 띄운 메세지 들이 뒤에 가려서 안보이게 되는데 위처럼 사용하면 MessageBox 가 가려지지 않고 상단에 표시 된다.
LoadingDialogControl 은 화면에 표시될  UserControl 이다.

반응형
728x90
반응형

쿼리문 하나에 parameter 를 변경해 일일히 쿼리하는 일을 아래처럼 하면 dapper 가 알아서 해준다.

#region MultiUpdate
/// <summary>
/// Multipul Update
/// </summary>
private void MultiUpdate()
{
    string sql = "UPDATE TestTable SET DATA1 = @DATA1 WHERE ID = @ID;";

    using (IDbConnection db = new SqlConnection(this.connectionString))
    {
        int rowsAffected = db.Execute(sql,
            new[]
            {
                    new { ID = 1, DATA1 = "UPDATEA1" },
                    new { ID = 2, DATA1 = "UPDATEA2" },
            }
        );
    }
}
#endregion
#region MultiDelete
/// <summary>
/// Multipul Delete
/// </summary>
private void MultiDelete()
{
    string sql = "DELETE FROM TestTable WHERE ID = @ID;";

    using (IDbConnection db = new SqlConnection(this.connectionString))
    {
        int rowsAffected = db.Execute(sql,
            new[]
            {
                    new { Id = 1 },
                    new { Id = 2 }
            }
        );
    }
}
#endregion
반응형

'C#' 카테고리의 다른 글

[C#] gRPC Stream Server/Client 만들기  (0) 2022.05.04
[C#] gRPC Server/Client 만들기  (0) 2022.05.04
[C#/Dapper] Multi Delete, Multi Update  (0) 2022.04.23
[C#/Dapper] Multi Select  (0) 2022.04.23
[C#/Dapper] Bulk Insert (List<T> Insert)  (0) 2022.04.23
[C#/Dapper] Dynamic Parameter  (0) 2022.04.23
728x90
반응형

dapper 를 이용하면 select 문을 여러개 사용해 여러 결과를 얻어올수 있다.

using (IDbConnection db = new SqlConnection(this.connectionString))
{
    db.Open();

    // ■ Multi Result
    sql = @"
SELECT * FROM TestTable WHERE ID = @ID
SELECT * FROM TestTable2 WHERE ID = @ID";

    using (var multi = db.QueryMultiple(sql, new { id = 7 }))
    {
         // 순서를 맞춰야 함
         var multiData1 = multi.Read<TestDataModel>().ToList();
         var multiData2 = multi.Read<TestDataModel2>().ToList();
    }
}

쿼리 순서에 맞춰 Read 를 호출해 데이터를 가져오면 된다.

반응형

'C#' 카테고리의 다른 글

[C#] gRPC Server/Client 만들기  (0) 2022.05.04
[C#/Dapper] Multi Delete, Multi Update  (0) 2022.04.23
[C#/Dapper] Multi Select  (0) 2022.04.23
[C#/Dapper] Bulk Insert (List<T> Insert)  (0) 2022.04.23
[C#/Dapper] Dynamic Parameter  (0) 2022.04.23
[C#/Dapper] Dynamic Result  (0) 2022.04.23
728x90
반응형
using (SqlConnection connection = new SqlConnection(this.connectionString))
{
    connection.Open();

    // 데이터 삭제
    connection.Execute("DELETE FROM TestTable");

    // 추가될 데이터
    List<TestDataModel> testDataList = new List<TestDataModel>();

    for (int i = 0; i < 15; i++)
    {
        testDataList.Add(new TestDataModel() { ID = i, DATA1 = "A" + i, DATA2 = "B" + i, DATA3 = "C" + i });
    }

    SqlTransaction transaction = connection.BeginTransaction();
    try
    {
        connection.Execute("INSERT TestTable (DATA1, DATA2, DATA3) VALUES (@DATA1, @DATA2, @DATA3)", testDataList, transaction);
        transaction.Commit();
    }
    catch(Exception ex)
    {
        transaction.Rollback();
        throw ex;
    }

실제 bulk insert 는 Dapper 유료버전에 있다; 위처럼 사용하면 여러 데이터 처리가 가능하다.

반응형

'C#' 카테고리의 다른 글

[C#/Dapper] Multi Delete, Multi Update  (0) 2022.04.23
[C#/Dapper] Multi Select  (0) 2022.04.23
[C#/Dapper] Bulk Insert (List<T> Insert)  (0) 2022.04.23
[C#/Dapper] Dynamic Parameter  (0) 2022.04.23
[C#/Dapper] Dynamic Result  (0) 2022.04.23
[C#/Dapper] Dapper 설치 및 기본사용  (0) 2022.04.23
728x90
반응형
using (IDbConnection db = new SqlConnection(this.connectionString))
{
    db.Open();

    // ■ Dynamic Parameter
    var data1 = "A1";
    var data2 = "B1";
    string query = "SELECT * FROM TestTable WHERE DATA1 = @DATA1 and DATA2 = @DATA2";
    var dynamicParameters = new DynamicParameters();
    dynamicParameters.Add("DATA1", data1);
    dynamicParameters.Add("DATA2", data2);
    
    IEnumerable<dynamic> results = db.Query(query, dynamicParameters);
}

위 내용을 아래처럼 사용하면 간단하게 사용할수 있다.

IEnumerable<dynamic> results = db.Query(query, new { DATA1 = "A1", @DATA2 = "B1" });

반응형

'C#' 카테고리의 다른 글

[C#/Dapper] Multi Select  (0) 2022.04.23
[C#/Dapper] Bulk Insert (List<T> Insert)  (0) 2022.04.23
[C#/Dapper] Dynamic Parameter  (0) 2022.04.23
[C#/Dapper] Dynamic Result  (0) 2022.04.23
[C#/Dapper] Dapper 설치 및 기본사용  (0) 2022.04.23
[C#] VB → C#  (0) 2022.04.22
728x90
반응형

블로그 코드블록 내용을 복사하고 붙여넣기하게되면 코드가 개행되지 않고 한줄로 붙여넣기 되는 경우가 있다

이를 해결하기 위해선 플러그인 > 저작권자 표시 선택

 

해제 를 클릭!


이제 복붙 시 제대로 되는걸 확인할수 있다.

반응형

'IT Info' 카테고리의 다른 글

[펌] HTTP2  (0) 2022.05.03
원격 데스크톱 연결 접속 IP 정보 삭제  (0) 2022.04.27
Tistory 코드블럭 복사시 개행되지 않을 때  (0) 2022.04.23
[펌] 제페토와 게더타운  (0) 2022.04.11
유용한 단축키  (0) 2022.04.08
GIS (지리정보 시스템)  (0) 2022.03.11
728x90
반응형
using (IDbConnection db = new SqlConnection(this.connectionString))
{
    db.Open();

    // ■ Dynamic Result
    IEnumerable<dynamic> dynamicResult = db.Query(sql, parameters);
    var first = dynamicResult.First();
    string getData1 = first.DATA1;
    string getData2 = first.DATA2;
}

구조를 정의 하지 않고 사용할 때 Dynamic 으로 처리하여 결과 데이터를 가져올수 있다.

반응형
728x90
반응형

1. Nuget 에서 Dapper 설치

2. 기본 사용

public class TestDataModel
{
    public int ID { get; set; }
    public string DATA1 { get; set; }
    public string DATA2 { get; set; }
    public string DATA3 { get; set; }
}
using Dapper;

using Prism.Commands;
using Prism.Mvvm;

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Windows;
using System.Windows.Input;

private string connectionString = "Server=192.168.0.20;Database=kjundb;User Id=userid;Password=1234;";

using (IDbConnection db = new SqlConnection(this.connectionString))
{
    db.Open();

    // ■ Scalar
    var eventTime = db.Query<DateTime>("SELECT EventTime FROM TestTable WHERE ID = 1").SingleOrDefault();

    // ■ Basic Query
    var parameters = new { id = 18 };
    string sql = "SELECT * FROM TestTable WHERE ID = @id";

    var result = db.Query<TestDataModel>(sql, parameters);
}

 

반응형

+ Recent posts