๋์ฉ๋ ์ฒ๋ฆฌ ํ
์คํธ ๊ตฌํ ํ๋ก์ ํธ - 2 (์ฝ๋ ์์ฑ)
2024. 6. 5. 15:47ใProject
๋ฐ์ํ
๐ Redis ๊ด๋ จ ํ์ผ
1. RedisConfig.java
์ญํ | RedisTemplate์ ์ค์ ํ์ฌ Redis ์๋ฒ์ ์ํธ์์ฉ |
---|---|
์ค๋ช | Redis์์ ์ฐ๊ฒฐ์ ์ค์ ํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ๋ฌธ์์ด๋ก ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํํ๋ ๋ฐ ํ์ํ ์ค์ ์ ํฌํจ |
package com.realTime.Insight.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer()); // ํค๋ฅผ ๋ฌธ์์ด๋ก ์ง๋ ฌํ
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // ๊ฐ์ JSON์ผ๋ก ์ง๋ ฌํ
return redisTemplate;
}
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("webSocketTopic")); // ํน์ ์ฃผ์ ์ ๋ฉ์์ง๋ฅผ ์์
return container;
}
}
2. DataService.java
์ญํ | Redis๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ์กฐํํ๋ ์๋น์ค ํด๋์ค |
---|---|
์ค๋ช | Redis์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ณ ์กฐํํ๋ ๋ก์ง ํฌํจ |
package com.realTime.Insight;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
@Service
public class DataService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private ValueOperations<String, Object> valueOperations;
@PostConstruct
public void init() {
valueOperations = redisTemplate.opsForValue();
}
public List getData() {
return redisTemplate.opsForHash().values("TimeSeriesData").stream()
.map(data -> (Data) data)
.collect(Collectors.toList());
}
public void addData(Data data) {
String key = "webSocketTopic:" + System.currentTimeMillis();
valueOperations.set(key, data); // ๋จ์ผ ๊ฐ ์ ์ฅ
redisTemplate.opsForHash().put("TimeSeriesData", key, data); // ํด์ ๊ฐ ์ ์ฅ
}
public List getAllData() {
List dataList = new ArrayList<>();
for (String key : redisTemplate.keys("webSocketTopic:*")) {
dataList.add(valueOperations.get(key));
}
return dataList;
}
}
๐ Kafka ๊ด๋ จ ํ์ผ
1. KafkaConsumerConfig.java
์ญํ | Kafka Consumer ์ค์ ์ ๋ด๋น |
---|---|
์ค๋ช | Kafka์ Consumer๋ฅผ ์ค์ ํ๊ณ , ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ Listener๋ฅผ ์ค์ |
package com.realTime.Insight.config;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import java.util.HashMap;
import java.util.Map;
@EnableKafka
@Configuration
public class KafkaConsumerConfig {
@Bean
public ConsumerFactory<String, String> consumerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id");
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
return new DefaultKafkaConsumerFactory<>(config);
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
return factory;
}
}
2. KafkaProducerConfig.java
์ญํ | Kafka Producer ์ค์ ์ ๋ด๋น |
---|---|
์ค๋ช | Kafka์ Producer๋ฅผ ์ค์ ํ๊ณ , KafkaTemplate์ ์ ๊ณต |
package com.realTime.Insight.config;
import java.util.HashMap;
import java.util.Map;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.support.serializer.JsonSerializer;
@EnableKafka
@Configuration
public class KafkaProducerConfig {
@Bean
public ProducerFactory<String, Object> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return new DefaultKafkaProducerFactory<>(configProps);
}
@Bean
public KafkaTemplate<String, Object> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
3. KafkaProducerService.java
์ญํ | Kafka๋ฅผ ํตํด ๋ฉ์์ง๋ฅผ ์ ์กํ๋ ์๋น์ค ํด๋์ค |
---|---|
์ค๋ช | Kafka์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ๋ก์ง์ ํฌํจ, sendMessage ๋ฉ์๋๋ ์ง์ ๋ ํ ํฝ์ผ๋ก ๋ฉ์์ง๋ฅผ ์ ์ก |
package com.realTime.Insight;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
@Service
public class KafkaProducerService {
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
/**
* Kafka๋ก ๋ฉ์์ง๋ฅผ ์ ์กํ๋ ๋ฉ์๋
* @param topic ๋ฉ์์ง๋ฅผ ์ ์กํ Kafka ํ ํฝ
* @param message ์ ์กํ ๋ฉ์์ง
*/
public void sendMessage(String topic, Object message) {
kafkaTemplate.send(topic, message);
}
}
4. KafkaConsumerService.java
์ญํ | Kafka๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ ์๋นํ๋ ์๋น์ค ํด๋์ค |
---|---|
์ค๋ช | Kafka ๋ฉ์์ง๋ฅผ ์๋นํ๊ณ , ์ด๋ฅผ Redis ๋ฐ WebSocket์ผ๋ก ์ ์กํ๋ ๋ก์ง ํฌํจ |
package com.realTime.Insight;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
@Service
public class KafkaConsumerService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private SimpMessagingTemplate messagingTemplate;
@KafkaListener(topics = "webSocketTopic", groupId = "group_id")
public void consume(String message) {
redisTemplate.opsForList().rightPush("real_time_data", message);
System.out.println("message => " + message);
messagingTemplate.convertAndSend("/topic/data", message);
System.out.println("Consumed message: " + message);
}
}
๐ป Front ํ์ผ (React)
DataDisplay.js ํ์ผ์ ์๋์ ๊ฐ์ด ์์ฑํฉ๋๋ค.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import SockJS from 'sockjs-client';
import { Stomp } from '@stomp/stompjs';
const DataDisplay = () => {
const [data, setData] = useState([]);
useEffect(() => {
// Fetch initial data
axios.get('http://localhost:8080/api/data')
.then(response => {
setData(response.data);
})
.catch(error => {
console.error('There was an error fetching the data!', error);
});
// Setup WebSocket connection
const socket = new SockJS('http://localhost:8080/ws');
const stompClient = Stomp.over(socket);
stompClient.connect({}, frame => {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/data', message => {
const newData = JSON.parse(message.body);
setData(prevData => [...prevData, newData]);
});
});
return () => {
if (stompClient) {
stompClient.disconnect();
}
};
}, []);
return (Data from Backend
{data.map((item) => (
ID: {item.id}Title: {item.title}
Description: {item.description}
Timestamp: {item.timestamp}
))}
);
};
export default DataDisplay;
์ค์ ์ฝ๋๋ ์์ ๊ฐ์ด ์์ฑํ๊ณ , ๋๋จธ์ง ์ฝ๋๋ ์๋ GitHub๋ฅผ ์ฐธ๊ณ ํฉ๋๋ค.
GitHub - sonhoil/Largevolume: ๋์ฉ๋ ์ฒ๋ฆฌ ์์คํ ํ ์คํธ ํ๊ฒฝ ๊ตฌํ ํ๋ก์ ํธ
๋ฐ์ํ
'Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋์ฉ๋ ์ฒ๋ฆฌ ํ ์คํธ ๊ตฌํ ํ๋ก์ ํธ - 3 (JMeter ํ ์คํธ) (0) | 2024.06.10 |
---|---|
๋์ฉ๋ ์ฒ๋ฆฌ ํ ์คํธ ๊ตฌํ ํ๋ก์ ํธ - 1 (๊ฐ์ ๋ฐ ํ๊ฒฝ์ธํ ) (0) | 2024.06.05 |