Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/.DS_Store
Binary file not shown.
22 changes: 22 additions & 0 deletions .github/ISSUE_TEMPLATE/bug-report-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: Bug Report Template
about: '버그 리포트 이슈 템플릿 '
title: ''
labels: ''
assignees: ''

---

## 어떤 버그인가요?

> 어떤 버그인지 간결하게 설명해주세요

## 어떤 상황에서 발생한 버그인가요?

> (가능하면) Given-When-Then 형식으로 서술해주세요

## 예상 결과

> 예상했던 정상적인 결과가 어떤 것이었는지 설명해주세요

## 참고할만한 자료(선택)
18 changes: 18 additions & 0 deletions .github/ISSUE_TEMPLATE/feature-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: feat issue template
about: for new features
title: "[Feat]"
labels: feat
assignees: ''

---

## 어떤 기능인가요?
> 추가하려는 기능에 대해 간결하게 설명해주세요

## 작업 상세 내용
- [ ] TODO
- [ ] TODO
- [ ] TODO

## 참고할만한 자료(선택)
15 changes: 15 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## #️⃣연관된 이슈

> ex) #이슈번호, #이슈번호

## 📝작업 내용

> 이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

### 스크린샷 (선택)

## 💬리뷰 요구사항(선택)

> 리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요
>
> ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?
37 changes: 37 additions & 0 deletions .github/workflows/cd-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CD with Gradle and Docker

on:
push:
branches:
- 'main'
pull_request:
branches:
- 'main'

permissions:
contents: read

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: ☕️ Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Grant execute permission for Gradlew
run: chmod +x ./gradlew

- name: 🐘 Build with Gradle
run: ./gradlew clean build -x test --stacktrace

- name: 💣 Build and Push Docker Image
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/memcached_server:latest .
docker push ${{ secrets.DOCKER_USERNAME }}/memcached_server:latest
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM gradle:8.5-jdk17 AS builder
WORKDIR /app
COPY . .
RUN gradle bootJar --no-daemon --build-cache

FROM openjdk:17
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
244 changes: 244 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# Distributed Memcached Server

분산 캐시 시스템의 Spring Boot 클라이언트 애플리케이션입니다. Consistent Hashing 알고리즘을 사용하여 여러 Memcached 노드에 데이터를 분산 저장하고, Apache Zookeeper를 통해 노드 상태를 관리합니다.

## 시스템 아키텍처

### 주요 구성 요소

1. **ZookeeperConfig**: Zookeeper 연결 설정 및 Bean 등록
2. **ZookeeperConnection**: Zookeeper 클라이언트 초기화 및 이벤트 핸들러 등록
3. **ZKEventHandler**: Zookeeper 노드 변화 이벤트 처리
4. **HashingManager**: Consistent Hashing 기반 노드 분산 관리
5. **CacheManager**: 캐시 데이터 저장/조회/삭제 인터페이스

### 기능

- **분산 캐시 저장**: Consistent Hashing을 통한 효율적인 데이터 분산
- **동적 노드 관리**: Zookeeper를 통한 실시간 노드 추가/제거 감지
- **자동 리밸런싱**: 노드 변화 시 해시 링 자동 재구성
- **REST API**: HTTP 기반 캐시 조작 인터페이스

## 사전 요구사항

- Java 17 이상
- Apache Zookeeper 3.x
- Memcached 1.4 이상
- Docker (Memcached 노드 실행용)

## 설치 및 실행

### 1. Zookeeper 설치 및 실행

```bash
# Zookeeper 다운로드 및 실행
wget https://downloads.apache.org/zookeeper/zookeeper-3.8.3/apache-zookeeper-3.8.3-bin.tar.gz
tar -xzf apache-zookeeper-3.8.3-bin.tar.gz
cd apache-zookeeper-3.8.3-bin

# 설정 파일 복사
cp conf/zoo_sample.cfg conf/zoo.cfg

# Zookeeper 실행
bin/zkServer.sh start
```

### 2. Memcached 노드 실행 (Docker)

```bash
# 첫 번째 Memcached 노드
docker run -d --name memcached1 -p 11211:11211 memcached:latest

# 두 번째 Memcached 노드
docker run -d --name memcached2 -p 11212:11211 memcached:latest

# 세 번째 Memcached 노드
docker run -d --name memcached3 -p 11213:11211 memcached:latest
```

### 3. Zookeeper에 노드 등록

```bash
# Zookeeper CLI 접속
bin/zkCli.sh

# Memcached 경로 생성
create /memcached ""

# 노드 등록 (데이터에 host:port 형식으로)
create /memcached/node1 "127.0.0.1:11211"
create /memcached/node2 "127.0.0.1:11212"
create /memcached/node3 "127.0.0.1:11213"
```

### 4. Spring Boot 애플리케이션 실행

```bash
# 프로젝트 빌드 및 실행
./gradlew bootRun
```

## API 사용법

### 데이터 저장

```bash
curl -X POST http://localhost:8080/api/cache/mykey \
-H "Content-Type: application/json" \
-d '"Hello, World!"'
```

### 데이터 조회

```bash
curl -X GET http://localhost:8080/api/cache/mykey
```

### 데이터 삭제

```bash
curl -X DELETE http://localhost:8080/api/cache/mykey
```

### 캐시 상태 확인

```bash
curl -X GET http://localhost:8080/api/cache/status
```

### 헬스 체크

```bash
curl -X GET http://localhost:8080/api/cache/health
```

## 설정 파일

`src/main/resources/application.yml`:

```yaml
# Zookeeper Configuration
zookeeper:
address: localhost:2181

memcached:
path: /memcached

# Server Configuration
server:
port: 8080

# Logging Configuration
logging:
level:
com.DSC.distributedCache: INFO
org.apache.curator: WARN
net.spy.memcached: WARN

# Application Configuration
spring:
application:
name: distributed-cache-server

# Health Check Configuration
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: always
```

## 시퀀스 다이어그램

### 데이터 저장 시퀀스
1. Client → CacheManager: addData(key, value)
2. CacheManager → HashingManager: getNode(key)
3. HashingManager → CacheManager: MemcachedClient
4. CacheManager → MemcachedClient: set(key, expire, value)
5. MemcachedClient → CacheManager: isAdded

### 데이터 조회 시퀀스
1. Client → CacheManager: getData(key)
2. CacheManager → HashingManager: getNode(key)
3. HashingManager → CacheManager: MemcachedClient
4. CacheManager → MemcachedClient: get(key)
5. MemcachedClient → CacheManager: data

### 노드 변화 처리 시퀀스
1. Zookeeper → ZKEventHandler: childEvent()
2. ZKEventHandler → HashingManager: addNode() or removeNode()
3. HashingManager: 해시 링 재구성

## 테스트

### 노드 동적 추가 테스트

```bash
# 새 Memcached 노드 실행
docker run -d --name memcached4 -p 11214:11211 memcached:latest

# Zookeeper에 노드 추가
bin/zkCli.sh
create /memcached/node4 "127.0.0.1:11214"
```

### 노드 제거 테스트

```bash
# Zookeeper에서 노드 제거
bin/zkCli.sh
delete /memcached/node4

# Memcached 컨테이너 중지
docker stop memcached4
```

## 트러블슈팅

### Zookeeper 연결 실패
- Zookeeper 서버 상태 확인: `bin/zkServer.sh status`
- 방화벽 설정 확인
- 포트 2181 사용 가능 여부 확인

### Memcached 연결 실패
- Docker 컨테이너 상태 확인: `docker ps`
- 포트 바인딩 확인
- Memcached 로그 확인: `docker logs <container_name>`

### 해시 링 불일치
- 애플리케이션 재시작
- Zookeeper 노드 등록 상태 확인: `ls /memcached`

## 개발자 가이드

### 패키지 구조

```
com.DSC.distributedCache/
├── config/
│ └── ZookeeperConfig.java
├── zookeeper/
│ ├── ZookeeperConnection.java
│ └── ZKEventHandler.java
├── hashing/
│ └── HashingManager.java
├── cache/
│ └── CacheManager.java
├── controller/
│ └── CacheController.java
└── DistributedCacheApplication.java
```

### 확장 포인트

1. **다른 해싱 알고리즘**: `HashingManager.hashing()` 메서드 수정
2. **추가 캐시 백엔드**: `CacheManager`에 새로운 클라이언트 추가
3. **모니터링**: Spring Actuator를 통한 메트릭 추가
4. **보안**: Spring Security를 통한 인증/인가 추가

## 라이선스

이 프로젝트는 MIT 라이선스를 따릅니다.
11 changes: 11 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'

// Zookeeper dependencies
implementation 'org.apache.curator:curator-framework:5.4.0'
implementation 'org.apache.curator:curator-recipes:5.4.0'

// Memcached client
implementation 'net.spy:spymemcached:2.12.3'

// For consistent hashing
implementation 'com.google.guava:guava:32.1.2-jre'

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
Loading