TaeHyun Lim
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Redis 운영 ###### tags: `Etc` ## Redis 특징 1. Key-value 스토어 - 단순 String에 대한 key-value 지원 2. Collection 자료 구조 지원 - List, Set, Sorted Set, Hash 등의 자료 구조 지원 - 분산 서버 환경에서 처리하기 편함 3. Pub/Sub 지원 - Pub/Sub 모델 지원 - 서버 간에 통지가 필요할 때 유용 4. Persistent Layer(디스크 저장) - 메모리 상태를 디스크로 저장하는 RDB 기능 - 현재까지의 업데이트 관련 명령을 저장하는 AOF 기능 5. Replication - Primary-Secondary 구조 - 장애 발생에 대한 failover 대비 - 읽기 처리에 대한 부하 분산 6. 빠른 속도 - In-Memory로 빠른 성능을 보장 ## Redis VS Memcached ### Memcached는 Cache Solution! - cache는 빠른 속도를 위해 사용했던 것, 혹은 사용할 데이터를 저장해두는 것 - 하지만 빠른 성능을 위한 optional한 Solution이기 때문에 데이터가 사라져도 큰 문제가 없다. ### Redis는 Cache + Store Solution! - 데이터를 유지해야하는 특성이 있기 때문에 Memcached보다 좀 더 민감하게 다뤄야한다. - 따라서 디스크에 저장하는 RDB, AOF 기능이 추가되어 있다. - 또한, Collection 기능이 있어 개발의 생산성면에서 효과적이다. - 하지만 Memcached보다 응답 속도의 균일성이 떨어진다. - jemalloc이란 메모리 할당 구조로, 매번 malloc과 free를 통해 메모리 할당이 이루어진다. - 하지만 Memcached는 slab 할당자를 사용해 내부적으로 메모리 할당을 다시 하지 않고 관리하는 형태를 사용한다. - 즉, Redis는 메모리를 직접적으로 사용하기 때문에 Memory Fragment가 발생해 할당 비용때문에 응답 속도가 느려진다. ## Redis 운영 관리 팁 ### Redis가 싱글 스레드임을 인지하자. - 싱글 스레드임을 인지하지 않으면 의도하지 않은 장애나 성능 저하가 발생한다. - 싱글 스레드 특징으로 생긴 원인은 긴 명령을 호출하면 다른 명령을 처리하지 못하는 것이다. - 밑에서 설명하는 팁들도 다 이 특징을 고려한 것들이다. ### Keys 명령을 사용하지 마라 - keys 명령어는 현재 서버에 저장된 key 목록들을 조회하는 명령이다. - 즉, key를 모두 갖고 오는 과정에서 다른 명령을 처리하지 못한다. - keys 명령을 사용해야 한다면, `list`, `set`, `sorted set`을 사용해 `userlist_20200406` 같은 이름으로 데이터를 각 Collection에 묶어서 저장한다. - 그렇게 되면 Collection의 `get`, `hget` 명령을 이용해 묶어진 범위내의 Keys들만 조회하면서 갖고 올 수 있다. ### flushall, flushdb 명령을 조심하자 - Redis는 db라는 공간으로 분리해 데이터를 따로 저장할 수 있다. - select 명령으로 db를 이동할 수 있다. - select 명령을 사용하지 않았다면 기본적으로 0번 db를 사용한다. ```shell= select 0 set name "1234" select 1 set name "4321" get name ==> "4321" select 0 get name ==> "1234" ``` - 모든 데이터를 삭제, 특정 db내의 모든 데이터 삭제하는 명령어 - flushall 명령은 모든 Keys를 조회해서 삭제하기 때문에 O(n) 시간이 걸려, key 수가 많으면 상당히 오래걸린다. - Memcached의 flushall은 상당히 빠르다. - 그 이유는 데이터를 삭제하지 않고 명령어를 실행한 시간을 기록하기만 하기 때문이다. - 이전에 저장된 key들은 get 접근할 때 기록했던 시간을 비교해 지운다. ## Persistent - Memcached는 서버 장애시, 모든 데이터가 사라진다. - 하지만 Redis는 디스크에 저장된 데이터를 기반으로 복구할 수 있다. - 그래서 저장소로 Redis를 사용할 때 필수 기능이지만 장애의 주 원인이 될 수 있다. ### RDB - 현재 메모리에 대한 덤프를 생성하는 기능 - Redis의 메모리 스냅샷을 파일로 저장한 파일의 확장자명이다. - 사용하기 위해서 redis.conf에 내용을 추가하거나 config set/get 명령으로 변경할 수 있다. ``` dbfilename dump.rdb ``` ``` config set dbfilename test.rdb config get dbfilename ===> 1) "dbfilename" ===> 2) "test.rdb" ``` - RDB 저장 명령으로 `SAVE`와 `BGSAVE`가 있다. - SAVE는 현재 작업을 멈추고 덤프를 생성한다. - 기본적으로 RDB는 사용하는 옵션으로 되어있으며, SAVE 명령으로 동작한다. - `BGSAVE`는 덤프를 저장하는 동안 다른 작업을 할 수 있게 프로세스를 fork해서 자식 프로세스로 백그라운드 실행할 수 있게 도와준다. - 현재 메모리 상태를 복제한 것을 기반으로 데이터를 저장한다. - 하지만 Fork하는데 문제가 발생한다. - OS가 자식 프로세스를 생성하면 부모 프로세스의 메모리를 모두 복사해야 한다. - 따라서 부모 프로세스가 10GB 메모리를 사용하면 자식 프로세스에 복사할 메모리도 10GB의 메모리가 필요하다. - Copy On Write 기술을 적용해도 부모 프로세스 메모리에서 실제 변경이 발생한 부분만 복사해도 Redis는 대부분 Write가 많아 메모리가 많이 필요하다. - Fork 문제 정리 - 자식 프로세스가 생성 시, 메모리 사용을 추가하지 않고 부모 프로세스의 메모리를 공유 받는다. - 자식 프로세스에 Write 요청이 있으면 자식 프로세스에도 데이터가 복사된다. - 여기서, Write 작업이 많아지면 결국엔, 자식 프로세스도 부모 프로세스가 사용하는 메모리 양만큼 데이터가 차게 된다. - 메모리 할당법 - Redis는 싱글 스레드이기 때문에 자원 활용을 위해서 CPU Core수 만큼 서버를 생성하는 것이 좋다. - 그리고 Fork를 해 RDB를 저장하는 용도의 프로세스를 고려해야 한다. - 예로 들어, CPU Core가 4개이고 메모리를 32GB 사용하는 컴퓨터라고 생가갛자. - Core 4개를 다 사용하기 위해 4개의 Redis 서버가 필요해 4개의 프로세스를 사용해야 한다. - 여기서 RDB를 BGSAVE할 Fork 프로세스까지 +1 해서 5개가 필요하다. - 그래서 32GB/5 = 6GB를 각 서버에 할당하는 것이 좋다. ### AOF - Append Only File - 기존의 DBMS에서 제공하는 Write Ahead LOg와 비슷한 기능 - 과정 1. 데이터 저장전에 AOF 파일에 현재 수행해야 할 명령을 저장 2. 파일 쓰기 완료 3. 실제 명령어를 메모리 내용에 반영 - AOF 파일은 Redis 프로토콜 그대로 저장 - redis.conf에 appendonly가 yes로 설정, appendfilename으로 지정한 이름으로 저장됨 - appendfilename을 지정하지 않으면 기본 값인 appendonly.aof로 저장됨 ### RDB VS AOF 우선순위 - 최신 데이터를 더 많이 가진 파일을 읽어야 됨 - AOF는 항상 메모리에 반영하기 직전에 Write한 파일이기 때문에 AOF를 우선순위를 크게 두고 사용한다. - RDB는 특정 시간 단위로 저장하기 때문에 다음에 저장하는 명령 이전의 데이터는 적용이 안되 데이터가 유실되기 때문이다. - 하지만 AOF에서 appendfsync 값을 설정할 때 주의해야한다. - `appendfsync everysec`: AOF 값을 추가할 때마다 호출해 디스크에 쓴다. - `everysec`: 매초마다 fsync를 호출해 디스크에 쓴다. - `no`: OS가 실제 sync할 때까지 따로 설정하지 않는다. ## Read는 되지만 Write가 실패하는 상황 - Heartbeat 체크는 이상이 없지만 RDB 저장이 실패해 Write가 동작하지 않는 현상이 발생할 수 있다. - 이 경우는 Hearbeat 체크가 Read 관련 명령을 사용하기 때문에 이상이 없다고 말한다. - Write가 실패하는 경우 - RDB를 저장할 디스크 여유 용량이 없는 경우 - 디스크가 고장난 경우 - 메모리 부족으로 자식 프로세스를 생성하지 못하는 경우 - 자식 프로세스가 강제로 종료된 경우 - 즉, RDB에 이상있으면, 실제 메모리에 Write도 동작하지 않는다. - RDB 이상시에도 Write 허용 방법 1. 이미 운영 중인 Redis의 적용 ``` config set stop-writes-on-bgsave-error no ``` 2. redis.conf에 미리 등록 ``` stop-writes-on-bgsave-error no ``` ## Replication - Redis는 Primary-Secondary 형태의 복제 모델을 제공한다. - Primary 변경 사항이 Secondary들에게 전파되는 구조이다. - Secondary는 무조건 하나의 Primary만을 가질 수 있다. - Secondary도 Primary로써 동작할 수 있다. - 운영 중인 장비에서 Primary 대상을 선택하는 명령 ``` slaveof ip port ``` ``` pc 1) redis-server -port 6379 pc 2) redis-server -port 6380 redis-cli -p 6380 slaveof 127.0.0.1 6379 ``` - 위의 경우는 6379 포트의 Redis server가 Primary, 6380 포트의 Redis-server가 Secondary가 된다. - redis.confg 수정 ``` slaveof 127.0.0.1 6379 - info 명령어로 관계를 확인할 수 있다. - 우선 위의 redis server 추가 생성은 할 수 없다. - redis을 설치하고 난 뒤, utils 폴더에 있는 `install_server.sh`를 실행해 새로운 포트의 인스턴스를 만들어야 한다. ### Replication 과정 1. slave of 명령어로 마스터 서버를 설정 2. main -> initServer -> serverCron -> replicationCron 3. replicationCron에서 현 상태에 따라 connectWithMaster를 호출 4. Primary는 Replication을 위해 RDB를 생성하고 Secondary에게 전송 5. Secondary는 RDB를 로드하고 차이에 따른 명령을 마스터에게 전달받아 Replication을 완료 ### Redis Replication 주의 사항 1. slaveof no one - Secondary는 Primary와 연결이 끊기면 재접속을 시도 - 이 과정에서 Primary에서 전체 데이터를 다시 가져와 Primary의 최종 상태로 자신의 데이터를 변경한다. - 하지만 Primary가 장애로 데이터가 날라가면 Secondary의 데이터도 모두 사라진다. - 따라서 Primary에 장애가 일어났음을 인지했다면 Secondary에게 `slaveof no one` 명령을 줘서 Replication 관계를 끊는다. 2. Replication을 사용하면 RDB가 BGSAVE로 동작한다. - 사용자 설정과 무관하게 무조건 Secondary에게 전달할 RDB를 만들기 위해 프로세스를 fork해서 RDB를 생성한다. ## Redis Migration 방법 1. 새로운 Redis 인스턴스를 생성해 실행한다. 2. 만든 Redis 인스턴스를 기존 마스터의 Secondary로 지정한다. 3. 이 장비에 `slave-read-only` 설정을 꺼, 업데이트가 가능하게 설정한다. ``` config set slave-read-only no ``` 4. Redis 클라이언트들을 새로운 Redis Server를 Primary로 인식하게 설정을 바꾼다. 5. `slaveof no one` 명령으로 기존에 있던 Redis server와의 Replication 관계를 끊는다. 6. 기존 Redis 장비를 제거한다. ## Sentinel - High Availability(고 가용성)을 위해선 Primary가 죽었을 경우 Secondary를 승격시키는 시스템이 존재해야 한다. - 장애 판별 -> Secondary를 Primary로 승격 -> 이 작업을 Client에게 통보 - 위 같은 과정은 `Sentinel`이란 데몬을 사용해 쉽게 작업을 처리할 수 있다. - 하지만 Sentinel은 Client을 알 수 없으므로, Pub/Sub으로 Sentinel에 등록해야 한다. ### 장애 판별 - Sentinel은 Primary, Secondary에 장애가 발생했음을 기본적으로 PING 명령의 응답으로 판단한다. - 하지만 응답이 없다고 바로 서버가 장애라고 판단하지 않는다. - PING 명령은 `sentinelPingReplyCallback` 함수에서 응답 시간을 기록한다. - Sentinel은 `SDOWN`, `ODOWN`이란 두가지 상태로 장애를 인식한다. - SDOWN: 주관적인 장애 상태 - PING이 오지 않는 시간과 현재 시간의 간격의 차이를 보고 결정 - ODOWN: 객관적인 다운 상태 - Sentinel 설정에 있는 Failover를 위한 정족수 설정 이상의 Sentinel 서버가 장애라 판단하면 ODOWN 상태가 된다. ### Secondary 승격 - SDOWN, ODOWN, DISCONNECT된 Secondary는 제외 - last_avail_time이 info_validity_time보다 작으면 제외 - info_refresh가 info_validity_time보다 작으면 제외 - master_link_down_time이 max_master_down_time 보다 크면 제외 - 남은 후보 중 slave_priority가 높은 Secondary를 우선적으로 선택됨 - priority가 같으면 runid를 비교해 가장 큰 값을 Primary로 선택 - 백업 전용 서버처럼 승격하면 안되는 Secondary는 redis.conf에서 slave_priority를 0으로 설정한다. ### sentinel.conf - sentinel monitor 클러스터명 PrimaryIP PrimaryPort 정족수 - sentinel down-after-milliseconds 클러스터명 시간밀리세컨드 - 다운으로 인식하는 시간 설정 - SDOWN을 인식하는 Period - sentinel failover-timeout 클러스터명 시간밀리세컨드 - failover 시에 사용하는 timeout - failover가 위에서 설정한 시간이 지나도 수행되지 않으면 포기한다. - sentinel can-failover 클러스터명 yes - yes로 설정해야만 Sentinel이 failover를 진행할 수 있다. - sentinel parallel-syncs 클러스터명 sync할Secondary수 - 새 Primary 승격 후 몇 개의 Secondary가 sync되야 실제 Client에게 알려줄 지 설정 ### Sentinel은 Primary 정보만 알아도 된다. - sentinel monitor 설정에 Secondary 서버 주소를 설정해도 Primary 주소로 자동으로 변경된다. - 그 이유는 Primary에서 info 명령어로 Secondary 정보들을 알 수 있기 때문이다. ## 모니터링 툴 공부하자.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully