728x90
반응형
Redis 큐 기반 GPU 별 작업 할당 및 처리
*자세한 설명 생략
▷ 시스템 구성도
▷ 프로젝트 구조
*필요한 부분만 필터링
< 파일 따라가기 >
*순서대로 나열
▷ RedisConfig.java
package gms.cmm.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import gms.cmm.util.TaskManager;
/**
* Redis Config
*/
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private TaskManager taskManager;
@Value("${redis.subscribe.channel}")
private String SUBSCRIBE_CHANNEL;
/**
* Redis 구독 설정
*/
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener(messageListener(), new ChannelTopic(SUBSCRIBE_CHANNEL));
return container;
}
/**
* Redis 메시지 리스너
*/
private MessageListener messageListener() {
return new MessageListener() {
@Override
public void onMessage(Message message, byte[] pattern) {
byte[] resultData = message.getBody();
taskManager.setResultData(resultData);
}
};
}
}
▷ TaskManager.java
package gms.cmm.util;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
/**
* Task Manager
*/
@Component
@RequiredArgsConstructor
public class TaskManager {
@Autowired
private StringRedisTemplate redisTemplate;
private final Lock lock = new ReentrantLock();
private byte[] resultData;
/**
* Lock 객체
*
* <pre>
* - 여러 스레드가 동시에 자원에 접근하지 않도록 동기화
* </pre>
*/
public Lock getLock() {
return lock;
}
/**
* Redis 큐 추가
*
* @param queueName
*/
public void addTaskToQueue(String queueName) {
String requestId = UUID.randomUUID().toString();
redisTemplate.opsForList().leftPush(queueName, requestId);
}
/**
* 결과 데이터 반환
*
* @return
*/
public byte[] getResultData() {
return resultData;
}
/**
* 대기 중인 스레드에 작업 완료 알림
*
* @param resultData
*/
public void setResultData(byte[] resultData) {
synchronized (lock) {
this.resultData = resultData;
lock.notify();
}
}
}
▷ IMG1000Controller.java
package gms.gms.img.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import gms.cmm.api.CmmController;
import gms.cmm.util.CmmUtil;
import gms.gms.img.service.IMGService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
/**
* Image 서비스 Controller
*/
@RestController
@RequestMapping("img")
@Tag(name = "IMAGE", description = "IMAGE 서비스")
@Slf4j
public class IMG1000Controller extends CmmController {
@Autowired
private IMGService imgService;
@GetMapping("/img1000.do")
@Operation(summary = "IMG-1000", description = "이미지 생성")
public ResponseEntity<?> IMG1000() {
final String title = "IMG-1000";
ResponseEntity<byte[]> resVO = new ResponseEntity<>(HttpStatus.OK);
try {
resVO = imgService.getIMG1000();
if (resVO.getBody() == null) {
return ResponseEntity.status(500).build();
}
} catch (Exception e) {
CmmUtil.errLogStamp(title, e);
return ResponseEntity.status(500).build();
}
return resVO;
}
}
▷ IMGServiceImpl.java
package gms.gms.img.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import gms.cmm.util.TaskManager;
import gms.gms.img.service.IMGService;
import lombok.extern.slf4j.Slf4j;
/**
* Image 서비스 Impl
*/
@Service
@Slf4j
public class IMGServiceImpl implements IMGService {
@Autowired
private TaskManager taskManager;
@Value("${redis.img.queue}")
private String IMG_QUEUE;
/**
* IMG-1000: 이미지생성
*/
@Override
public ResponseEntity<byte[]> getIMG1000() {
try {
// 작업 큐 추가
taskManager.addTaskToQueue(IMG_QUEUE);
// GPU 서버가 작업을 완료할 때까지 대기
synchronized (taskManager.getLock()) {
taskManager.getLock().wait();
}
// 작업 완료
byte[] resultData = taskManager.getResultData();
log.info(resultData+"");
if (resultData == null) {
return ResponseEntity.status(500).build();
}
// 결과 이미지 반환
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE)
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=image.png")
.body(resultData);
} catch (Exception e) {
log.error("getIMG1000 Err: " + e.getMessage(), e);
return ResponseEntity.status(500).build();
}
}
}
▷ IMGService.java
package gms.gms.img.service;
import org.springframework.http.ResponseEntity;
/**
* Image 서비스
*/
public interface IMGService {
/** IMG-1000: 이미지생성 */
public ResponseEntity<byte[]> getIMG1000();
}
▷ application.properties
## Server
server.port=9999
# Redis
spring.data.redis.url=redis://127.0.0.1:6379
redis.subscribe.channel=gpu_channel
redis.img.queue=gpu_image
▷ 관련 글
728x90
728x90
'▶ Back-End > Java' 카테고리의 다른 글
Get Add Time(HHH:mm:ss) (0) | 2024.11.27 |
---|---|
Get Convert HHH:mm:ss to Second (0) | 2024.11.27 |
Get Convert Second to HHH:mm:ss (0) | 2024.11.27 |
Get Days Between Count (0) | 2024.11.27 |
Get Date Now in String (0) | 2024.11.27 |
댓글