묻고 답해요
137만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨Real MySQL 시즌 1 - Part 1
PreparedStatment 사용 시 메모리 사용 증가
안녕하세요. 좋은 강의 감사 드립니다.PrepareStatement 사용 시 메모리 사용률이 증가하는 단점에 대해 다루어주셨는데, 혹시 이 부분을 실제로 확인할 수 있는 메트릭이있다면 공유 부탁 드립니다. 실제로 이 이슈를 재현해보고 싶습니다.
-
해결됨대용랑 채팅 TPS에 대한 stateful 서비스 구축하기
카프카의 이유
안녕하세요 강사님 아키텍처에 궁금한 점이 생겨 질문드립니다.카프카를 사용한 이유가 채팅 서버의 상태를 비동기로 전송하기 위함이라 이해했습니다.채팅 서버가 실행/종료될 때카프카에 이벤트 발행컨트롤 서버가 이벤트 컨슈밍하며 채팅서버 상태 확인제가 제대로 이해한게 맞다면 대략 위와 같은 흐름이라 이해했습니다. 즉 채팅 서버의 상태를 컨트롤 서버에 알리기 위해 카프카라는 메시지 브로커를 둔것 같은데, 카프카를 사용하지 않고 채팅서버에서 컨트롤 서버로 직접 상태를 전송하는 방식은 불가능할까요.? 이 상황에서 카프카가 굳이 필요한건지 라는 의문이 들어 질문하게 됐습니다ㅇㅅㅇ.
-
미해결[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스
여러분 우분투에서 mysql 설치 질문있습니다.
처음에 터미널 열어서 아무 블로그에서 나오는대로 설치하고 로그인도하고 잘했던거같아요.근데 강의 따라하면서 dbeaver-ce에 연결이안되서 내가 설치를 잘못했나 싶어서검색해서 mysql 지웠습니다.근데 리눅수 우분투 App Center에 mysql치면 나오는게있길래 mysql-shellmysql-server두개를 설치후,mysql -u root -p 를하면 ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2) 이런 에러가 나옵니다.다시 재설치를위해서sudo apt-get install mysql-server명령어를 입력하면몇몇 패키지를 설치할 수 없습니다. 요청한 상황이 불가능할 수도 있고, 불안정 배포판을 사용해서 일부 필요한 패키지를 아직 만들지 않았거나, 아직 Incoming에서 나오지 않은 경우일 수도 있습니다. 이 상황을 해결하는데 다음 정보가 도움이 될 수도 있습니다: 다음 패키지의 의존성이 맞지 않습니다: mariadb-client-core : 충돌: virtual-mysql-client-core mysql-community-server-core : 의존: libaio1 (>= 0.3.93) 하지만 설치할 수 없습니다 추천: mecab-ipadic-utf8 하지만 %s 패키지를 설치하지 않을 것입니다 E: 오류, pkgProblemResolver::Resolve가 망가졌습니다. 고정 패키지때문에 발생할 수도 있습니다. 이렇게 터미널에 나옵니다.마리아db를 설치한적도없는데 왜 충돌나는건지 잘 모르겠네요.. 혹시 제가 겪은거 겪고 해결해보신분 계실까요?ㅠㅠ
-
해결됨대용랑 채팅 TPS에 대한 stateful 서비스 구축하기
컨트롤 서버가 다운되면 어떻게 되나요?
[이 강의에서 다룰 zero-downtime-deploy를 위한 아키텍처 구조도를 알려드릴게요] 강의를 들으면서 컨트롤 서버의 필요성에 대해 설명해주셨습니다. 채팅 서버 1,2,3 이 다운될 때를 고려해서 로드 밸런싱 용으로 컨트롤 서버를 따로 둔다고 이해했는데, 컨트롤 서버가 배포되거나 다운되는 경우는 없을까요? 컨트롤 서버도 이중화로 구성을 해야하는 것인지, 다른 방법은 무엇이 있는지 궁금합니당
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
@Column 어노테이션 안써도 되는 경우 질문이요!
저희 학습내용으로 보면private Integer age; 는 테이블의 age int,와 같아서 어노테이션 안써도 된다고 하셨는데그럼 name 같은경우도 테이블의그냥 컬럼명과 타입 똑같은 조건인데왜 어노테이션쓰고 nullable = false, length = 25라고 해야하나요??그리고 한가지만 더 질문 드릴게요!저는 서버 실행하면 콘솔쪽에 따로 쿼리가 안찍히던데 왜그럴까요?? 이상은 없는데 hibernate가 인식이 안되서 그런건지콘솔에 쿼리가 안찍히네요ㅠㅠ
-
미해결Real MySQL 시즌 1 - Part 1
CHAR VARCHAR 질문입니다!
안녕하세요 먼저 좋은 강의 감사드립니다. CHAR vs VARCHAR를 수강하던 중 궁금한 점이 생겨 질문 남깁니다!1. CHAR의 경우 미리 공간을 할당해두기 때문에 update 시 파편화되는 부분이 없지만, VARHAR의 경우 길이가 더 길게 update 시 처음 레코드가 저장되었던 공간은 delete marking 후에 새롭게 빈 공간에 레코드를 저장하는 것으로 이해했습니다. 그렇다면 VARCHAR에서 길이가 더 짧거나 길이가 같게 update를 하는 경우는 어떻게 동작하는걸까요? UTF8MB4 CHAR 경우 미리 할당된 데이터 보다 더 큰 데이터를 업데이트 하게 된다면 VARCHAR 처럼 처음 레코드가 저장되었던 공간은 delete marking후 새롭게 빈 공간에 레코드를 저장하게 되는걸까요? 예시 : CHAR(10)에 '한글'을 저장했다가, '한글 연습'을 업데이트 하는 경우 VARCHAR 처럼 동작하는지가 궁금합니다.
-
해결됨인프라공방 - 그럴듯한 서비스 만들기
지하철 노선도, 설문 조사 코드
지하철 노선도 코드와 설문 조사 코드는 언제 사용하는건가요?강의 내용에는 어느 서버에 올리라는 이야기가 없더라구요그리고 리버스 프록시는 어느 서버에 구성해야 하는지 모르겠습니다!
-
해결됨Real MySQL 시즌 1 - Part 1
실제 프로젝트에서의 데이터 타입 환경
안녕하세요.강의 잘 보고 있습니다.(너무 감사합니다.)일단 char와 varchar에 대해서는 저는 이전부터 고민이 많았는데요. 이번 강의를 보면서 기존 인터넷에서 보던 자료와 상충하는 내용이 발생하여 질문을 드리고 싶습니다.(물론 '누구의 자료가 잘못됐다'라는 것이 아니라 초보자인 제 입장에서 정말 궁금해서 질문을 드린다는 말씀을 드리고 싶습니다!)사실 내용을 여럿 찾아봤는데 결과적으로 char를 써야 할 경우 TRIM을 통해 공백을 지워야 하기 때문에 그러한 연산이 더 들어가므로 varchar를 쓰는 것이 귀찮음도 없고 좋다라는 글을 보았던 것 같습니다.(백엔드 개발자의 입장에서도 편리하다고 생각합니다.)하지만 varchar를 쓸 경우 말씀해주신 것처럼 데이터의 길이가 기존보다 클 경우 기존 데이터를 삭제하고 새로 옮겨야 하는 비효율적인 작업이 증가할 뿐더러 데이터 페이지의 파편화가 발생할 수 있다는 생각도 정말 충분히 납득이 가는 설명이었습니다.실제로 웬만해서는 char보다는 varchar를 쓰는 편일까요? 아니면 trim의 연산을 하는 것을 감안하고 char를 쓰는 편일까요?
-
해결됨인프라공방 - 그럴듯한 서비스 만들기
안녕하세요. BFF 사용 이유 관련되서 질문이 있습니다.
안녕하세요. nextXXXX에서 언제 개설되나 궁금했었는데 이렇게 강의로 나오다니 좋네요.. BFF를 도입한 이유에 대해서 말씀 주신것 중에 궁금한게 있습니다!트래픽 대응, 크롤링, 시스템 점검과 같은 클라이언트 접근 제어와 관련된 정책을 한곳에서 관리 가능 및 보안성 수준 제공 가능=> Q. 나머지는 이해되는데 크롤링이 잘 이해가 안갑니다 front 모듈에서 크롤링을 시도해서 client한테 뿌려주는건가요? 사용자에게 노출되어야 하는 정보를 제한할 수도 있음bff가 없다면 변경사항이 있을때 마다 내부적으로 사용하는 API와 public call을 위한 api 모두 변경을 해야 합니다(백엔드 api랑 프론트 모두 변경해야 한다는건가?) 그러다보면 놓치는 부분도 생김 => Q. 내부적으로 사용하는 API는 분리된 서버(컨퍼런스, analysis 등)로 이해했늗네, public call을 위한 api는 어떤걸 지칭하는 걸까요? 감사합니다.
-
미해결[Rookiss 켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
수강생은 디스코드 강좌도 참여 가능한가요?
궁금합니다!
-
해결됨Real MySQL 시즌 1 - Part 1
Optimistic Lock 경우 이런 케이스일때는 Lost Update 문제 발생 될수 있지 않나요???
이미지가 작게 보인다면https://cdn.inflearn.com/public/files/posts/2722bc2b-12a3-4512-a5b7-35227283e6ec/aaaa.png여기로 부탁드립니다! 우선 좋은 강의 배포해주셔서 정말 감사드립니다 :) 우선 설명 하기전에왼쪽: A 트랜젝션오른쪽: B 트랜젝션 으로 예시 하겠습니다. 순서를 말씀드리자면 A 트랜젝션 "SELECT * FROM account WHERE id=1;" 구문 실행B 트랜젝션 "SELECT * FROM account WHERE id=1;" 구문 실행B 트랜젝션 "UPDATE account SET balance=balance-150, version=2 WHERE id=1 AND version=1;" 업데이트 실행A트랜젝션 "UPDATE account SET balance=balance-200, version=2 WHERE id=1 AND version=1;" 업데이트 실행B트랜젝션 Commit 실행A트랜젝션 Commit 실행영상에서는 B 트랜젝션을 먼저 Update 문 실행하고 그리고 Commit 을 실행 하고나서 A 트랜젝션을 Update을 하였으니 version 정보가 불일치로 정상적으로 A 트랜젝션은 업데이트가 일어나지 않겠지만 제가 업로드한 이미지 순서대로 하게된다면 즉 A, B 트랜젝션이 동시에 Update를 실행하고이후 동시에 A, B 트랜젝션이 동시에 Commit 을 실행하면 balance 가 0 으로 되지 않을까요? (A 트랜젝션이 맨 나중에 Commit을 했으니깐)반대로 B 트랜젝션이 맨 마지막에 Commit을 하게 된다면 balance 값은 50으로 설정되겠지만 정상적으로 업데이트가 된다고 가정시 balance 값은 -150 이 일어나야 하는데요.이런 케이스 때문에 optimistic Lock 보다 Pessimistic Lock 으로 해야 하지 않을까요???? 갑자기 이런 의문이 들어서 질문 드립니다.
-
미해결장래쌤과 함께하는 쉽고 재미있는 SQL 이야기
pdf 문의드립니다
안녕하세요 강사님혹시 강의 pdf는 따로 다운하는 곳이 있을까요?
-
해결됨Real MySQL 시즌 1 - Part 1
1강 CHAR vs VARCHAR 궁금한 부분이 있습니다.
안녕하세요. 우선 좋은 강의 감사드립니다.1강에서 UTF8MB4 셋을 사용하면서 CHAR(10) 을 선언했을 때 기본적으로 할당되는 크기에 대해서 궁금한 부분이 있는데요.UTF8MB4 의 경우 글자당 최대 4 바이트 까지니까, CHAR(10) 이 최초에 10글자 만큼의 공간을 할당받는다고 하면 최대 40바이트가 할당되는 것이 아닌가요??예를 들어 '안녕' 이라는 문자열을 저장한다고 하면 안 (4바이트) 녕(4바이트) 에 문자열 길이를 저장하는 부분 까지 한다고 해도 낭비되는 공간이 있다고 생각했는데, 저장되는 기준이 궁금합니다.
-
해결됨Real MySQL 시즌 1 - Part 2
Real MySQL 시즌 1 - Part 1 or Part2 영상에 나오는 자료 공유 가능하나요?
우선 좋은 강의 기회를 주셔서 너무 감사드립니다 :) 출근길 아니면 퇴근길에 영상에 나오는 자료 보면서 공부 할려고 하는데요. 영상에 나오는 자료 공유 해주시면 정말 감사드리겠습니다! 앞으로 좋은 강의 부탁드리고 다시 한번 좋은 강의 기회 주셔서 정말 감사합니다 :)
-
해결됨Real MySQL 시즌 1 - Part 1
Real MySQL 시즌 1 - Part 1 or Part2 영상에 나오는 자료 공유 가능하나요?
우선 좋은 강의 기회를 주셔서 너무 감사드립니다 :) 출근길 아니면 퇴근길에 영상에 나오는 자료 보면서 공부 할려고 하는데요. 영상에 나오는 자료 공유 해주시면 정말 감사드리겠습니다! 앞으로 좋은 강의 부탁드리고 다시 한번 좋은 강의 기회 주셔서 정말 감사합니다 :)
-
해결됨200억건의 데이터를 MySQL로 마이그레이션 할 때 고려했던 개념과 튜닝 방법
안녕하세요 좋은 강의 감사합니다. 혹시 실습 코드는 따로 제공 안되나요??
강의 영상에 나오는 실습 코드도 공유해주시면 정말 감사드리겠습니다 :)
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
실시간 채팅방에서 GIF uploads 하면 GIF가 바로 화면에 보이지 않고 새로 고침을 해야 보이는데 어떻게 해야 할까요?
실시간 채팅방 강좌 코드를 작성하여 작동 시켜 본 결과 메시지 전송 까지는 잘 되는 것을 확인 하였는데 GIF 업로드 시 다음 그림과 같은 현상이 발생하고 있습니다그림 하단에 표시한 부분 처럼 처음에 GIF 올리기를 하면 그림이 보이지 않다가 새로 고침을 하면 위의 다른 GIF 처럼 잘 보이긴 하는데 무슨 문제 일까요?참고로 관련 코드를 같이 올립니다chat.html {% extends 'layout.html' %} {% block content %} <h1>{{title}}</h1> <a href="/" id="exit-btn">방 나가기</a> <fieldset> <legend>채팅 내용</legend> <div id="chat-list"> {% for chat in chats %} {% if chat.user === user %} <div class="mine" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %}} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% elif chat.user === 'system' %} <div class="system"> <div>{{chat.chat}}</div> </div> {% else %} <div class="other" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% endif %} {% endfor %} </div> </fieldset> <form action="/chat" id="chat-form" method="post" enctype="multipart/form-data"> <label for="gif">GIF 올리기</label> <input type="file" id="gif" name="gif" accept="image/gif"> <input type="text" id="chat" name="chat"> <button type="submit">전송</button> </form> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script> const socket = io.connect('http://localhost:8005/chat', { path: '/socket.io', }); socket.emit('join', new URL(location).pathname.split('/').at(-1)); socket.on('join', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); div.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); }); socket.on('exit', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); div.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); }); socket.on('chat', function (data) { const div = document.createElement('div'); if (data.user === '{{user}}') { div.classList.add('mine'); } else { div.classList.add('other'); } const name = document.createElement('div'); name.textContent = data.user; div.appendChild(name); if (data.chat){ const chat = document.createElement('div'); chat.textContent = data.chat; div.appendChild(chat); } else { const gif = document.createElement('img'); gif.sr = '/gif/' + data.gif; div.appendChild(gif); } div.style.color = data.user; document.querySelector('#chat-list').appendChild(div); }); document.querySelector('#chat-form').addEventListener('submit', function (e) { e.preventDefault(); if (e.target.chat.value) { axios.post('/room/{{room._id}}/chat', { chat: this.chat.value, }) .then( () => { e.target.chat.value = ''; }) .catch( (err) => { console.error(err); }); } }); document.querySelector('#gif').addEventListener('change', function (e) { console.log('******',e.target.files); const formData = new FormData(); formData.append('gif', e.target.files[0]); axios.post('/room/{{room._id}}/gif', formData) .then( () => { e.target.file = null; }) .catch( (err) => { console.error(err); }); }); </script> {% endblock %} routes/index.jsconst express = require('express'); const { renderMain, renderRoom, createRoom, enterRoom, removeRoom, sendChat, sendGif } = require('../controllers'); const multer = require('multer'); const fs = require('fs'); const path = require('path'); const router = express.Router(); router.get('/', renderMain); router.get('/room', renderRoom); router.post('/room', createRoom); router.get('/room/:id', enterRoom); router.delete('/room/:id', removeRoom); router.post('/room/:id/chat', sendChat); try {fs.readdirSync('uploads'); } catch (err) { console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.'); fs.mkdirSync('uploads'); } const upload = multer({ storage: multer.diskStorage({ destination(req, file, done) { done(null, 'uploads/'); }, filename(req, file, done ) { const ext = path.extname(file.originalname); done(null, path.basename(file.originalname, ext) + Date.now() + ext); }, }), limits: {fileSize: 5 * 1024 *1024 }, }) router.post('/room/:id/gif', upload.single('gif'), sendGif); module.exports = router;controllers/index.jsconst Room = require('../schemas/room'); const Chat = require('../schemas/chat'); const { removeRoom: removeRoomService } = require('../services'); exports.renderMain = async ( req, res, next ) => { try{ const rooms = await Room.find({}); res.render('main', {rooms, title: 'GIF 채팅방'}); } catch (error) { console.error(error); next(error); } }; exports.renderRoom = ( req, res, next ) => { res.render('room', { title: 'GIF 채팅방 생성'}); }; exports.createRoom = async ( req, res, next ) => { try{ const newRoom = await Room.create({ title: req.body.title, max: req.body.max, owner: req.session.color, password: req.body.password, //session data 에서 옮 }); const io = req.app.get('io'); io.of('/room').emit('newRoom', newRoom); // 방에 들어가는 부분 if (req.body.password ) { res.redirect(`/room/${newRoom._id}?password=${req.body.password}`); } else { res.redirect(`/room/${newRoom._id}`); } } catch (error) { console.error(error); next(error); } }; exports.enterRoom = async( req, res, next ) => { try{ const room = await Room.findOne({_id: req.params.id}); if (!room){ return res.redirect('/?error=존재하지 않는 방입니다.'); } if (room.password && room.password !== req.query.password ){ return res.redirect('/?error=비밀번호가 틀렸습니다.'); } const io = req.app.get('io'); const { rooms } = io.of('/chat').adapter; if (room.max <= rooms.get(req.params.id)?.size) { return res.redirect('/?error=허용 인원을 초과하였습니다.'); } const chats = await Chat.find({room: room._id }).sort('createdAt'); res.render('chat', { title: 'GIF 채팅방 생성', chats , room, user: req.session.color }); } catch (error) { console.error(error); next(error); } }; exports.removeRoom = async ( req, res, next ) => { try { await removeRoomService(req.params.id ); res.send('ok'); setTimeout(() => { req.app.get('io').of('/room').emit('removeRoom', req.params.id); }, 2000) } catch (error) { console.error(error); next(error); } }; exports.sendChat = async (req, res, next ) =>{ try { const chat = await Chat.create({ room: req.params.id, user: req.session.color, chat: req.body.chat, }); req.app.get('io').of('/chat').to(req.params.id).emit('chat', chat); res.send('ok'); } catch( error ){ console.error(error); next(error); } } exports.sendGif = async (req, res, next ) => { try { const chat = await Chat.create({ room : req.params.id, user: req.session.color, gif: req.file.filename, }) setTimeout(() => { req.app.get('io').of('/chat').to(req.params.id).emit('chat',chat); }, 1000); res.send('ok'); } catch (error) { console.error(error); next(error); } } [제로초 강좌 질문 필독 사항입니다]질문에는 여러분에게 도움이 되는 질문과 도움이 되지 않는 질문이 있습니다.도움이 되는 질문을 하는 방법을 알려드립니다.https://www.youtube.com/watch?v=PUKOWrOuC0c0. 숫자 0부터 시작한 이유는 1보다 더 중요한 것이기 때문입니다. 에러가 났을 때 해결을 하는 게 중요한 게 아닙니다. 왜 여러분은 해결을 못 하고 저는 해결을 하는지, 어디서 힌트를 얻은 것이고 어떻게 해결한 건지 그걸 알아가셔야 합니다. 그렇지 못한 질문은 무의미한 질문입니다.1. 에러 메시지를 올리기 전에 반드시 스스로 번역을 해야 합니다. 번역기 요즘 잘 되어 있습니다. 에러 메시지가 에러 해결 단서의 90%를 차지합니다. 한글로 번역만 해도 대부분 풀립니다. 그냥 에러메시지를 올리고(심지어 안 올리는 분도 있습니다. 저는 독심술사가 아닙니다) 해결해달라고 하시면 아무런 도움이 안 됩니다.2. 에러 메시지를 잘라서 올리지 않아야 합니다. 입문자일수록 에러메시지에서 어떤 부분이 가장 중요한 부분인지 모르실 겁니다. 그러니 통째로 올리셔야 합니다.3. 코드도 같이 올려주세요. 다만 코드 전체를 다 올리거나, 깃헙 주소만 띡 던지지는 마세요. 여러분이 "가장" 의심스럽다고 생각하는 코드를 올려주세요.4. 이 강좌를 바탕으로 여러분이 응용을 해보다가 막히는 부분, 여러 개의 선택지 중에서 조언이 필요한 부분, 제 경험이 궁금한 부분에 대한 질문은 대환영입니다. 다만 여러분의 회사 일은 질문하지 마세요.5. 강좌 하나 끝날 때마다 남의 질문들을 읽어보세요. 여러분이 곧 만나게 될 에러들입니다.6. 위에 적은 내용을 명심하지 않으시면 백날 강좌를 봐도(제 강좌가 아니더라도) 실력이 늘지 않고 그냥 코딩쇼 관람 및 한컴타자연습을 한 셈이 될 겁니다.
-
해결됨인프라공방 - 그럴듯한 서비스 만들기
포트, http 체크 질문
어떤 부분이 port체크이고 어떤 부분이 http 체크를 한건가요?ping 체크는 명확이 알겠는데 2개가 좀 헷갈리네요
-
미해결따라하며 배우는 MySQL on Docker
Proxy SQL에 대한 질문입니다.
안녕하세요, 특정 테이블의 데이터를 Master에서 업데이트를 하고 바로 조회를 한다면, 아직 복제되지 않은 Slave 테이블에서 데이터가 조회가 된다면, 업데이트 되지 않는 것처럼 보일 수 있을 것 같아서, 이런 경우에는 어떻게 진행이 되야하는지 궁금합니다.바로바로 결과를 확인해야하는 경우는 Master에서만 Read되도록 설정이 가능한가요?
-
해결됨장래쌤과 함께하는 쉽고 재미있는 SQL 이야기
regexp like 에 특정 특수기호 포함
안녕하세요 강사님! 컬럼에 특수기호 중 + (플러스) 문자가 포함된 값을 찾으려고하는데요 정규식에 해당 기호를 쓰면 오류가 발생하는데 어떻게 해당 문자만 골라 뽑을 수 있을지 질문드립니다 .