6년? 8년? 전에 tokumx mongoDB 부터 사용했었는데,  mongodb java driver 소스를 몇 번 봤었습니다.

(그 당시에는 지금처럼 mongodb가 안정화? 되지 않은 부분도 많았습니다. db커넥션 유지관련 버그 등..)

 

mongodb java driver 소스 중에 인상 깊고, 이후  다른 시스템들의 pk설계할때 많이 참고한 부분이  objectId  부분입니다.(인스타그램의 id체계 참고와 함께)

 

지금도 가끔 필요한 경우 소스를 다시 보는데, 메모 목적으로 내용을 복사해둡니다.(기억력이 예전같지 않아요 ...;)

 

추가 참고 글들

1. 리소스의 ID, GUID로 할까 Sequential로 할까?(https://news.hada.io/topic?id=6038)
2. ulid git(https://github.com/ulid/spec)

 


참고 링크:  https://www.mongodb.com/docs/manual/reference/bson-types/

 

ObjectIds are small, likely unique, fast to generate, and ordered. ObjectId values are 12 bytes in length, consisting of:

  • A 4-byte timestamp, representing the ObjectId's creation, measured in seconds since the Unix epoch.
  • A 5-byte random value generated once per process. This random value is unique to the machine and process.
  • A 3-byte incrementing counter, initialized to a random value.

For timestamp and counter values, the most significant bytes appear first in the byte sequence (big-endian). This is unlike other BSON values, where the least significant bytes appear first (little-endian).

If an integer value is used to create an ObjectId, the integer replaces the timestamp.

In MongoDB, each document stored in a collection requires a unique _id field that acts as a primary key. If an inserted document omits the _id field, the MongoDB driver automatically generates an ObjectId for the _id field.

몇 달전에 redis client를 어떻게 사용하는게 더 잘 사용하는지에 대해서 여러가지 검토 및 테스트를 진행했었습니다.

시간이 지나서 많이 잊어버려서 몇가지만이라도 메모 해둡니다.

 

1. https://lettuce.io/core/release/reference/index.html#_pipelining_and_command_flushing 에 정리가 잘되어 있었습니다. (AWS 문서는 퀄리티가 높음)

 

2. lettuce를 사용했을때 Pipe 커맨드 내용

 - https://lettuce.io/core/release/reference/index.html#_pipelining_and_command_flushing

 

3. I/O 멀티플렉싱 향상된 redis 버전을 사용

 - 예) ElastiCache for Redis 버전 7.0(향상된 버전)

     https://aws.amazon.com/ko/blogs/database/enhanced-io-multiplexing-for-amazon-elasticache-for-redis/

  1. 목적/배경
    1. https://blog.eomsh.com/187 에서 AWS SES를 사용해서 이메일 발송 서비스를 구축했다면 bounce 관리가 필요하다고 간단히만 코멘트
    2. 그런데, 메일함이 꽉 차서 유저에게 메시지를 띄워주거나, 반송되는 이메일 주소에게 본인의 어플리케이션이 메일을 다시 보내지 않게 하려면 메일 주소를 어플리케이션에 DB로 구축해야함
      1. 수신거부 등의 이벤트도 수집 가능
  2. 방법
    1. AWS SES 웹 콘솔에서 Notification 설정 -> SNS로 전송 -> Lambda 호출 -> 작성한 파이썬 코드 호출
      1. 추가 로직이 필요 없으면 SNS에서 바로 http api호출해도 될 것 같기는 함
      2. 참고 링크 
  3. 간단히 작성한 파이썬 소스코드
    1. AWS Lambda runtime 파이썬 레이어에 request 사용을 위해 추가 후 아래 코드 실행되게 함(참고 링크)
    2. 해당 API가 호출되어 저장되는 DB DDL과 Java 어플리케이션도 있는데 그건 추후 로그에 작성해보겠음

 

import json
import os

import requests

AWS_ACCOUNT_ID = "입력필요"  # AWS 계정ID(readable한 키워드-고유의 숫자ID 포맷 사용, 해당 파이썬 코드가 실행되는 AWS계정에 맞춰서 변경하세요)
AWS_REGION_CD = "입력필요"  # AWS 리전 코드(해당 파이썬 코드가 실행되는 lambda 리전에 맞춰서 변경하세요)

REQ_AUTH_KEY = "API호출할 때 보안을 위해서 사용하는 인증키"  # API 호출에 사용하는 인증용 키

# HTTP API로 SES알림 저장을 요청하는 end point URL
SES_NOTIFICATION_SAVE_API_URL = "https://블라블라/" + AWS_ACCOUNT_ID + "/" + AWS_REGION_CD + "/블라블라"

def lambda_handler(event, context):
    ses_notification = event['Records'][0]['Sns']['Message']  # SNS로부터 전달받는 이벤트 추출
    data_json = json.loads(ses_notification)  # json으로 파싱/로드

    notification_type = data_json['notificationType']
    if notification_type == "AmazonSnsSubscriptionSucceeded":
        print(f"AmazonSnsSubscriptionSucceeded는 저장하지 않습니다.(SNS로 구독 성공시 이벤트) data_json: {data_json}")
        return

    # 알림 저장 API 호출
    data_json_str = json.dumps(data_json, ensure_ascii=False).encode('utf-8')
    result_save_api = request_http_save(SES_NOTIFICATION_SAVE_API_URL, 10, data_json_str)
    print(f"result_save_api: {result_save_api}", end="\n\n")


def test_save_from_sample_file():  # 테스트 목적으로 만든 파일의 샘플 json을 읽어서 저장요청

    # 샘플: https://docs.aws.amazon.com/ko_kr/ses/latest/dg/notification-examples.html#notification-examples-bounce 를 파일로 만들어서 테스트
    file_name = "test-bounce-exist-dns-data.json"
    # file_name = "test-bounce-not-exist-dns-data.json"
    # file_name = "test-AmazonSnsSubscriptionSucceeded.json"
    current_directory = os.getcwd()
    test_json_file_path = os.path.join(current_directory, file_name)

    with open(test_json_file_path, 'r', encoding='UTF8') as f:
        data_json = json.load(f)  # 문자열 json을 파싱한 내용

    print(f"테스트 파일 {file_name}의 내용 ===>\n\t", json.dumps(data_json, indent=4, ensure_ascii=False), end="\n\n")

    notification_type = data_json['notificationType']
    if notification_type == "AmazonSnsSubscriptionSucceeded":
        print(f"AmazonSnsSubscriptionSucceeded는 저장하지 않습니다. data_json: {data_json}")
        return

    # 알림 저장 API 호출
    data_json_str = json.dumps(data_json, ensure_ascii=False).encode('utf-8')
    result_save_api = request_http_save(SES_NOTIFICATION_SAVE_API_URL, 10, data_json_str)
    print(f"result_save_api: {result_save_api}", end="\n\n")

def request_http_save(uri: str, timeout_seconds: int, req_json_str: str) -> object:
    """
    외부 API에 SES 알림 데이터 전송하는 HTTP통신용 함수

    :param uri: 요청 URI
    :param timeout_seconds: 타임아웃(초)
    :param req_json_str: 요청할 json(문자가 아니라 json타입)
    :return:
    """
    print("\n === Start request_http_save. uri: " + uri)
    headers = {
        'reqAuthKey': REQ_AUTH_KEY,
        'Content-Type': 'application/json; charset=utf-8'
    }

    try:
        # 한글이 포함되어 있을 수 있음
        # req_json_str = json.dumps(ses_notification_json, ensure_ascii=False).encode('utf-8')
        response = requests.request("POST", uri, headers=headers, timeout=timeout_seconds, data=req_json_str)

        return {
            'statusCode': response.status_code,
            'body': response.text
        }

    except requests.exceptions.Timeout as errd:
        print("Timeout Error : ", errd)

    except requests.exceptions.ConnectionError as errc:
        print("Error Connecting : ", errc)

    except requests.exceptions.HTTPError as errb:
        print("Http Error : ", errb)

    # Any Error except upper exception
    except requests.exceptions.RequestException as erra:
        print("AnyException : ", erra)

# API에 저장요청(로컬 테스트를 위해서 파일에서 샘플 Json을 읽어서 호출)
#test_save_from_sample_file()

 

 

트러블슈팅할때 가끔 RSS메모리를 주기적으로 관찰해야할 필요가 있습니다.

커맨드 등등으로 했었는데 아래 bash쉘로도 가능합니다.

 - 참고: https://poonamparhar.github.io/dynamic_compiler_threads/

#!/bin/bash

pid=$1
smaps_file=/proc/$pid/smaps
output_file=rss_$pid.out
rm rss_$pid.out

echo 'Monitoring RSS of the Process' $pid. Saving output to file $output_file.

while true
do
  # Get the current timestamp
  timestamp=$(date +"%FT%T%z")
  # Get the current RSS value
  rss=$(grep -m 1 "^Rss:" "$smaps_file" | awk '{print $2}')
  # write timestamp and rss to the output file
  echo "$timestamp: $rss" >> "$output_file"
  sleep 5
done

 

위 스크립트 생성 후 ps -ef | grep java 로 PID 확인해서 스크립트 아큐먼트로 PID를 입력해서 사용하면 파일로 저장됩니다.

 

P.S. 링크 글 자체의 퀄리티도 꽤 높습니다. 이런 글 볼때마다 커널이나 OS 공부, C공부를 다시 깊게 해보고 싶다는 생각이 드는군요.

-- mvnd 홈 디렉토리 생성 및 다운로드 후 압축해제
cd ~ && wget https://downloads.apache.org/maven/mvnd/1.0-m6/maven-mvnd-1.0-m6-m39-linux-amd64.tar.gz && tar -xzf maven-mvnd-1.0-m6-m39-linux-amd64.tar.gz && rm -f maven-mvnd-1.0-m6-m39-linux-amd64.tar.gz

-- 심볼릭 링크 추가
ln -s maven-mvnd-1.0-m6-m39-linux-amd64 mvnd

-- path 등록
cd ~ && echo 'export PATH=mvnd/bin:$PATH' >> .bashrc && source .bashrc

-- 버전 확인 및 실행 & 프로세스 확인
mvnd --version
ps -ef | grep mvnd


참고
https://blog.frankel.ch/faster-maven-builds/1/

https://rudaks.tistory.com/entry/mvnd-%EC%82%AC%EC%9A%A9%EB%B2%95

https://www.mastertheboss.com/jboss-frameworks/jboss-maven/introduction-to-maven-daemon-mvnd/

가끔 Jit 컴파일러 튜닝해야하는 경우 참고하는 내용
 - https://man.archlinux.org/man/java-openjdk11.1.en#Advanced_JIT_Compiler_Options

개발을 하다보면 이미지 리사이징이 필요한 경우가 있습니다.

관련해서 라이브러리, 방법 등 시간될때마다 정리해둘 예정입니다.(계속해서 업데이트)

 

  1. golang으로 만든 라이브러리 imagor
    1. https://github.com/cshum/imagor
  2. imageMgick. 10여년정도 전에 시스템 구축할때 사용했었고 써봤던거라서 지금도 빠르게 필요할때 가끔 사용
    1. https://imagemagick.org/index.php
  3. GraphicsMagick
    1. imagemaginck를 fork해서 만듬
    2. http://www.graphicsmagick.org/
  4. AWS를 서비스를 이용해서 리사이징
    1. https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-tutorial.html
    2. 클라우드 사용하면서 종종 이용(golang과 람다 조합하면 비용 및 빠른 시작의 이점으로 좋음)
      1. https://netflixtechblog.medium.com/netflix-images-enhanced-with-aws-lambda-9eda989249bf
  5. 대규모 이미지 서비스를 개발한다면 스토리지 비용을 무시할 수 없음. 이때 포맷 선택도 중요한 사항
    1. LINE에서 JPEG->HEIF포맷으로 변환
      1. https://engineering.linecorp.com/ko/blog/antman-project-development-story
      2. 콜드 스토리지를 잘 활용해야함
      3. 사실 이정도를 고려해야하는 서비스는 국내에 많지 않아서 개발 조직 규모/유지보수 용이성 등을 잘 고려해야하고 오버 엔지니어링 안되게 해야함
  6. 오픈소스 이미지 프록시 서버
    1. ImageMagick, GraphicsMagick 등 이미지 변환 작업을 빠르게 해줄 수 있는 단독 서버
    2. 외부에 존재하는 많은 이미지들의 리사이징에 최적
    3. https://github.com/imgproxy/imgproxy
  1. 목적/배경
    1. 서비스를 운영하다보면 봇 등의 공격이 있을 수 있습니다.
    2. 특정 IP를 차단해도 IP를 변경해가면서 공격이 들어옵니다. 이때 효과적인 차단 방법 중 하나입니다.
  2. 제한 사항
    1. AWS의 CloudFront를 사용해야합니다.
    2. CloudFront에서 헤더 추가를 활성화해서 nginx에서 JA3헤더를 얻을 수 있어야합니다.(참고 링크)
  3. 참고
    1. 서버에서 tcpdump -s 0 -A 'tcp dst port 80' 등으로 인입되는 헤더의 CloudFront-Viewer-JA3-Fingerprint 를 분석
      1. AWS JA3헤더 관련 참고 링크
        1. 상세 셋팅 방법은 하단 참고
      2. ja3 fingerprint란? 링크
  4. nginx 설정 방법
    1. 확인된 나쁜 JA3 Fingerprint값을 아래 nginx 설정에 추가해서 1(true)로 설정 -> 403리턴
map $http_cloudfront_viewer_ja3_fingerprint $block_fingerprint {
        default 0;
        "차단할 CloudFront-Viewer-JA3-Fingerprint값" 1;
        "차단할 CloudFront-Viewer-JA3-Fingerprint값" 1;
}

server
{
        if ($block_fingerprint) {
           return 403;
        }

        .......

}

 
추가로, API 요청이었고 rate limit 처리해서 429 리턴 json으로 처리해야하는 경우 아래처럼 작업 가능

error_page 429 /429.json;
location /429.json {
    add_header 'Content-Type' 'application/json charset=UTF-8';
    return 429 '{"success":false, "errorCd":"RATE_LIMITED","msg":"Too Many Requests(rate limit nginx)"}';
}

 


참고- AWS Cloud Front 헤더 셋팅 방법

  1. CloudFront -> Distributions -> 대상 CloudFront -> Edit behavior
    1.  

AWS Cloud Front의 Custom Origin request policy를 추가하는 위치

2. Custom policies 생성

Custom policies 추가하는 방법
샘플 Custom Policy Origin reqeust settings

+ Recent posts