Mysql主从复制
掘金
MySQL 主从复制:原理与实战 一、理论 什么是主从复制 主从复制是一种数据库复制技术:把主库(Master / Source)的数据变更,实时或准实时地复制到一个或多个从库(Slave / Rep
Score: 57.28Confidence: 54%
View offerLoading the catalog…
THE AI OPPORTUNITY INDEX
Find your next AI tool. Explore free access, trials, and credits — all in one place.
掘金
MySQL 主从复制:原理与实战 一、理论 什么是主从复制 主从复制是一种数据库复制技术:把主库(Master / Source)的数据变更,实时或准实时地复制到一个或多个从库(Slave / Rep
Score: 57.28Confidence: 54%
View offer掘金
上一篇我们用十行代码,把全中国 39 个机场的实时天气画上了地图。地图上的每个圆点背后,都是一条这种模样的电码: 这一篇不写代码。我们蹲到电码的身后去,看这套系统本身。
Score: 56.8Confidence: 54%
View offerInfoQ - 促进软件开发领域知识与创新的传播
点击查看原文>
Score: 55.67Confidence: 54%
View offervelog
IT 인프라를 운영하다 보면 DR 플랜이 "있기는 한데 실제로 돌아갈지는 모르겠다"는 상태로 방치되는 경우를 종종 본다. 1년에 한 번, 주말 밤을 새워가며 하는 페일오버 테스트가 전부인 팀도 있고, 그마저도 테스트 중에 실제 서비스가 영향받아 다들 쉬쉬하는 경우도 있다. 현실에서 서비스 중단이 1시간 이어질 때 직접 손실만 억 단위를 넘는 기업이 생각보다 많다. 거기에 브랜드 이미지 손상과 고객 이탈까지 더하면 숫자는 더 커진다. 문제는 기술이 없어서가 아니다. 대부분 위협 환경이 바뀌었는데 DR 전략이 따라가지 못한 것이다. 이 글에서는 Nutanix 플랫폼 기반의 현대적인 DR 체계를 어떻게 구성할 수 있는지, 실무 관점에서 짚어보려 한다. 1. 지금의 위협은 예전과 다르다 예전 DR의 주적은 명확했다. 자연재해, 화재, 하드웨어 고장. "데이터를 멀리 있는 백업 사이트에 복사해두면 된다"는 논리가 통하던 시절이다. 지금은 상황이 다르다. 하드웨어 조달 리스크 : CPU와 메모리 납기가 12개월을 넘는 상황에서, 두 번째 DR 사이트를 물리 장비로 온전히 갖추기가 쉽지 않다. 온프레미스 하드웨어 가격은 2026년 기준으로 40%까지 오를 수 있다는 분석도 나온다. 이런 상황에서 모든 DR 인프라를 온프레미스 장비에만 의존하는 건 리스크가 크다. 랜섬웨어 : 최근 공격자들은 파일을 암호화하기 전에 백업 서버를 먼저 찾아서 지운다. "백업 있으면 괜찮다"는 논리가 더 이상 통하지 않는다. 규제 강화 : 금융권과 헬스케어는 물론이고, 일반 기업도 SOC2나 GDPR 같은 데이터 거버넌스 요구가 점점 구체화되고 있다. "복구할 수 있다"는 말 대신 "테스트 기록과 감사 추적 문서"를 요구하는 시대다. 하이브리드의 복잡성 : 온프레미스에서 시작해 하이브리드 클라우드로 확장하면서, 오히려 어느 데이터가 어디 있고 어떻게 보호되는지 파악하기가 더 어려워진 팀이 많다. 이런 환경에서 기존의 수동 백업+페일오버 방식은 근본적인 한계에 부딪혔다. 2. 수동 보호 도메인이 왜 문제인가 Nutanix를 써온 팀이라면 "보호 도메인(Protection Domain)"이 익숙할 거다. Prism Element에서 VM들을 일일이 골라 일관성 그룹에 넣고, 복제 일정을 설정하는 방식이다. 규모가 작고 환경이 고정적이라면 나름 직관적이다. 그런데 VM이 수백, 수천 개로 늘고, 개발팀이 하루에도 몇 개씩 새 VM을 만들어내는 환경에서는 보호 누락 문제가 반드시 생긴다. 개발팀이 새 데이터베이스 서버를 배포했는데, 인프라 팀이 보호 도메인에 추가하는 것을 빠뜨리는 상황이다. 이게 쌓이다가 실제 재해가 터지면, 복구해 보니 중요한 VM 몇 개가 통째로 날아간 상태가 된다. "그런 실수를 왜 해?"라고 할 수도 있지만, 수동으로 관리해야 하는 VM이 수천 개라면 하나쯤 빠지는 건 구조적으로 막기 어렵다. 3. 카테고리 기반 정책: "새 VM 만들면 자동으로 보호된다" Nutanix의 현대적 DR 접근법은 이 문제를 구조적으로 해결한다. Prism Central 기반의 카테고리(Category) 태그 시스템 을 사용하면, VM을 일일이 보호 도메인에 등록하는 작업 자체가 없어진다. 방식은 간단하다. 관리자는 Production , Database , Tier-1 같은 비즈니스 분류에 맞는 카테고리를 만들어 두고 각 카테고리에 RPO, RTO 등 보호 정책을 미리 연결한다 이후 개발팀이 VM을 만들 때 카테고리 태그만 붙이면, 나머지는 자동으로 처리된다 새 VM이 생성되는 즉시 정책이 자동으로 상속되기 때문에, 누락이 구조적으로 불가능해진다. "만들었으면 이미 보호된다"는 상태가 되는 것이다. 항목 보호 도메인 (기존) 카테고리 기반 (현대적) 관리 콘솔 Prism Element (클러스터별) Prism Central (중앙 통합) 보호 단위 수동 VM 선택 카테고리 태그 기반 자동 누락 리스크 수동 추가 누락 가능 구조적으로 누락 차단 운영 부담 VM 증가할수록 비례 증가 태그 정책만 관리하면 됨 4. 복구 계획(Recovery Plans): 데이터만 있어도 소용없다 "백업은 잘 돼 있어요"라는 팀에게 꼭 물어보는 게 있다. "서비스를 올바른 순서로 복구하는 계획은 있나요?" 데이터를 복구 사이트로 잘 복제해 두었다 해도, 순서를 틀리면 다 소용없다. DNS가 안 뜬 상태에서 웹 서버를 먼저 올리거나, 데이터베이스보다 애플리케이션이 먼저 부팅되면 시스템 전체가 오류를 뱉는다. Nutanix의 Recovery Plans 는 이 복구 순서 문제를 자동화한다. 부팅 순서 제어 (Stage Management) 실제 엔터프라이즈 환경 기준으로 보통 이런 순서로 구성한다. Stage 0 : Active Directory, DNS, DHCP 등 기반 인프라부터 올린다. 이게 완전히 뜨기 전까지 나머지 VM 부팅은 차단된다. Stage 1 : DB 서버, 모니터링, 인증 서버. Stage 0 완료 후 의도적인 딜레이를 주는 것이 중요하다. Stage 2 이상 : 미들웨어, 웹 서버, 실제 서비스 레이어. 이 순서를 정책으로 정의해두면, 재해 상황에서 "뭐부터 올려야 하지?"를 기억에 의존할 필요가 없다. 수동 검증 수십 단계가 클릭 하나로 처리된다. 네트워크 매핑과 IP 문제: 여기서 많이 막힌다 Recovery Plan 구성할 때 의외로 자주 놓치는 부분이 있다. 복구 계획이 VM의 네트워크 인터페이스를 DR 사이트의 VLAN에 연결해주는 것은 해준다. 그런데 VM 내부 OS에 정적으로 박혀있는 IP 주소는 기본적으로 건드리지 않는다. DR 사이트 서브넷 대역이 프라이머리 사이트와 다른 경우, VM은 올라왔는데 네트워크를 못 찾는 상황이 된다. 이를 해결하려면 두 가지가 필요하다. 보호 대상 VM 전체에 Nutanix Guest Tools(NGT) 설치. 이게 없으면 게스트 OS 제어가 안 된다. Recovery Plan에 In-Guest 스크립트 를 구성해서, 복구 후 자동으로 IP 변경, DNS 업데이트, 로드밸런서 재등록이 실행되도록 한다. 사전에 이 구성을 빠뜨리면 복구 완료 직전에 네트워크 문제로 발이 묶이는 상황이 생긴다. 동기식과 비동기식 혼합은 안 된다 설계 시 기억해둘 제약이 하나 더 있다. 단일 Recovery Plan 안에서 동기식(Sync)과 비동기식(Async/Near-Sync) 복제 방식을 혼합해서 사용할 수 없다. 둘의 복구 메커니즘이 근본적으로 달라서 충돌이 생긴다. 워크로드 특성에 맞게 복구 계획을 분리해서 구성해야 한다. 5. NCI 7.5: 규모와 유연성의 확장 NCI 7.5에서 주목할 변화는 단일 보호 정책 내에서 최대 4개 사이트로 데이터를 분산 복제 할 수 있게 됐다는 점이다. RPO 요구사항에 따라 사이트별로 다른 복제 방식을 조합할 수 있다. Metro Availability (RPO 0) : 근거리 동기식 복제. 금융권 핵심 데이터에 적합하다. 사이트 간 RTT 5ms 미만 유지가 필수이고, 스플릿 브레인 방지를 위해 Witness VM을 제3의 사이트에 따로 배치해야 한다. NearSync (RPO 20초 ~ 15분) : 거리가 멀어 Metro를 쓸 수 없는 경우에 쓴다. 대역폭 부족 시 자동으로 비동기로 전환했다가, 상황이 나아지면 다시 NearSync로 복귀하는 유연함이 장점이다. MST (Multicloud Snapshot Technology) : 퍼블릭 클라우드 오브젝트 스토리지에 장기 보관용으로 보내는 방식이다. 이 세 가지를 조합하면 단일 정책 아래에서 이런 구성이 가능하다. 사이트 A ↔ 사이트 B: Metro Sync (로컬 HA) 사이트 A → 사이트 C: NearSync (지역 재해 대비) 사이트 A → 퍼블릭 클라우드: MST (장기 보관 및 규정 준수) 그 외에 주목할 변화들: VM 수용 규모가 단일 환경에서 최대 10,000개까지 확대됐다. Dual Prism Central 지원 : Prism Central 자체가 장애나도 다른 쪽 PC가 오케스트레이션을 이어받는다. Pure Storage 연동 : 기존 Pure Storage SAN을 쓰는 AHV 환경에 Prism Central 기반 비동기 복제를 얹을 수 있다. VMware에서 Nutanix AHV로 전환하려는데 기존 스토리지 자산이 걱정됐던 팀들에게 현실적인 선택지가 생긴 셈이다. 6. 테스트를 안 하면 계획이 아니다 많은 팀이 DR 테스트를 꺼리는 이유는 단순하다. 테스트 자체가 운영 환경에 영향을 주기 때문이다. 실제로 예전 방식에서는 DR 테스트 도중 실수로 실제 서비스 중단이 생기는 경우도 있었다. 그러다 보니 대부분 팀에서 DR 테스트는 1년에 한두 번, 제한된 범위에서만 형식적으로 하는 수준이 됐다. Nutanix의 Test Bubble 기능은 이 문제를 다르게 풀었다. 테스트 실행 시 라이브 데이터가 아닌 최신 복제 스냅샷을 가져와서, 완전히 격리된 Layer 2 가상 네트워크에서 VM들을 올린다. 이 샌드박스는 물리 네트워크와 라우팅이 원천적으로 단절되어 있어서, 테스트 VM들이 프로덕션 VM과 같은 IP로 뜨더라도 충돌이 없다. 결과적으로 업무 시간에도 테스트가 가능하고, 서비스 영향 없이 실제 부팅 순서와 In-Guest 스크립트 동작을 전부 확인할 수 있다. 테스트 결과는 자동으로 감사 추적 보고서로 생성된다. 규제 요구사항 대응을 위해 별도로 문서를 만들 필요가 없어진다. 기술 말고 '사람 테스트'도 해야 한다 DR 테스트에서 자주 빠뜨리는 게 있다. 기술적인 복구보다 "사람이 실제로 원격에서 복구를 실행할 수 있는가"다. 재해 발생 시 인프라 팀이 VPN을 통해 복구 도구에 접근할 수 있는가? 런북과 비밀번호 관리 도구가 장애가 난 프라이머리 사이트 서버에만 저장되어 있지는 않은가? 내부 이메일과 슬랙이 다운됐을 때 팀 간 소통할 외부 채널이 있는가? DR 사이트 IP에서도 외부 서비스 연동이 정상 동작하도록 화이트리스트 설정이 되어 있는가? 이런 인적, 운영적 측면까지 포함한 "버그 아웃(Bug Out) 시나리오"를 정기적으로 훈련하는 팀이 실제 재해에서도 빠르게 대응한다. 7. NC2로 TCO 절감: Pilot Light 전략 기존 DR 구성에서 가장 큰 비용 문제는 DR 사이트의 하드웨어가 평소엔 거의 안 쓰인다는 거다. 재해가 언제 올지 모르니 항상 켜두어야 하고, 그 유지비가 매달 나간다. Nutanix Cloud Clusters(NC2) + Pilot Light 전략 은 이 문제를 다르게 접근한다. 평소엔 VM 데이터를 AWS S3 같은 저렴한 오브젝트 스토리지에 지속 복제해 둔다. 비용의 대부분을 차지하는 컴퓨팅 노드는 Hibernate 상태로 꺼둔다. 이때는 컴퓨팅 비용이 발생하지 않는다. 실제 재해 시에만 Resume 버튼으로 클러스터를 깨워 서비스를 올린다. 컴퓨팅 비용이 실제로 필요한 순간에만 발생하기 때문에 전체 TCO가 크게 줄어든다. Nutanix 측에서는 최대 53%까지 절감 가능하다고 밝힌다. 온프레미스 워크로드를 그대로 클라우드로 확장하는 방식이라 리팩토링이 필요 없다는 것도 장점이다. 기존에 쓰던 툴과 프로세스를 그대로 쓸 수 있다. Zero Compute DR과 MST MST 기능은 한 단계 더 나아간다. 라이브 클러스터를 기동하지 않고도 온프레미스 스냅샷을 퍼블릭 클라우드 오브젝트 스토리지로 직접 전송한다. NCI 7.5 기준으로 최대 1PB 규모의 데이터와 5,000개 엔티티까지 지원한다. 클라우드 컴퓨팅 노드를 하나도 쓰지 않으면서도 대용량 데이터를 클라우드에 보관하는 'Zero Compute DR'이 가능해진다. 하드웨어 조달이 막히는 상황에서도 데이터 보호를 유지하는 현실적인 방법이다. VMware에서 Nutanix로 전환하는 팀이라면 Broadcom의 VMware 인수 이후 라이선스 비용 이슈로 Nutanix 전환을 검토하는 팀들이 늘었다. 이때 주의할 게 있다. 마이그레이션 자체가 또 다른 서비스 중단의 원인이 되면 안 된다. Nutanix Move 툴을 쓰면 기존 VMware VM을 리팩토링 없이 AHV로 이전할 수 있다. HD한국조선해양이 이 방식으로 전환해 TCO 30%를 절감했고, 현대엔지니어링은 가상화 구축 기간을 3개월에서 1개월 이내로 줄인 사례가 있다. 8. 보안: 복구 사이트도 Zero Trust가 필요하다 DR 사이트를 잘 구성해도, 보안 설정이 프라이머리보다 느슨하면 문제가 생긴다. 랜섬웨어가 메인 사이트를 감염시킨 후 복구 사이트로 그대로 옮겨타는 시나리오가 실제로 있다. 네트워크 보안 정책 복제 NCI 7.5의 VPC Policy Sync 기능은 프라이머리 사이트에 설정된 Flow Network Security 정책을 DR 사이트에 자동으로 동기화한다. 마이크로 세그멘테이션 정책, VLAN 규칙, VPC 구성 등 최대 1,000개까지 복제된다. VM이 DR 사이트에서 뜨는 순간부터 프라이머리와 동일한 Zero Trust 정책이 적용된다. 복구 직후 보안 구성을 수동으로 다시 맞춰야 하는 공백이 없어진다. 랜섬웨어 대응: 불변 스토리지와 클린룸 복구 랜섬웨어 방어에서 핵심은 두 가지다. 첫째, 백업 데이터를 건드릴 수 없게 만들기. Nutanix Objects의 WORM(Write Once Read Many) 정책으로 백업 데이터에 불변성을 적용한다. 관리자 계정이 탈취되더라도 백업을 삭제하거나 수정할 수 없다. 둘째, 복구 전에 감염 여부 확인하기. 랜섬웨어 감염이 의심될 때, 오염된 스냅샷을 바로 프로덕션으로 올리는 건 위험하다. 외부 네트워크와 완전히 격리된 클린룸 환경에 먼저 복구해서 바이러스 스캔 및 무결성 검증을 마친 후, 이상 없을 때만 실제 서비스로 올리는 방식이다. Nutanix Data Lens(NDL)의 랜섬웨어 탐지 기능은 비정상적인 암호화 시도를 감지하면 자동으로 격리 조치를 취한다. HYCU 연동 서드파티 솔루션인 HYCU는 Nutanix Prism과 AHV 가상화 레이어, Nutanix Database Service, NC2 환경까지 네이티브 수준으로 통합된다. 에이전트 없이 VM과 애플리케이션 컨텍스트를 인식하며 백업을 처리하고, RBAC와 MFA 기반의 접근 제어를 제공한다. AI 워크로드와 컨테이너도 보호 대상이다 VM만 보호하면 끝나지 않는다. 수개월 학습시킨 AI 모델 데이터가 날아가는 것도 재해다. Nutanix는 Cisco HCI C240 M7에 NVIDIA L40S GPU를 결합한 AI 워크로드 보호 아키텍처를 제공하고, Enterprise AI Gateway 2.6이 모델 데이터 거버넌스를 담당한다. 쿠버네티스 환경이라면 NKP(Nutanix Kubernetes Platform)와 연동된 NDK가 컨테이너 영구 볼륨까지 VM 수준의 데이터 보호를 확장한다. NKP Starter 에디션은 NCI Pro/Ultimate 구독 고객에게 추가 비용 없이 제공된다. 정리: DR 전략 점검을 위한 세 가지 기준 첫째, 보호 누락이 구조적으로 불가능한 환경인가. VM이 생성되는 즉시 보호가 시작되어야 한다. 수동 등록에 의존하는 구조는 규모가 커질수록 위험해진다. 카테고리 기반 정책 상속이 이 문제를 해결한다. 둘째, 운영 영향 없이 상시 테스트가 가능한가. 테스트하기 어려운 DR 플랜은 실제로 안 된다고 봐야 한다. Test Bubble처럼 서비스 중단 없이 언제든 테스트하고 감사 증적도 남길 수 있는 환경이 필요하다. 셋째, 비용 구조가 지속 가능한가. 아무리 좋은 DR 구성도 유지 비용이 너무 크면 결국 흐지부지된다. NC2 Pilot Light 모델처럼 평소엔 스토리지 비용만, 필요할 때만 컴퓨팅을 쓰는 방식이 현실적인 대안이다. 지금 운영 중인 인프라의 복구 계획이 어느 수준에 있는지 한번 점검해보자. 특히 마지막으로 테스트한 날짜와 그때 IP 매핑이 현재 환경과 일치하는지부터 확인하는 것을 권한다.
Score: 54.4Confidence: 49%
View offervelog
HN圣淘沙实体博彩平台 不限IP注册 线上线下同步 正规,公平,公正,公开,三合一网投平台 主营:百家乐等多种电子游戏 任你挑选。 圣淘沙娱乐 注册官网: 232592.com 华纳|圣淘沙 注册官网: 232592.com PG电子游戏: 232592.com 注册官网: 232592.com 上下分业务办理客服: @sts9888 上下分业务办理客服: 8963209 充值方式:KBZ,微信,支付宝,银行卡,网银,USDT。充值联系APP上的在线客服办理也可以。
Score: 54.4Confidence: 49%
View offervelog
Buy Google Ads Accounts Embark on a journey to amplify your online presence and skyrocket your business growth with the potent tool of Google Ads. In today's digital landscape, standing out amidst the vast sea of competitors is a challenge many businesses face. This article delves into the strategic approach of buying Google Ads accounts, offering insights, guidance, and success stories. Discover how to navigate the world of digital advertising with finesse and precision. Uncover the secrets to unlocking the full potential of Google Ads accounts, learn where to find reliable resources, and unleash a wave of success that propels your business to new heights. Get ready to revolutionize your marketing strategy and witness firsthand the remarkable impact that targeted online advertising can have on your brand. If you want to more information just contact now. 24 Hours Reply/Contact ✅E-mail: smmseoit24h@gmail.com ✅Telegram: @smmseoit ✅Skype: SMM SEO IT ✅WhatsApp: +1(226) 785-3444 ✅Website: https://smmseoit.com/product/buy-google-ads-accounts/ The Power of Google Ads Google Ads, formerly known as Google AdWords, is a powerful online advertising platform that allows businesses to reach their target audience with precision and efficiency. With over 3.5 billion searches conducted on Google every day, Google Ads provides unparalleled access to potential customers at the exact moment they are searching for products or services. This advertising platform offers a variety of ad formats, including text ads, display ads, and video ads, allowing businesses to showcase their offerings in a visually appealing and engaging manner. By leveraging the power of Google's vast network and sophisticated targeting options, advertisers can connect with users across different devices and channels, driving brand awareness, website traffic, and conversions. In today's digital age, harnessing the power of Google Ads is essential for businesses looking to stay competitive and maximize their online presence. Why Buy Google Ads Accounts? Investing in pre-existing Google Ads accounts can provide a shortcut to success in the fiercely competitive digital advertising landscape. By purchasing established accounts, businesses gain access to valuable historical data, higher quality scores, and a ready-to-use platform that can jumpstart their marketing efforts. This strategic move allows companies to bypass the initial learning curve and immediately leverage the proven performance of these accounts. Where to Find Reliable Google Ads Accounts When it comes to sourcing reliable Google Ads accounts, quality is paramount. Look for reputable online platforms that specialize in providing verified and trustworthy accounts. Consider seeking recommendations from industry experts or joining forums where users share their experiences and recommendations. Another avenue to explore is connecting with established digital marketing agencies that offer Google Ads account services. These agencies often have a track record of delivering results and can provide you with accounts that meet your specific needs and budget. Remember, the key is to choose providers who prioritize transparency and customer satisfaction. Factors to Consider Before Buying When considering purchasing Google Ads accounts, several crucial factors must be taken into account to ensure a successful investment. Firstly, assess the reputation of the seller. Look for reviews and testimonials to gauge their credibility and reliability. Secondly, consider the age and activity of the accounts. Older, established accounts tend to perform better than newly created ones. Additionally, analyze the niche relevancy of the accounts. Ensure that they align with your target market to maximize effectiveness. Lastly, review the pricing structure and compare it with market standards. Remember, quality often comes at a price but aim for a balance between cost and value for optimal results. Step-By-Step Guide to Purchasing Google Ads Accounts When embarking on the journey of buying Google Ads accounts, it's crucial to conduct thorough research. Begin by identifying reputable providers through online reviews and testimonials. Compare pricing packages and features offered by different sellers to ensure you are getting the best value for your investment. Next, reach out to potential sellers and ask detailed questions about the accounts they are offering. Inquire about account history, performance metrics, and any additional services included. Once you have selected a trustworthy provider, negotiate terms and finalize the transaction securely. Remember, transparency and communication are key in this process to guarantee a successful purchase that aligns with your marketing goals. Tips for Maximizing ROI When it comes to maximizing ROI on your Google Ads accounts, strategic planning is key. Start by analyzing your target audience and crafting compelling ad copy that speaks directly to their needs and desires. Utilize ad extensions to provide additional information and enhance visibility. Continuously monitor your campaigns and adjust bids based on performance data to ensure you are getting the most out of your investment. Furthermore, leverage the power of remarketing to re-engage with users who have shown interest in your products or services but haven't converted yet. A/B test different ad creatives, landing pages, and targeting options to identify what resonates best with your audience. By staying agile and proactive in optimizing your Google Ads accounts, you can unlock new opportunities for growth and success. Success Stories of Buying Google Ads Accounts Embarking on the journey of purchasing Google Ads accounts has led numerous businesses to remarkable success stories. From small startups to established corporations, the decision to buy Google Ads accounts has proven to be a game-changer in their marketing strategies. These success stories illustrate how investing in reliable Google Ads accounts can significantly boost brand visibility and drive conversions. One notable success story involves a local bakery that saw a substantial increase in online orders after purchasing a Google Ads account with targeted keywords and ad placements. The bakery experienced a surge in website traffic and foot traffic to their physical store, showcasing the tangible impact of strategic ad campaigns. Such success stories inspire other businesses to explore the potential benefits of buying Google Ads accounts as a catalyst for growth. Common Mistakes to Avoid One common mistake to avoid when buying Google Ads accounts is overlooking the account history. It's crucial to thoroughly review the account's performance data, including click-through rates, conversion rates, and overall effectiveness. Ignoring this information could lead to purchasing an underperforming account, resulting in wasted resources and missed opportunities. Another key mistake is neglecting to set clear goals and strategies before buying Google Ads accounts. Without a well-defined plan in place, you risk aimlessly running campaigns that don't align with your business objectives. To avoid this pitfall, take the time to establish specific goals, target audiences, and budget allocations to maximize the impact of your Google Ads investment. Future Trends in Google Ads As technology continues to advance at a rapid pace, the future of Google Ads is poised for exciting developments. One prominent trend on the horizon is the increasing integration of artificial intelligence and machine learning into ad campaigns. These innovations will enable advertisers to create more personalized and targeted ads, leading to higher engagement and conversion rates. Additionally, we can expect to see a rise in voice search optimization within Google Ads. With the growing popularity of voice-activated devices like smart speakers and virtual assistants, advertisers will need to adapt their strategies to cater to this emerging trend. By optimizing ads for voice search queries, businesses can stay ahead of the curve and reach customers in new, innovative ways. Conclusion As we come to the end of this exploration into the world of purchasing Google Ads accounts, it is evident that with the right strategy and approach, businesses can truly unlock immense potential for growth and success. Embracing the opportunities presented by buying Google Ads accounts not only opens doors to a wider audience but also allows for targeted marketing efforts that can yield remarkable results. In a digital landscape that is constantly evolving, staying ahead of the curve is key. By understanding the intricacies of Google Ads and leveraging the benefits of purchased accounts ethically and strategically, businesses can navigate the competitive advertising space with confidence and innovation. Remember, success in online advertising is not just about investment but also about creativity, adaptability, and a willingness to explore new avenues.
velog
Thread 상태 : 생성, 준비, 실행, 대기, 종료 NEW ** 스레드 객체 생성, 실행 시작 X start() 로 스레드 시작되어 RUNNABLE 상태로 넘어감 * RUNNABLE * 실행 준비 완료 상태, CPU 스케줄링 기다리는 중 **RUNNING 스케줄러가 스레드를 골라 CPU를 할당하면 실제로 실행 yield() 는 실행 가능한 다른 스레드에게 실행을 양보할 수 있음 WAITING 실행 중인 스레드는 항상 CPU를 사용하는 것은 아니고, 실행 상태에서 빠져나와 대기 상태가 될 수 있음 TIMED_WAITING : 시간이 정해져 있는 대기 상태 sleep() 일정 시간 동안 기다림 WAITING : 언제 끝날지 알 수 없는 대기 상태 wait() 기다림 notify() 기다리는 스레드 하나를 깨움 notifyAll() 기다리는 스레드들을 깨움 join() 다른 스레드가 끝나는 것을 기다림 BLOCKED 내가 필요한 lock을 다른 스레드가 사용하고 있을 때, 다른 스레드가 lock을 놓을 때까지 기다림 → lock은 무엇인가... 멀티스레드에서 여러 스레드가 데이터를 동시에 건드리지 못하게 막는 잠금장치 / synchronized 영역에 들어가려고 하면, lock 필요 TERMINATED 실행 중인 run()의 코드가 전부 끝나서 스레드의 실행이 종료됨 ❋ 한 번 종료된 스레드 객체는 start() 를 통해 다시 시작할 수 없다! 다시 시작하려면 새로운 객체를 만들어야 함... Thread 동기화 (Synchronization) 멀티스레드 작성 시 주의할 것 다수의 스레드가 공유 데이터에 동시에 접근하는 경우 스레드 동기화 : 공유 데이터의 동시 접근 문제 해결 공유 데이터에 동시에 접근하는 다수의 스레드가 공유 데이터를 배타적으로 접근하기 위해서 상호 협력한다 - 공유 데이터를 접근하는 모든 스레드를 한 줄로 세우고, 한 스레드가 공유 데이터에 대한 작업을 끝낼 때까지 다른 스레드가 대기 하도록 한다! 자바에서 스레드 동기화를 위한 방법 synchronized 동기화 블록 지정 → 한 스레드가 독점 실행해야 하는 임계 영역을 지정하고, 한 번에 하나의 스레드만 공유 데이터에 접근할 수 있도록 제어한다 wait()-notify() 메소드로 스레드 실행 순서 제어 Lab #5 MyBank 출력문을 제거하고 아무리 돌려봐도 오류발생! 메시지가 안 떠서... sleep time도 2로, 스레드 개수도 5개로, 반복 횟수도 10000번으로 바꾸었더니 드디어 오류발생! 메시지가 떴다 ᄒ... 출력문 추가 후 오류발생 없이 잘 돌아가는 것처럼 보이는 것도 확인할 수 있었다 콘솔 출력이 내부적으로 synchronization 되어 있기 때문에 실행 흐름을 정렬할 수도 있다, (스레드 실행 타이밍 자체가 달라짐) 하지만 여전히 코드가 synchronized 되어있는 것은 아니기 때문에 race-condition 이 발생할 수 있는 환경에 노출되어 있다 ❋ race-condition : 여러 스레드가 공유 데이터에 동시에 접근할 때 누가 먼저 실행되느냐에 따라 결과가 달라지는 현상 이게 어떤 식의 문제를 발생시키냐면, balance가 0인 상태를 읽어서 스레드1에서도 입금을 하고 스레드2에서도 입금을 했다면 balance는 20000이 되어야 하는데 각각 balance를 10000으로 내보내서 balance가 10000이 될 수도 있는... 상황이다 이런 식으로 synchronized 를 붙여줌으로써 방금 말한 문제를 해결할 수 있다 이러면 한 순간에 하나의 스레드만 허용된다 ❋ 그리구 synchronized의 위치는 접근제어자와 리턴 형식 사이임을 기억하도록 하자^..^;;!! Lab #6 FamilyAccount BankAccountV1은 balance라는 데이터를 공유하고 있음 deposit(), withdraw() 둘다 balance를 수정하는 기능을 가지고 있음 따라서 동시에 접근하지 못하도록 synchronized를 사용함 ⇒ 공유 자원 데이터 보호 위에서 말했던 BLOCKED 상태와 연관지을 수 있음 이 버전은 synchronized 사용에서 나아가서, wait()/notifyAll() 을 사용해서 입출금이 번갈아 실행되도록 만들고 있다 empty = 입출금 순서를 제어 하는 flag로 사용 → deposit : !empty가 true이면 기다리고, empty이면 돈을 넣고 empty를 false로 바꾼다 → withdraw : empty가 true이면 기다리고, !empty이면 돈을 빼고 empty를 true로 바꾼다 그러면 동작할 때마다 empty의 true/false가 달라지니까 입금 뒤에는 출금이, 출금 뒤에는 입금이 나올 수밖에! Lab #7 아기돼지삼형제 join()을 통해 호출한 곳(Main)에서 해당 스레드(pig1, pig2, pig3)가 완료될 때까지 기다리게 한다 그래서 모두 다 도착하고 엄마 돼지가 문을 열 수 있는 것이다 또한 여기서도 역시 start()를 pig1, pig2, pig3 순서대로 썼어도 실제로 실행되는 것은 정해지지 않는다는 걸 다시 한 번 확인할 수 있다 Math.random() : 0 이상 1 미만의 실수를 랜덤으로 만드는 것 ❋ try-catch문은 왜 있는 것? sleep()과 join()은 스레드를 기다리게 만드는 메소드이고, 기다리는 도중 interrupt()를 받을 수 있어서 InterruptedException을 처리해야 한다!
velog
3개월차 교육을 시작한 지도 벌써 3개월이 지났다. 이번 달에는 크게 CI/CD 와 Multi-Agent System 에 대해서 배웠다. CI/CD에서는 Docker, GitHub Actions, AWS를 이용해 코드가 실제 환경까지 배포되는 과정과 반복 작업을 자동화하는 방법을 배웠고, Multi-Agent에서는 하나의 목표를 여러 Task로 나누고 여러 Agent가 역할을 나눠 작업하도록 만드는 방법을 배웠다. 처음에는 두 주제가 크게 관련 없어 보였다. 하지만 한 달 동안 배운 내용을 다시 정리해보니 결국 둘 다 작업을 더 잘하기 위해 필요한 구조를 명시적으로 만드는 방법 이라는 공통점이 있었다. 사람이 일을 하든, 소프트웨어가 실행하든, AI가 작업하든 결국 비슷한 질문이 필요하다. 왜 하는가? ↓ 무엇을 해야 하는가? ↓ 어떻게 나눌 것인가? ↓ 누가 할 것인가? ↓ 어떤 순서와 관계로 실행할 것인가? ↓ 무엇을 주고받을 것인가? ↓ 현재 어디까지 진행됐는가? ↓ 실행 ↓ 잘했는지 확인 ↓ 다음 작업에 반영 이번 달에는 이런 질문들이 실제 기술에서는 어떤 개념과 구조로 표현되는지를 많이 확인했던 것 같다. 1. 배운 내용 CI/CD CI와 CD CI(Continuous Integration) 는 코드 변경을 지속적으로 통합하면서 Build와 Test를 통해 문제가 있는지를 빠르게 확인하는 과정이다. Code Change ↓ Integration ↓ Build ↓ Test ↓ Feedback CD 는 CI를 통과한 결과물을 배포 가능한 상태로 유지하거나 실제 실행 환경까지 전달하는 과정이다. Continuous Delivery → 언제든 배포할 수 있는 상태까지 자동화 Continuous Deployment → 검증된 변경을 실제 환경까지 자동 배포 결국 CI/CD는 코드 변경 ↓ 검증 ↓ Build ↓ 배포 가능한 결과물 ↓ 실제 실행 환경 이라는 과정을 반복 가능하게 만드는 것이라고 볼 수 있다. GitHub Actions CI/CD를 실제로 구성할 때는 GitHub Actions를 이용했다. 기본 구조는 Workflow → 전체 자동화 흐름 Event / Trigger → 언제 실행할 것인가 Job → 어떤 작업 묶음을 실행할 것인가 Step → 실제 실행 단위 Runner → 어디에서 실행할 것인가 정도로 나눌 수 있다. 예를 들어 코드가 Push되면 Push ↓ GitHub Actions ↓ Test ↓ Docker Image Build ↓ Registry Push ↓ Deploy 같은 작업을 자동으로 실행할 수 있다. 직접 배포할 때는 사람이 알고 있던 순서대로 명령을 실행하면 됐지만 자동화하려면 무엇을 언제 어떤 조건에서 실행할지를 명시적인 Workflow로 만들어야 한다. 그래서 CI/CD는 단순히 명령을 대신 실행하는 것보다 사람이 반복해서 하던 작업 절차를 시스템이 실행할 수 있는 형태로 바꾸는 것 에 가까운 것 같다. Docker와 AWS 배포 Docker를 이용하면 애플리케이션과 실행에 필요한 Runtime, Dependency 등을 이미지 형태로 묶을 수 있다. Application + Runtime + Dependency ↓ Docker Image 만들어진 이미지는 Registry에 저장하고 실제 서버에서 가져와 실행할 수 있다. 이번에는 AWS의 여러 서비스를 연결해 실제 배포 과정도 경험했다. OIDC / IAM → GitHub Actions가 AWS에서 사용할 권한 ECR → Docker Image 저장 EC2 → 애플리케이션 실행 RDS → 영속 데이터 저장 ElastiCache → Redis와 같은 인메모리 저장소 SSM → 서버에 명령 전달 및 관리 전체 흐름은 대략 GitHub ↓ GitHub Actions ↓ AWS 인증 ↓ Build / Test ↓ Docker Image ↓ ECR ↓ EC2 ↓ Container 실행 ↓ RDS / Redis 등과 연결 ↓ Service 로 볼 수 있었다. 각 서비스를 따로 배우는 것보다 실제 배포 흐름에서 어떤 역할을 담당하는지 보니 훨씬 단순하게 이해할 수 있었다. Kubernetes와 GitOps도 개념적으로 접했지만 이번 달에는 실제 활용보다는 이런 방식으로 실행 상태를 관리할 수 있다는 정도로 이해했다. Multi-Agent System Multi-Agent와 Orchestration Multi-Agent 자체는 크게 낯설지 않았다. AI를 어느 정도 일을 빠르게 처리할 수 있는 작업자라고 생각하면 Single Agent → 한 명에게 일을 맡긴다. Multi-Agent → 여러 명에게 일을 나눠 맡긴다. Orchestration → 여러 작업자를 하나의 목표에 맞게 조율한다. 정도로 생각할 수 있다. 실제로는 Goal ↓ Task Decomposition ↓ Task 관계 정의 ↓ Agent Assignment ↓ Execution ↓ Communication ↓ Result Merge ↓ Evaluation 같은 구조가 필요하다. 결국 Multi-Agent에서 중요한 것은 Agent의 숫자보다 작업을 어떻게 나누고 여러 실행 주체를 어떻게 연결할 것인가 라고 생각한다. Role과 Task Agent를 여러 개 사용할 때는 Role 과 Task 를 구분할 수 있다. Role → 이 Agent가 어떤 책임을 가지는가 Task → 지금 실제로 수행해야 하는 일 예를 들면 Role: Researcher Task: 특정 기술 조사 Role: Reviewer Task: 조사 결과 검증 처럼 볼 수 있다. 사람이 팀에서 맡고 있는 역할과 지금 처리해야 하는 일이 다른 것과 크게 다르지 않다. Task Decomposition과 Dependency 큰 일을 여러 Agent에게 맡기려면 먼저 Task를 나눠야 한다. Goal ↓ Task Decomposition ↓ Task A Task B Task C 하지만 Task를 나눴다고 모두 동시에 실행할 수 있는 것은 아니다. A → B → C 처럼 앞의 결과가 필요하다면 순차적으로 실행해야 한다. 반대로 → A → Input → B → Merge → C → 처럼 서로 독립적이라면 병렬로 처리할 수 있다. 따라서 Multi-Agent에서 먼저 봐야 하는 것은 Agent의 수보다 Task 사이의 Dependency 다. Goal ↓ Task Decomposition ↓ Dependency ↓ Execution Strategy ↓ Agent Assignment 작업 관계는 Graph로 표현할 수 있고, 순환이 없는 의존 관계라면 DAG(Directed Acyclic Graph) 형태로 볼 수도 있다. Workflow Pattern Task를 어떤 관계로 실행할지에도 반복되는 Pattern이 있다. Sequential / Chain A → B → C 앞 작업의 결과를 다음 작업이 사용한다. Parallel / Fan-out, Fan-in → A → Input → → B → Merge → C → 독립적인 작업을 동시에 수행하고 마지막에 합친다. Router → Agent A Input → Router → Agent B → Agent C 입력이나 상태에 따라 적절한 실행 경로를 선택한다. Evaluator–Optimizer Generate ↓ Evaluate ↓ Pass? ─ YES → Result │ NO ↓ Improve ↺ 결과를 평가하고 기준을 만족하지 못하면 다시 개선한다. 처음부터 특별히 새로운 개념이라기보다 작업 사이의 관계에 이미 존재하던 구조들에 이름이 붙어 있는 느낌 에 가까웠다. Contract와 Interface Agent들이 독립적으로 동작하려면 서로 무엇을 주고받을지에 대한 약속이 필요하다. Task Input Constraints Expected Output Status Error Metadata 같은 정보를 정해진 형태로 전달할 수 있다. Agent A ↓ Contract / Interface ↓ Agent B 이 부분 역시 기존 소프트웨어의 Interface나 Contract 개념과 크게 다르지 않았다. 내부 구현이 달라져도 Contract가 유지된다면 다른 구성요소에 주는 영향을 줄일 수 있다. 결국 Agent를 독립적으로 나눈다는 것도 경계를 명확하게 정의하는 문제 라고 생각할 수 있다. Router, Supervisor, Handoff 여러 Agent 사이에서 작업을 전달하거나 관리하는 방법도 나눌 수 있다. Router "누구에게 보낼 것인가?" 입력이나 현재 상태를 보고 적절한 Agent를 선택한다. → Research Input → Router → Coding → Review Supervisor "전체 작업을 어떻게 조율할 것인가?" 전체 목표와 진행 상태를 보고 여러 Agent에게 Task를 배분하거나 다음 행동을 결정한다. ┌→ Agent A Goal → Supervisor → Agent B └→ Agent C Handoff "현재 하던 작업을 누구에게 넘길 것인가?" 현재 Agent가 다른 Agent가 더 적합하다고 판단하면 필요한 Context와 함께 작업의 제어권을 넘긴다. Agent A ↓ 작업 수행 ↓ 다른 Agent가 더 적합 ↓ Handoff ↓ Agent B 정리하면 Router → 선택 Supervisor → 전체 조율 Handoff → 작업과 제어권 이전 정도로 볼 수 있다. 사람이 여러 명 모여서 일할 때도 자연스럽게 생기는 역할들이라 개념 자체가 어렵게 느껴지지는 않았다. State와 Context 여러 Agent가 작업하면 전체 Workflow가 현재 어떤 상태인지 관리해야 한다. Global State 현재 Task 완료된 Task Agent별 Result Error 다음 실행 대상 하지만 모든 정보를 모든 Agent에게 전달할 필요는 없다. Global State ↓ 필요한 정보 선택 ↓ Local Context ↓ Agent 각 Agent가 현재 작업을 처리하는 데 필요한 정보만 전달할 수 있다. 단일 Agent에서도 생각했던 문제지만 Multi-Agent에서는 실행 주체가 늘어나면서 누가 어떤 정보를 알아야 하는가 가 더 명시적인 문제가 되는 것 같다. A2A와 MCP 여러 Agent와 Tool을 연결하면서 A2A 와 MCP 의 역할도 볼 수 있었다. A2A → Agent ↔ Agent MCP → Agent ↔ Tool / Resource 하나의 시스템에서는 Agent A │ A2A ↓ Agent B │ MCP ↓ Tool / API / Data 처럼 함께 사용할 수도 있다. 서로 경쟁하는 기술이라기보다 연결하는 대상이 다른 도구 로 보는 편이 자연스럽다. Trace와 Evaluation Agent가 여러 개가 되면 최종 결과만 봐서는 내부에서 어떤 일이 있었는지 알기 어렵다. 그래서 Trace를 통해 어떤 Agent가 실행됐는가 어떤 Task를 수행했는가 어떤 Tool을 사용했는가 어디에서 실패했는가 얼마나 많은 비용과 시간이 들었는가 같은 실행 과정을 확인할 수 있다. Evaluation도 결과 하나만 보는 것이 아니라 Result Quality → 최종 결과가 좋은가 Task Quality → 각 Agent가 맡은 일을 잘했는가 Trajectory → 실행 경로가 적절했는가 Latency → 시간이 적절한가 Cost → 자원을 얼마나 사용했는가 Reliability → 반복해도 안정적인가 처럼 여러 기준을 사용할 수 있다. Agent가 늘어나면 능력뿐 아니라 관찰하고 평가해야 하는 범위도 같이 늘어난다. 결국 모두 작업을 잘하기 위한 도구 이번 달에 배운 내용을 다시 생각해보면 CI/CD와 Multi-Agent는 구체적으로 전혀 다른 기술이지만 더 위에서는 비슷한 질문에 답하고 있었다. 사람이든 AI든 소프트웨어든 일을 하려면 결국 왜 하는가? ↓ 무엇을 해야 하는가? ↓ 어떻게 나눌 것인가? ↓ 누가 할 것인가? ↓ 어떤 순서와 관계로 실행할 것인가? ↓ 어떤 정보를 주고받을 것인가? ↓ 현재 상태는 무엇인가? ↓ 실행 ↓ 잘했는지 확인 ↓ 다음 작업에 반영 이 필요하다. 이번 달에 배운 개념들을 여기에 대응하면 Goal / Intent → 왜 하는가 Task → 무엇을 해야 하는가 Task Decomposition → 어떻게 나눌 것인가 Dependency / DAG → 작업들은 어떤 관계인가 Role / Agent → 누가 할 것인가 Workflow Pattern → 어떤 흐름으로 실행할 것인가 Contract / Interface → 무엇을 어떤 형태로 주고받을 것인가 State → 지금 어디까지 진행됐는가 Context → 현재 작업에 무엇을 알아야 하는가 Router → 누구에게 보낼 것인가 Supervisor → 전체를 어떻게 조율할 것인가 Handoff → 다른 실행 주체에게 어떻게 넘길 것인가 A2A → Agent와 Agent가 어떻게 협력할 것인가 MCP → 외부 Tool과 Resource를 어떻게 사용할 것인가 Trace → 실제로 무엇이 일어났는가 Evaluation → 잘했는가 정도로 볼 수 있다. CI/CD는 이 중에서 특히 이미 방법이 정해진 반복 작업을 어떻게 안정적으로 실행할 것인가 에 대한 도구라고 생각할 수 있다. 사람이 반복하던 작업 ↓ 명시적인 Workflow ↓ 자동 실행 Multi-Agent는 한 주체가 모두 처리하기 어려운 작업을 어떻게 나누고 여러 실행 주체가 협력하게 할 것인가 에 더 가깝다. 복잡한 Goal ↓ Task 분리 ↓ 역할 분배 ↓ 관계 정의 ↓ 협력 ↓ 결과 결국 이번 달에 배운 기술들은 새로운 작업 원리를 만든다기보다 사람이 일을 잘하기 위해 원래 필요했던 구조들을 소프트웨어와 AI가 실행할 수 있는 형태로 명시한 것 처럼 보인다. AI가 특별해서 완전히 새로운 질문이 생긴 것이 아니라, 왜 하는가? 무엇을 해야 하는가? 누가 하는 것이 좋은가? 어떤 정보를 알아야 하는가? 어떻게 협력할 것인가? 잘했는지는 어떻게 알 것인가? 같은 질문에 답하는 방식이 조금씩 달라지고 있는 것 같다. 2. 소감 이번 달에는 새로운 개념을 이해하는 데 어렵거나 헷갈린다는 느낌은 거의 없었다. 단일 Agent를 배우면서 이미 역할, Task, Context, State, Tool, Trace, Evaluation 등에 대해서 많이 생각했고, AI를 어느 정도 똑똑한 사람이 일을 빠르게 처리해주는 것처럼 생각하고 있었기 때문에 Multi-Agent의 개념들도 대부분 바로 이해할 수 있었다. Supervisor는 여러 작업자를 관리하는 사람, Handoff는 더 적절한 사람에게 일을 넘기는 것, Contract는 서로 일을 주고받기 위한 약속이라고 생각하면 특별히 새롭게 느껴질 부분이 많지 않았다. 처음에는 내가 이전에 비슷한 생각을 많이 해봤기 때문에 쉬운 것이라고 생각했다. 그런데 이번 달 내용을 다시 정리하면서 꼭 그것만은 아닌 것 같다는 생각도 들었다. Role, Task, Workflow, Supervisor, Handoff, Contract 같은 개념은 결국 사람이 여러 명이서 일을 잘하려고 해도 자연스럽게 필요한 것들 이다. 누가 어떤 일을 할지 정하고, 일을 작은 단위로 나누고, 순서를 정하고, 관리자가 전체 상황을 보고, 더 적절한 사람이 있으면 일을 넘기고, 서로 결과를 주고받기 위한 약속을 만드는 것은 AI가 없어도 원래 존재했던 문제다. 소프트웨어도 마찬가지다. 모듈 사이에는 Interface가 필요하고, 여러 작업에는 Dependency가 생기고, 반복 작업에는 Workflow가 필요하다. AI가 들어오면서 완전히 새로운 방식으로 일이 바뀐다기보다 기존 작업 구조 안에 스스로 판단할 수 있는 새로운 실행 주체가 추가되고 있다는 느낌 이 더 강했다. CI/CD도 비슷했다. Test, Build, Image 생성, 배포를 사람이 직접 할 수도 있지만 방법이 충분히 명확하고 반복된다면 사람이 매번 할 이유가 없다. 사람이 판단하며 반복 ↓ 과정을 명시 ↓ 자동화 라는 흐름이다. 어떻게 보면 Multi-Agent도 같은 방향에 있다. 사람이 직접 여러 AI에게 하나씩 일을 나눠주고 결과를 확인할 수도 있지만 역할과 작업 흐름이 어느 정도 반복된다면 그 관계 역시 시스템으로 만들 수 있다. 이렇게 생각하니 이번 달에 배운 여러 기술들이 모두 사람이 직접 하던 판단과 작업 중 어떤 부분을 명시적으로 만들고 시스템에 맡길 수 있는가 라는 문제로도 보였다. 그래서 새로운 기술을 볼 때 이름이나 사용법을 외우는 것보다 이 기술은 일을 하는 과정에서 어떤 질문에 답하기 위해 필요한가? 를 먼저 생각하는 방식이 나에게는 더 잘 맞는 것 같다. 기술이 달라져도 해결하려는 질문이 같으면 전체 구조에서 어디에 들어가는지도 금방 이해할 수 있다. 앞으로는 새로운 개념을 더 많이 아는 것보다 실제 작업을 하나 선택해서 이런 구조가 어디까지 도움이 되는지 직접 확인해보는 것이 더 중요할 것 같다. 생각으로는 자연스럽게 연결되지만 실제로 사용했을 때도 항상 효과적인지는 별개의 문제이기 때문이다. 3. KPT Keep 기술보다 먼저 "왜 필요한가"를 생각하기 새로운 개념을 배울 때 무엇인가? 만 보는 것보다 왜 필요한가? 어떤 문제를 해결하는가? 를 먼저 생각하는 방식은 계속 유지하고 싶다. 이번 달에도 Router → 적절한 실행 주체 선택 Handoff → 작업 이전 Contract → 협업을 위한 약속 CI/CD → 반복 실행의 자동화 처럼 목적을 기준으로 보니 새로운 개념을 빠르게 이해할 수 있었다. 이미 알고 있는 작업 구조와 연결하기 AI의 개념을 AI 안에서만 생각하지 않고 사람이나 기존 소프트웨어가 일하는 방식과 비교하는 것이 도움이 됐다. 구체적인 구현은 달라도 어떤 문제가 반복되는지를 찾으면 전체 구조를 이해하기 쉬웠다. 직접 실행해서 확인하기 AWS 배포와 GitHub Actions처럼 실제로 해봤을 때 각 기술의 역할이 더 명확해지는 경우가 많았다. 생각으로 이해한 것과 실제로 효과가 있는 것은 다를 수 있기 때문에 작은 범위라도 직접 실행하는 것은 계속 유지하고 싶다. Problem 생각보다 구현과 검증에 훨씬 많은 시간이 든다 구조 자체는 비교적 빠르게 이해하고 설계할 수 있지만 실제 코드로 만들고 여러 상황에서 정상적으로 동작하는지 확인하려면 훨씬 많은 시간이 필요하다. AI를 사용하면 만드는 속도는 빠르지만 사람이 결과를 이해하고 검증하는 속도는 그만큼 빠르게 늘어나지 않는다. 사용할 수 있는 도구가 너무 많다 Framework, A2A, MCP, Observability, Evaluation 등 사용할 수 있는 기술이 굉장히 많다. 문제는 각각 좋은 기술이라는 이유만으로 추가하면 시스템이 실제 필요 이상으로 복잡해질 수 있다는 것이다. 어디까지 기존 기술을 사용하고 어디부터 직접 만들지 결정하기 어렵다 이미 잘 만들어진 도구를 사용하면 빠르지만 내가 직접 보고 싶은 구조가 내부에 숨겨질 수 있고, 전부 직접 구현하면 이미 해결된 문제에 많은 시간을 쓰게 된다. 현재 목적에서 무엇을 확인하려는지를 기준으로 선택할 필요가 있다. 생각하는 범위가 계속 커진다 하나의 문제를 생각하면 자연스럽게 다음 문제도 보인다. Agent ↓ State ↓ Trace ↓ Evaluation ↓ Policy ↓ Memory ... 계속 연결해서 생각하는 것은 도움이 되지만 실제 실험 전에 범위가 지나치게 커지지 않게 조절할 필요가 있다. Try 1. 작업의 "왜"부터 적어보기 새로운 기술이나 구조를 선택하기 전에 왜 이 작업을 하는가? ↓ 무엇이 성공인가? ↓ 무엇을 해야 하는가? 부터 정리해보려고 한다. 목적이 명확해야 이후의 Task, Role, Workflow도 결정할 수 있다. 2. Task를 먼저 구조화하고 기술을 나중에 선택하기 Goal ↓ Task ↓ Dependency ↓ Workflow ↓ Role ↓ Executor ↓ Technology 순서로 보는 습관을 만들고 싶다. 특히 Multi-Agent 자체를 목적으로 사용하지 않고 Task 구조상 필요할 때 선택하려고 한다. 3. 작은 구조부터 실제로 비교하기 Single Agent ↓ 작은 Workflow ↓ Multi-Agent 로 단계적으로 늘리면서 품질 시간 비용 안정성 이 실제로 어떻게 달라지는지 비교해보고 싶다. 4. 기존 기술은 해결하려는 문제를 기준으로 선택하기 어떤 문제가 있는가? ↓ 이미 해결한 기술이 있는가? ↓ 현재 목적에 맞는가? ↓
velog
Make your Jaipur journey more memorable with a visit to the magnificent Hawa Mahal. Known as the Palace of Winds, this historic monument showcases beautiful Rajput architecture, delicate screens, arched openings, and an unforgettable pink sandstone façade. Whether you love history, architecture, photography, or Indian culture, Hawa Mahal offers something special. Before visiting, check the latest timings, ticket price, entrance information, and travel tips. A little planning can help you enjoy the monument without rushing. Explore Jaipur’s old city and create lasting memories around one of Rajasthan’s most celebrated attractions. https://coloursindiatours.com/hawa-mahal-jaipur-timings-ticket-price
Score: 54.4Confidence: 49%
View offervelog
출근 첫 주가 끝나고 주말 일을 하다가 복기하면서 문득 궁금해진 것들을 정리했다. 그런데 세 개를 다 확인해보니 내가 알던 게 전부 틀렸거나 반쯤 틀렸다. 그리고 공통점이 있었다. 1. JSP는 HTML에 JS를 끼워넣는 것인가 내가 알던 것 "JSP는 HTML 파일에 <script> 태그 사이로 자바스크립트 기능을 동적으로 끼워넣는 것" 뭔가 기능은 맞는 것 같은데 핵심을 놓친 느낌이 계속 들었다. 그럴 만했다. 실제 — 자바스크립트가 아니라 자바다 <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <body> <c:forEach var="dto" items="${freeBoardList}"> <tr><td>${dto.title}</td></tr> </c:forEach> </body> </html> 이 코드는 서버에서 실행된다. 브라우저는 이걸 본 적이 없다. [서버] JSP 를 읽는다 → ${freeBoardList} 를 실제 데이터로 치환 → <c:forEach> 를 돌려서 <tr> 을 여러 개 만든다 → 완성된 HTML 을 만든다 ↓ [브라우저] <tr><td>안녕하세요</td></tr> <tr><td>반갑습니다</td></tr> ← 이것만 받는다 브라우저가 받는 HTML 에는 <c:forEach> 도 ${...} 도 없다. 서버가 다 처리하고 결과만 보낸다. 반대로 브라우저의 소스 보기에 <c:forEach> 나 ${...} 가 그대로 보이면 서버가 처리하지 않은 것이다. 맨 위 taglib 선언이 빠지면 <c:...> 태그가 글자 그대로 나가고, web.xml 이 2.4 미만 버전이면 EL 이 꺼져서 ${...} 가 그대로 나간다. 한 줄 정의 HTML 안에 자바 코드를 섞어서, 서버가 HTML을 만들어내는 기술. "동적"의 주체가 서버다. 요청할 때마다 다른 HTML이 만들어진다. 값이 HTML 의 일부가 된다는 뜻이기도 하다. ${dto.title} 은 값을 escape 없이 그대로 넣는다. 게시판 제목처럼 사용자가 쓴 값은 <c:out value="${dto.title}"/> 로 찍어야 < , > 가 태그로 해석되지 않는다. JS 로 목록을 그릴 때도 같다. 문자열로 이어 붙여 .html() 에 넣는다면 escape 를 거치거나 .text() 로 넣는다. 그럼 내가 말한 건 뭐였나 <script> $("#tb").html(html); </script> 이건 브라우저에서 실행되는 자바스크립트다. JSP와 아무 상관이 없다. JSP 파일 안에 <script> 를 쓸 수 있어서 헷갈린 것이다. <%-- JSP 파일 --%> <c:forEach var="dto" items="${list}"> ← 서버가 실행 <tr><td>${dto.title}</td></tr> </c:forEach> <script> function searchFn() { ... } ← 브라우저가 실행 </script> 한 파일 안에 두 세계가 공존한다. 그게 JSP 를 처음 볼 때 혼란스러운 이유였다. 실행 시점이 다르다 JSP/EL/JSTL 서버가 HTML 을 만들 때 한 번 JavaScript 브라우저가 HTML 을 받은 뒤, 계속 이 차이 때문에 실제로 막힌 적이 있다. 검색 조건 <select> 를 바꿀 때마다 다른 입력창을 띄워야 했는데, <c:choose> 로 하려다 실패했다. <!-- [오개념] 이건 "페이지가 처음 뜰 때" 만 판단한다 --> <c:choose> <c:when test="${searchType eq '6'}"> <input type="text" name="startDate"> </c:when> </c:choose> 사용자가 select 를 바꾸는 건 브라우저에서 일어나는 일이라, 이미 끝난 JSTL 은 반응할 수 없다. // [정답] 미리 다 만들고 JS 로 숨긴다 function changeFn() { $("#case1, #case2, #case3").hide(); var v = $("#selection").val(); if (v == "6") $("#case3").show(); } 판단 기준 서버가 아는 값을 그린다 → JSTL / EL 사용자 조작에 반응한다 → JavaScript "누가 그 값을 알고 있느냐." 이 기준 하나로 정리된다. 검색 후 "아까 고른 옵션을 유지"하는 건 서버가 아는 값이니 EL 이 맞다. ${paramMap.searchType eq '4' ? 'selected' : ''} 같은 식으로. paramMap 은 컨트롤러가 model 에 담아 줘야 보이고, 안 담았다면 EL 기본 객체로 ${param.searchType ...} 이라 쓴다. 페이지를 서버가 다시 그릴 때 얘기고, AJAX 로 목록만 바꾸면 select 는 고른 그대로 남는다. 결정적 사실 — JSP는 서블릿이다 톰캣이 .jsp 파일을 자바 소스로 변환해서 컴파일한다. // 톰캣이 자동 생성한 freeBoardMain_jsp.java (패키지·implements·throws 는 줄였다) public final class freeBoardMain_jsp extends HttpJspBase { public void _jspService(HttpServletRequest request, HttpServletResponse response) { out.write("<html>\n<body>\n"); // ... } } 톰캣의 work/ 폴더에 이 파일이 실제로 생긴다. 열어보면 out.write("<html>") 같은 코드가 줄줄이 나온다. 이클립스에서 띄웠다면 워크스페이스의 .metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/프로젝트명/org/apache/jsp/ 아래다. WEB-INF 폴더는 WEB_002dINF 로 바뀌어 있다. 서블릿 자바 코드 안에 HTML 을 문자열로 섞는다 JSP HTML 안에 자바 코드를 섞는다 방향이 반대일 뿐 같은 것이다. 화면을 만들 때는 후자가 편해서 JSP 가 나왔다. 정리해서 말하면 JSP는 HTML 안에 자바 코드를 넣어 서버에서 동적으로 HTML을 생성하는 기술입니다. 톰캣이 JSP를 서블릿 자바 코드로 변환하고 컴파일해서 실행하기 때문에, 실제로는 서블릿과 같은 것입니다. 브라우저는 JSP 코드를 받지 않고 완성된 HTML만 받습니다. 2. SqlSessionTemplate 과 @Mapper 인터페이스 두 방식을 다 겪었다 // 개인 프로젝트에서 쓰던 방식 mapper.selectBoardList(boardCode, rowBounds); // 회사에서 보는 방식 sqlSessionTemplate.selectList("freeBoardGetList", param); 둘 다 XML 의 쿼리를 불러와 SQL 을 실행하는 건 같은데, 왜 이름과 형태가 다른지 궁금했다. 답 — 같은 것의 두 가지 표현이다 @Mapper 인터페이스 ↓ MyBatis 가 실행 시점에 구현체를 자동 생성 (동적 프록시) ↓ 메서드명 → XML 의 id 로 매칭 ↓ 내부적으로 SqlSession.selectList("...selectBoardList", param) 호출 인터페이스 방식이 결국 SqlSessionTemplate 방식을 대신 해주는 것이다. @Mapper public interface NeighborhoodMapper { List<Neighborhood> selectBoardList(int boardCode, RowBounds rowBounds); } 구현 클래스가 없는데 동작하는 게 신기했는데 , MyBatis 가 실행 시점에 만들어주는 것이었다. <mapper namespace="com.zipinfo.project.neighborhood.model.mapper.NeighborhoodMapper"> ↑ 인터페이스의 전체 경로와 일치해야 한다 <select id="selectBoardList"> ← 메서드명과 일치 namespace + id 를 합치면 SqlSessionTemplate 에 넘기는 문자열이 된다. 회사 코드처럼 "freeBoardGetList" 만 넘겨도 되는 건 MyBatis 가 짧은 id 도 같이 등록하기 때문이다. 다른 매퍼에 같은 id 가 생기면 짧은 id 호출은 is ambiguous in Mapped Statements collection 으로 터진다. 이것도 실행해봐야 안다. 차이점 SqlSessionTemplate Mapper 인터페이스 쿼리 지정 문자열 메서드 호출 오타 발견 런타임 메서드는 컴파일, XML id 는 런타임 파라미터 타입 Object 타입 지정 반환 타입 캐스팅 필요할 때 있음 선언된 타입 IDE 자동완성 안 됨 됨 여러 파라미터 Map 으로 묶어야 @Param 사용 가능 실제로 이 차이를 겪었다 Mapper 에서 쿼리 두 개를 하나로 합치면서 freeBoardSearchList 를 지웠는데, Service 가 아직 그 id 를 부르고 있었다. Mapped Statements collection does not contain value for freeBoardSearchList sqlSessionTemplate.selectList("freeBoardSearchList", paramMap); // ↑ 오타든 삭제된 id든 실행해봐야 안다 인터페이스 방식이었으면 메서드를 지우는 순간 컴파일 단계에서 "그런 메서드 없다"고 잡혔을 것이다. 단 XML 의 <select> 만 지우고 메서드를 남기면 컴파일은 통과하고, 처음 호출할 때 Invalid bound statement (not found) 로 터진다. 그리고 문제가 하나 더 있었다. return 문은 고쳤는데 위쪽 로그 줄이 옛 id 를 그대로 쓰고 있었다. System.out.println(sqlSessionTemplate.selectList("freeBoardSearchList", paramMap)); // ← 여기서 터짐 return sqlSessionTemplate.selectList("freeBoardGetList", paramMap); // ← 도달 못 함 문자열이라 Ctrl+F 로 찾지 않으면 놓친다. 메서드였으면 지우는 순간 IDE 가 부르는 곳을 전부 빨갛게 표시했을 것이다. 이 코드에는 다른 문제도 있다. 로그를 찍으려고 쿼리를 한 번 더 실행하고 있다. 결과를 변수에 담아 쓰는 게 맞다. 왜 회사는 옛날 방식인가 iBatis 2.x (~2010) 문자열 id 방식뿐. Spring 에서는 SqlMapClientTemplate MyBatis 3.0 (2010) SqlSession 문자열 방식과 Mapper 인터페이스가 처음부터 같이 있었다 mybatis-spring 1.0 (2010) SqlSessionTemplate 과 MapperFactoryBean 이 같이 나왔다 MyBatis 3.4 (2016) @Mapper 어노테이션 추가 현재 인터페이스 방식이 권장 SqlSessionTemplate 이 옛날 방식인 게 아니라, 문자열 id 로 부르는 습관이 iBatis 시절에서 온 것이다. MyBatis 3 와 mybatis-spring 은 처음부터 두 방식을 같이 줬다. 레거시 프로젝트는 만들 당시의 방식이 그대로 남아 있다. 그리고 한번 정한 방식을 중간에 바꾸지 않는다. 같은 맥락 — Service / ServiceImpl 개인 프로젝트 NeighborhoodService (인터페이스) + NeighborhoodServiceImpl (구현) 회사 FreeBoardService (클래스 하나) 인터페이스 분리는 "구현을 갈아끼울 수 있게" 하려는 것인데, 실제로 갈아끼우는 일이 거의 없어서 요즘은 생략하기도 한다. 옛 Spring 에서는 인터페이스가 있느냐가 AOP 프록시 방식을 갈랐다. Spring 3.2 전에는 인터페이스가 없는 클래스에 트랜잭션 같은 AOP 를 걸려면 CGLIB 라이브러리를 따로 넣어야 했고, 인터페이스가 있으면 JDK 동적 프록시로 끝났다. 3.2부터는 CGLIB 가 Spring 안에 들어 있어서 라이브러리를 따로 넣을 일이 없다. 둘 다 흔한 방식이다. 프로젝트 관례를 따르면 된다. 정리 원리 같다. 인터페이스 방식이 내부적으로 SqlSession 을 호출한다 차이 타입 안전성과 IDE 지원 현대적 인터페이스 방식 현장 둘 다 본다. 레거시일수록 SqlSessionTemplate 두 방식을 다 해본 게 오히려 유리하다. 어느 프로젝트에 가도 읽을 수 있다. 3. serialize() 없으면 여러 개를 못 보내나 내가 알던 것 "데이터를 둘 이상 백엔드로 넘긴다면 serialize() 를 한다" 검색 기능을 만들 때 기간 검색만 입력칸이 두 개였다. 통일성을 위해 전부 serialize() 로 보내야 한다고 생각했다. 그런데 최종 코드에는 serialize() 가 없었다. 왜 그랬는지 정리해봤다. 먼저 — 전제가 틀렸다 data : { searchType : "6", startDate : "20260101", endDate : "20261231" } $.ajax 의 data 에 객체를 주면 jQuery 가 알아서 직렬화한다. searchType=6&startDate=20260101&endDate=20261231 serialize() 를 쓴 것과 결과가 똑같다. 둘 다 key=value&key=value 형태로 나간다. serialize() 폼 안의 name 붙은 것을 자동 수집 객체 직접 작성 내가 고른 것만 담는다 serialize() 는 "폼 요소를 자동으로 수집"하는 편의 기능일 뿐이다. 여러 개를 보내는 것과는 별개 문제다. 그리고 검색 화면은 조건이 안 맞았다 serialize() 가 무엇을 담는지는 세 가지로 정해진다. 대상 <form> 에 부르면 안의 입력 요소를 모은다 <div> 에 부르면 에러 없이 빈 문자열이다. 안의 입력 요소를 직접 골라야 한다 name name 속성이 있는 요소만 담긴다 제외 disabled, 버튼류, type="file", 체크 안 된 체크박스·라디오는 빠진다. 숨긴 요소는 안 빠진다 문제 1 — <form> 이 없었다 <div> <select id="selection" onchange="changeFn()">...</select> <span id="case1" style="display:none">...</span> <span id="case2" style="display:none">...</span> <span id="case3" style="display:none">...</span> <button onclick="searchFn()">검색</button> </div> <div> 로만 감싸져 있었다. 여기에 바로 serialize() 를 부르면 빈 문자열이 나온다. 폼으로 감싸거나, div 에 id 를 붙여 $("#searchArea :input").serialize() 처럼 입력 요소를 직접 골라야 했다. select 에는 name 도 없어서 그대로는 searchType 부터 빠진다. 문제 2 — 숨긴 요소도 전송된다 이게 더 큰 문제다. display:none 이어도 disabled 가 아니면 값이 나간다 name 을 칸마다 따로 붙였다면( searchType , typeQuery , textQuery , startDate , endDate ), "제목" 검색을 골라도 서버가 받는 건 이렇게 된다. {searchType=4, typeQuery=01, textQuery=카페, startDate=, endDate=} ↑ 안 보이는데 나간다 어떤 값을 써야 하는지 서버가 판단해야 한다. 막으려면 hide() 할 때마다 disabled 를 걸고, show() 할 때 다시 풀어야 한다. $("#case1, #case2, #case3").hide() .find("input, select").prop("disabled", true); $("#case3").show() // 6번일 때 .find("input, select").prop("disabled", false); // 보여줄 칸은 다시 푼다 코드가 늘어난다. $("#searchArea :input:visible").serialize() 처럼 보이는 것만 고르는 방법도 있다. 대신 type="hidden" 도 안 보이는 요소로 쳐서 같이 빠진다. 문제 3 — name 충돌 이게 결정적이었다. 서버가 기대하는 것 searchType=4 & query=카페 ← 2~5번 searchType=6 & startDate=... & endDate=... ← 6번 query 라는 이름으로 보내야 하는데 입력칸이 두 개다. <select name="query" id="typeQuery"> <!-- 1번용 --> <input name="query" id="textQuery"> <!-- 2~5번용 --> name 이 같으면 serialize() 가 둘 다 담는다. query=01&query=카페 서버에서 Map<String,String> 으로 받으면 첫 번째 값 하나만 들어온다. 마크업에서 select 가 먼저라, "카페"를 입력해도 서버는 01 을 받는다. String 하나로 받으면 01,카페 로 붙어서 온다. 그래서 택한 방식 var value = $("#selection").val(); var data = { searchType : value }; if (value == "1") { data.query = $("#typeQuery").val(); } else if (value == "2" || value == "3" || value == "4" || value == "5") { data.query = $("#textQuery").val(); } else if (value == "6") { data.startDate = $("#startDate").val(); data.endDate = $("#endDate").val(); } 필요한 것만 골라 담는다. 1~5번 { searchType, query } 6번 { searchType, startDate, endDate } 보내는 방식은 하나고 담기는 키만 다르다. 원래 원했던 "통일성"이 이 부분이다. 나중에 페이지네이션을 붙일 때 data.page = page 한 줄만 추가하면 됐다. 조건부로 담는 구조라 확장이 쉬웠다. 그럼 serialize() 는 언제 쓰나 상세/수정 화면에서는 썼다. data : $("#detailForm").serialize() <form id="detailForm"> <input type="hidden" name="num" value="${freeBoardDto.num}"/> <select name="codeType">...</select> <input type="text" name="name" value="..."/> <input type="text" name="title" value="..."/> <textarea name="content">...</textarea> </form> 여기는 조건이 다 맞았다. <form> 으로 감싸져 있다 모든 요소에 name 이 있다 숨기거나 조건부로 보이는 게 없다 필드가 다섯 개라 손으로 담으면 길다 판단 기준 serialize() 가 좋을 때 폼 형태가 고정되어 있다 필드가 많다 전부 보내면 된다 직접 담는 게 좋을 때 조건에 따라 보낼 항목이 달라진다 숨겨진 요소가 있다 보내기 전에 가공이 필요하다 검색은 후자였다. "전체" 보기를 빼면 조건이 6개고 각각 다른 입력칸을 쓰니까. 정리 틀린 표현 "여러 개를 보내려면 serialize" 맞는 표현 "폼 전체를 통째로 보낼 때 serialize" 세 가지의 공통점 정리하고 보니 셋이 같은 종류의 오해였다. JSP "브라우저에서 JS 를 실행하는 것" → 서버에서 HTML 을 만드는 것 Mapper "다른 방식" → 같은 것을 대신 해주는 것 serialize "여러 개를 보내는 방법" → 폼을 수집해주는 것 전부 "어디서 실행되는가" 혹은 "무엇을 대신해주는가" 의 문제였다. 도구가 대신해주는 걸 모르면 Mapper 인터페이스 SqlSession 호출을 대신한다 serialize() 폼 요소 수집을 대신한다 jQuery DOM API 호출을 대신한다 Spring MVC URL 마다 서블릿을 만드는 일을 대신한다
velog
솔직히 말하면, 처음엔 "또 클라우드 회사네" 하고 넘겼습니다. 그런데 최근 고객사에서 가상화 라이선스 비용 이슈가 터지면서 제대로 뜯어볼 기회가 생겼고, 파고들수록 "이거 꽤 다르다"는 생각이 들었습니다. 왜 지금 뉴타닉스인가 요즘 기업 IT 담당자들 사이에서 공통적으로 나오는 한숨이 있습니다. "VMware 라이선스 비용이 너무 올랐다"는 거죠. 브로드컴 인수 이후 구독형 전환이 강제되면서 TCO가 단기간에 4배 이상 뛰었다는 얘기가 실제로 나오고 있고, 여기에 예기치 않은 컴플라이언스 패널티 위험까지 더해졌습니다. 비용 문제만이 아닙니다. AI를 도입하려면 인프라부터 뜯어고쳐야 한다는 인식도 확산되고 있어요. 최근 설문에서 기업 응답자의 96%가 생성형 AI가 조직 전략을 재편하고 있다고 답했는데, 정작 현재 인프라로 그 워크로드를 제대로 감당할 수 있다고 자신하는 곳은 많지 않습니다. 이 틈새를 파고드는 게 뉴타닉스입니다. IDC 분석 기준 — 뉴타닉스 도입 기업의 3년 평균 ROI는 391%, 초기 투자 회수 기간은 7개월. 5년 기준 TCO 절감은 평균 62%로 집계됩니다. 처음엔 반신반의했는데, 구조를 뜯어보니 어느 정도 납득이 됩니다. VMware에서 빠져나오는 현실적인 방법 저도 예전에 수백 대 VM을 다른 하이퍼바이저로 옮기는 프로젝트를 옆에서 지켜본 적이 있는데, 그때 제일 힘들었던 게 드라이버 충돌과 네트워크 재설정이었습니다. 마이그레이션이 끝났는데도 하드코딩된 IP 때문에 여기저기 앱이 터지는 사태가 벌어졌거든요. Nutanix Move는 이 부분을 꽤 영리하게 풀었습니다. 무료로 제공되는 도구인데, 핵심은 세 가지입니다. 서비스 중단 없는 데이터 동기화 — VM을 끄지 않고 백그라운드에서 먼저 복제합니다. 변경된 블록만 추적해서 실제 컷오버 중단 시간은 수 분 이내로 줄어듭니다. 드라이버 자동 주입 — AHV 환경에서 부팅 시 블루스크린이 뜨는 상황을 사전에 차단합니다. VirtIO 드라이버를 자동으로 넣어주기 때문에 애플리케이션 리팩토링이 필요 없습니다. IP·MAC 주소 유지 — 이게 제일 중요한 포인트입니다. 기존 방화벽 정책이나 앱 간 통신 설정을 건드릴 필요가 없습니다. 마이그레이션 후유증을 원천에서 막아줍니다. 결과적으로 고가의 가상화 라이선스를 폐기하고 AHV로 전환하면, Prism 단일 콘솔로 전체 인프라를 관리하면서 TCO를 53% 이상 추가로 낮출 수 있다고 합니다. 온프레미스와 AWS를 하나처럼 — NC2 이야기 기존 앱을 AWS로 올릴 때 왜 이렇게 복잡하냐면, 보통 클라우드 전용 이미지로 변환하거나 오버레이 네트워크를 얹어야 하는데, 그 과정에서 성능이 떨어지고 운영 복잡도가 올라가기 때문입니다. NC2(Nutanix Cloud Clusters) on AWS 는 접근 방식이 다릅니다. AWS 베어메탈 인스턴스 위에 뉴타닉스 AHV를 직접 올려서, 온프레미스와 완전히 동일한 환경을 퍼블릭 클라우드에서 구현합니다. 중첩 가상화를 쓰지 않으니 자원 낭비가 없고, AWS의 ENI와 직접 연결되어 S3, RDS, ELB 같은 200여 개의 AWS 서비스와 속도 저하 없이 통신할 수 있습니다. 개인적으로 흥미로웠던 건 하이버네이트 & 재개 기능입니다. 야간이나 주말에 쓰지 않는 개발·테스트 환경을 통째로 S3에 오프로드해두고, 필요할 때만 다시 깨우는 방식이에요. 비싼 베어메탈 인스턴스를 실제 쓴 시간만큼만 과금하니 비용이 크게 줄어듭니다. TCO 53% 절감이라는 숫자도 이런 구조에서 나오는 겁니다. 쿠버네티스를 프로덕션에서 쓰는 게 왜 이렇게 힘드냐 하면 실제로 쿠버네티스를 운영해본 팀들이 공통적으로 하는 말이 있습니다. "클러스터 띄우는 건 쉬운데, 로깅·모니터링·백업·보안 정책 다 붙이고 나면 반년이 지나 있더라." 파편화된 오픈소스 에코시스템을 직접 조립하는 피로감이 실제로 큽니다. NKP(Nutanix Kubernetes Platform) 는 이 복잡성을 하나로 묶어줍니다. 마음에 들었던 건 순수 CNCF 업스트림 기반이라 특정 벤더에 묶이지 않는다는 점입니다. 오늘 NKP에서 돌리는 앱을 내일 EKS나 AKS로 그대로 옮길 수 있습니다. 보안 스택도 실용적입니다. eBPF 기반 Cilium으로 마이크로서비스 간 통신을 격리하고, Trivy가 컨테이너 이미지 취약점을 자동 스캔하며, Gatekeeper가 규정 위반 배포를 원천 차단합니다. 인터넷이 아예 안 되는 망 분리 환경(국방·공공기관)에서도 오프라인 패치가 가능하도록 설계된 점은 국내 공공 시장에서 꽤 유효한 포인트라고 봅니다. 기업용 AI, 외부 API에만 의존하면 생기는 문제 ChatGPT API를 내부 서비스에 연동하면 편하긴 한데, 민감한 데이터를 외부 서버로 보내야 한다는 걱정과 예측 불가능한 토큰 과금이 항상 따라옵니다. 의료나 금융은 규제 이슈까지 있고요. Nutanix Enterprise AI(NAI) 는 자체 데이터센터 안에서 언어 모델을 구동하는 프라이빗 AI 플랫폼입니다. NVIDIA와의 파트너십을 통해 BlueField DPU로 네트워크·보안 처리를 오프로드하는 구조인데, 덕분에 GPU가 AI 연산에만 집중할 수 있게 됩니다. 더 눈길을 끈 건 KV 캐시 오프로딩입니다. LLM이 긴 문서나 대화를 처리할 때 GPU 메모리에 임시 데이터가 쌓이는데, 이게 꽉 차면 시스템이 멈추거나 GPU를 더 사야 합니다. NAI는 이 데이터를 NVMe 스토리지로 내보내고 RDMA 프로토콜로 초저지연 연결을 유지합니다. GPU 메모리를 적게 쓰면서도 긴 컨텍스트를 처리할 수 있으니, 토큰당 비용을 낮추는 실용적인 구조입니다. GPT-in-a-Box 2.0 — Cisco UCS 서버, NVIDIA GPU, 뉴타닉스 소프트웨어(NCI + NKP + NAI)가 공장 검증된 상태로 배송됩니다. Hugging Face 모델이나 NVIDIA NIM을 몇 번의 클릭으로 바로 배포할 수 있고, 부서별 토큰 사용량 제한과 과금 거버넌스 기능도 내장되어 있습니다. 재해 복구, 보조 데이터센터 없이 가능할까 DR을 위해 동일한 규모의 보조 데이터센터를 별도 운영하는 전통적인 방식은 비용이 너무 큽니다. 평소엔 아무것도 안 하는 인프라에 돈을 계속 쏟아붓는 격이니까요. MST(Multi-Cloud Snapshot Technology)는 이 구조를 바꿉니다. 온프레미스 스냅샷을 Amazon S3에 저장해두고, 실제 재해가 날 때만 NC2 on AWS를 긴급 프로비저닝해서 복원하는 방식입니다. 평소에는 저렴한 스토리지 비용만 내다가 필요할 때 컴퓨팅을 켜는 'Just-in-Time DR'이라고 볼 수 있습니다. 가장 경제적이면서도 강력한 RTO/RPO를 충족하는 현대적 아키텍처라고 생각합니다. 정책 기반 자동화도 실용적입니다. VM에 'DB', 'WEB' 같은 태그만 붙여두면 그 기준으로 복제 정책이 자동 적용되고, 재해 시에는 런북이 자동 실행되어 DB → 미들웨어 → 웹 순으로 순차 부팅됩니다. 실제 운영 환경에 영향 없이 격리망에서 DR 훈련을 해볼 수 있다는 것도 실무에서 중요한 포인트입니다. 보안 측면에서는 AccuKnox와의 파트너십이 눈에 띕니다. 뉴타닉스 Flow가 VM 간 통신을 네트워크 레벨에서 통제하고, AccuKnox의 eBPF 에이전트가 프로세스 레벨에서 이상 행동을 실시간 감지합니다. 랜섬웨어가 VM 하나를 뚫어도 내부 전파를 입체적으로 차단하는 구조입니다. 정리하면서 인프라 전환이 부담스러운 건 당연합니다. 잘못되면 서비스가 통째로 멈추니까요. 그런데 가상화 라이선스 비용은 계속 올라가고, AI 워크로드도 감당해야 하는 현실에서 "지금 쓰던 것 계속 쓰자"는 선택도 점점 더 위험해지고 있습니다. 뉴타닉스가 흥미로운 이유는 기술적 완성도뿐 아니라, 실제 마이그레이션 리스크를 줄이는 자동화 도구들이 잘 갖춰져 있기 때문입니다. Nutanix Move, 하이버네이트 기능, MST 기반 DR, GPT-in-a-Box가 각각 독립적으로 설계된 게 아니라 하나의 흐름 안에서 맞물려 있다는 인상을 받았습니다. 다음에는 실제 마이그레이션 PoC를 시작하는 방법과 TCO 계산 시 놓치기 쉬운 항목들을 정리해보겠습니다. 인프라 전환을 고민 중이시라면, 댓글로 어떤 부분이 가장 걸림돌인지 알려주세요.
velog
스위치를 이중으로 연결해두면 한쪽 링크가 죽어도 통신이 이어져서 좋지만, L2에서는 이 이중화가 오히려 문제를 만듭니다. 바로 루프 예요. STP(Spanning Tree Protocol)는 브로드캐스트 도메인에서 발생하는 이 루프를 막아주는 프로토콜입니다. 그림처럼 스위치 4대를 사각형으로 연결하면 프레임이 빨간 화살표를 따라 계속 돌게 됩니다. L2 프레임에는 TTL이 없어서 한 번 루프에 빠지면 스스로 사라지지 않거든요. 그래서 두 가지 문제가 생겨요. 브로드캐스트 스톰 : 브로드캐스트 프레임이 루프를 돌며 계속 늘어나서 대역폭과 장비 CPU를 잡아먹습니다. MAC 러닝 중복 : 같은 출발지 MAC이 여러 포트에서 번갈아 학습되어 MAC 테이블이 계속 흔들립니다. STP는 링크를 물리적으로 끊는 대신 일부 포트를 논리적으로 막아서 루프 없는 트리 구조를 만듭니다. 평소엔 막아두고, 활성 링크가 죽으면 그 포트를 열어서 백업으로 씁니다. 스패닝 트리의 필수 조건 트리가 만들어지려면 아래 세 가지가 성립해야 합니다. 네트워크당 Root bridge 가 하나 있다. Root bridge가 아닌 모든 bridge는 Root port 를 하나씩 가진다. 세그먼트(링크)마다 Designated port 가 하나씩 있다. Root port는 Root bridge로 가는 가장 좋은 길 쪽 포트이고, Designated port는 각 링크에서 Root bridge 방향으로 프레임을 전달하는 포트입니다. 둘 중 어느 쪽도 못 된 포트는 막힙니다. Root bridge, Root port, Designated port는 어떻게 정해질까 스위치들은 기본값으로 2초마다 BPDU 를 주고받으면서 아래 순서로 우선순위를 비교합니다. 위 기준에서 결판이 나면 아래 기준은 보지 않아요. 누가 더 작은 Root BID 를 가지는가 Root bridge까지의 Path cost 가 누가 더 작은가 누구의 BID 가 더 낮은가 누구의 포트 ID 가 더 낮은가 BPDU는 이 정보를 주고받기 위한 프레임으로 Root BID, Root Path Cost, Sender BID, Port ID를 담고 있습니다. BID는 priority + MAC 주소 로 만들어집니다. priority가 낮은 쪽이 이기고, priority가 같으면 MAC이 낮은 쪽이 이깁니다. EOS의 기본 priority는 32768이고, Path cost는 링크 속도가 빠를수록 낮아요. 실습 vEOS13의 priority를 28672로 설정했습니다. 기본값(32768)보다 낮으니 vEOS13이 Root bridge로 선출됩니다. spanning-tree priority 28672 그림의 포트 역할(R은 Root port, D는 Designated port, A는 Alternate port)을 보면 이렇습니다. vEOS13 : Root bridge라서 모든 포트가 D입니다. vEOS14, vEOS15 : Root bridge와 직접 연결된 포트가 R이고, 반대쪽 포트는 D입니다. 오른쪽 아래 vEOS : Root bridge로 가는 경로가 vEOS14 쪽과 vEOS15 쪽, 두 개입니다. Root port는 하나만 가질 수 있어서 한 경로(Eth1)가 R이 되고, 나머지(Eth2)는 A로 막힙니다. 그림의 빨간 X가 막힌 지점이에요. 포트 상태 변화 STP 포트는 5가지 상태를 거칩니다. Disabled(비활성) : 포트에 문제가 있거나 shutdown된 상태입니다. Blocking(차단) : BPDU 수신만 하고 데이터 전송과 MAC 학습은 하지 않습니다. BPDU로 상태를 확인하면서 토폴로지 변화에 대비해요. Listening(청취) : Blocking 포트가 Root port나 Designated port로 선출되고 20초(max age)가 지나면 전환됩니다. 간접 링크 장애 기준이고, 직접 링크 장애라면 20초는 생략할 수 있어요. 아직 데이터 전송과 MAC 학습은 안 합니다. Learning(학습) : Listening 상태를 15초 유지하면 전환됩니다. 이때부터 MAC 정보를 받아서 MAC 테이블을 갱신하지만 데이터 전송은 아직입니다. Forwarding(전송) : Learning 상태를 15초 유지하면 전환됩니다. 이제부터 데이터 송수신이 가능해요. 어느 단계에 있든 차단 포트로 선정되면 바로 Blocking으로 가고, 포트가 shutdown되거나 문제가 생기면 Disabled로 넘어갑니다. 전부 거치면 20 + 15 + 15 = 50초 , 직접 링크 장애라서 max age 대기를 생략하면 30초 입니다. 그래서 총 convergence time이 30~50초예요. 알아두면 좋은 점 1. 위 타이머는 고전 STP(802.1D) 기준입니다. 장애가 나고 30~50초 동안 통신이 안 된다는 건 실무에서 꽤 깁니다. EOS는 rstp , mstp , rapid-pvst 모드를 지원하는데 모두 RSTP를 기반으로 해서 훨씬 빠르게 수렴해요. 그림에 나온 A(Alternate) 포트도 RSTP에서 쓰는 역할 이름입니다. 2. Root bridge는 직접 정해두는 게 좋습니다. priority를 건드리지 않으면 MAC이 가장 낮은 장비가 Root bridge가 되는데, 오래된 액세스 스위치가 될 수도 있어요. 이번 실습처럼 백본(코어) 스위치에 낮은 priority를 주는 게 일반적입니다. EOS에는 spanning-tree root primary (priority 8192), secondary (16384)처럼 편하게 지정하는 명령도 있습니다. 3. 확인 명령어 show spanning-tree show spanning-tree instance detail 앞의 명령은 Root bridge와 포트 역할을, 뒤의 명령은 Hello time(2초), Max Age(20초), Forward Delay(15초) 같은 타이머를 확인할 때 씁니다. 정리 STP는 L2 루프를 막기 위해 Root bridge를 하나 정하고, 나머지 스위치마다 Root port, 세그먼트마다 Designated port를 정해서 나머지 포트를 막는 프로토콜입니다. BPDU를 주고받으며 Root BID, Path cost, BID, 포트 ID 순으로 비교하고, 포트는 Blocking에서 Forwarding까지 최대 50초에 걸쳐 올라옵니다.
Score: 54.4Confidence: 49%
Score: 54.4Confidence: 49%
Score: 54.4Confidence: 49%
Score: 54.4Confidence: 49%
Score: 54.4Confidence: 49%