참고) 데이터베이스 첫걸음, 기무라 메이지


정규형

칼럼을 정할 때 이상이 생기지 않도록 만드는 규칙

 

정규화

정규형을 만족하도록 릴레이션을 분해해나가는 것

 

아노말리

-삭제이상
200번학생이‘C123’ 과목을등록취소..200번학생의학년정보소실
-삽입이상
600번학생이2학년정보(투플)을삽입..불필요한정보(임시과목번호)를채워줘야함
-갱신이상
400번학생의학년을4->3로변경..4개의투플을모두갱신해야함

 

함수 종속

릴레이션이 변경되도 계속 지켜져야하는 의미적 관계(한 순간의 값으로 판단ㄴㄴ)

x(결정자)->y(종속자)

 

 

 

제1정규형: 하나의 셸에 복합적인 값을 포함하지 않는다

why? x에는 y가 대응하는 함수관계이기 때문에 기본키가 모든 열의 값을 하나로 특정할 수 있어야한다.

(1)처럼 칼럼을 추가->릴레이션 정의 변동이 많이 일어나서 성능 저하가 심함.

(2)->딩동댕

 

제2정규형: 제1을 만족하고, 기본키의 일부에만 종속하는 열이 없어야 한다 (==부분종속이 없어야한다)(기본키가 열이 하나라면 자동적으로 만족) 

why? 아래를 먼저 보자.

 

-기본키

cb,cb,cb가 중복되므로 [기업ID]만으론 기본키가 될 수 없다. 즉, [기업ID+주문번호]이다.

기본키를 정할 떈 의미적으로 거르고, 값으로 걸러서 정해야한다.

 

-존재하는 함수종속

[기업ID+주문번호]->[접수일]

[기업ID+주문번호]->[기업명]

[기업ID+주문번호]->[기업규모]

[기업ID]->[기업명]

[기업ID]->[기업규모]

 

여기서, 기본키의 일부인 [기업ID]에 종속되는 종속자 [기업명],[기업규모]가 있다. 

[기업명]과 [기업규모]열의 입장에서 보면, [주문번호]열음 쓸데없는 정보일 뿐이다. 

[주문번호] 열의 입장에서 보면, [기업규모]를 알지 못하면 데이터를 삽입할 수 없는 삽입이상이 생긴다. null허용은 썩 좋은 방법은 아니다.

 

그러므로, 기업ID만으로 기업명과 기업규모를 결정짓는 릴레이션으로  분해한다.

 

제3정규형: 제2를 만족하고, 기본키를 제외한 열에서 이행종속이 존재하지 않는다.

이행종속

기본키가 [a]일때, [b]->[c]라는 종속관계가 있으면 기본키 정의때문에 [a]->[b]가 성립되고, [a]->[b]->[c]가 되므로

[c]는 기본키[a]에 이행종속이다.

why?갱신이상이 여전히 존재하므로(참고로, 몇 정규화를 하면 무슨 이상은 완벽히 없어지고, 그런 경우는 없다. 단계가 높아질수록 이상이 생길 확률이 줄어드는 것 뿐이다). 아래를 보자.

 

제2를 만족하는 릴레이션에 업계코드,업계명을 추가

 

거래가 발생하지 않으면 기업의 업계코드와 업계명을 추가하고 싶어도 추가할 수 없다.

(ex거래한 업계는 석유,바이오와 했는데 업계종류를 화학도 추가하고 싶을떄..)

이런 경우, 업계코드와 업계명을 따로 빼서 분해한다.

 

주의 와 같은 경우는 이행종속이 아니다. 해당 종속관계의 종속자가 기본키이므로 제3정규형 정의와 관련없다.

 

BCNF: 릴레이션의 결정자가 모두 후보키여야만 한다

 

 

-존재하는 함수종속

[학번+과목]->[교수]

[교수]->[과목]

결정자는  [학번+과목],[교수] 총 두 가지가 존재한다.

[학번+과목]은 기본키이므로 후보키가 아니다.

[교수]는 키가 아니다. 그러므로 BCNF를 만족하지 않는다.

*제3을 만족하지 않는다고 실수할 수 있다. 교수와 과목은 이행종속이 아니다. 과목이 기본키이므로, 제3의 정의인 '기본키가 아닌 열이 기본키로부터 종속자'에 해당하지 않기 떄문이다. 

 

 

 

 

 


정규화를 많이 하면 테이블 수가 늘어난다

->테이블 간의 관계성을 파악하기 힘들다

->ER다이어그램을 그린다.

 

정규화를 많이하면 테이블 수가 늘어난다

->조인을 할 확률이 높다

->성능이 낮아진다/대신, 아노말리는 적다

 

 

 

 

 

제5정규화까지 있지만 실무에선 제3정규화까지만 하면 된다

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

키의 종류와 관계

'Basic > Database' 카테고리의 다른 글

트랜잭션-동시성제어,회복  (0) 2022.10.03
트랜잭션  (0) 2020.01.30
Issue: 오라클 노트북 두 개에 설치해서 db 공유 (IP의 이해)  (0) 2020.01.02
Index(인덱스)  (0) 2019.12.17
NoSQL  (0) 2019.12.10

*hadoop 2.0 기준* 


#빅데이터 청년인재 2기

#부산정보산업진흥원 하둡기반 빅데이터 처리

# https://www.slideshare.net/KeeyongHan/hadoop-introduction-10

# https://cskstory.tistory.com/entry/%EB%A7%B5%EB%A6%AC%EB%93%80%EC%8A%A4-MapReduce-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0


사전지식

빅데이터 분석 프로세스

 

RDBMS와 NRDBMS의 차이

 

RDBMS)관계형 데이터베이스다. 그래서 관계가 깨지면 의미가 없어지므로 데이터 무결성이 중요하고, 무결성을 위해서 스키마로 데이터 입력을 거르는 것이다. 하지만 이렇게 하면 입력되지 않는 데이터가 발생한다. 대표적 문법으로 sql

 

NRDBMS)비관계형 데이터베이스다. 위와 다르게 스키마가 없다. 예를 들어서, char의 길이를 10까지 할당할 수 있을 때 길이11의 char가 들어오면 할당 가능 길이를 11로 동적으로 바꿔준다(?).  하지만, 기존 데이터에서 수정을 하려면 모든 데이터를 다시 만들어야해서 (?) 사용성이 떨어진다. 대표적 문법으로 Nosql(Not only sql)

 

하둡은 NRDBMS를 기반으로 한다. 

텍스트 데이터 위주였던 과거와 달리, 이미지와 영상과 같은 비정형 데이터들이 급격히 증가하기 때문에 그것을 처리하는 것이 많이 연구되고 있다.

 

분산파일시스템

컴퓨터 네트워크를 통해 공유하는 여러 호스트 컴퓨터의 파일에 접근할 수 있게 하는 파일 시스템이다. 

네트워크를 통해 접근하는 파일들은 프로그램과 사용자의 하나의 로컬 디스크에 있는 파일처럼 다룰 수 있다.

 

즉, 서버증설시 스케일아웃이 되는데

스케일아웃은 저렴한 서버를 여러대 쓰기 때문에 비용이 저렴하고, 장애가 생기더라도 전체가 마비되지 않는다.

하지만, 분산해서 처리하기 때문에 관리 편의성이 떨어진다. (병렬적인 처리:웹 앱, 분산처리 등에 쓰임)

 

스케일업은 하나의 서버를 비싼 것으로 맞춰두고 더 필요하면 더 좋은 하드웨어를 계속 달아가는 것이다. 관리에는 편하지만 비용증가의 부담이 크고 확장에는 한계가 있다. 또한, 일부가 마비되면 전체가 마비될 수 있다.

 


일괄처리방식(batch),실시간 시스템

일괄처리방식) 일정 기간마다 주기적으로 한꺼번에 업무 처리...Hadoop ..why?)

실시간시스템)  작업 수행이 요청되었을 때, 이를 제한된 시간안에 처리해 결과를 내주는 것

 

 


소개

 

 

아파치 하둡대량의 데이터를 처리할 수 있는 큰 컴퓨터 클러스터에서 동작하는 분산 응용 프로그램을 지원하는 프리웨어 자바 소프트웨어 프레임워크이다. 분산처리 시스템인 구글 파일 시스템을 대체할 수 있는 하둡 분산 파일 시스템(HDFS)과 분산처리시스템(MapReduce)를 구현한 것이다.

 

배경

2006년 야후에서 일하던 더그 커팅이 구글 분산파일시스템에 대응하는 무료 라이브러리를 개발하고자 했고, 개발된 이후 아파치 재단으로 넘어가 관리되는 중이다.

 

 

구조

 

HDFS와 맵리듀스

 

+namenode~datanode부분 글씨 너무 작아서...

->통신으로 3초마다 heartbeat 체크. 에러나면 그 노드 버리고 다른 노드로 블록 복사한다.

 

 

클라이언트가 파일을 쓰려면, 먼저 파일을 로컬에 저장한다.

만약 파일크기가 정했던 블록 크기를 넘으면 Namenode를 만나고, Namenode는 블록이 저장될 시작위치와 간격(Datanode사이의)을 클라이언트에게 전달함. 클라이언트는 받은 데이터노드 첫부분부터 차례로 저장되고, 이 과정을 replication pipelining이라 함.

 

 

클라이언트가 파일을 읽으려면, Namenode에게서 블록ID를 받아내서 읽는다. (블록 크기 넘으면 ID를 여러개 받는다)

 

 

 

클라이언트가 하둡 잡 실행을 요청하면 하나의 잡 요청(맵리듀스코드 jar파일,입력위치,출력위치 등)을 JobTracker가 받고, 그

매퍼와 리듀스들을 TaskTracker에서 나누어준다. 

 

이 과정을 하둡 웹 인터페이스로 확인할 수도 있다.

 

 

 

 

 

 

 

맵리듀스의 동작과정

분산처리방식, 연속적인 작업을 나눠서 처리한다는 것부터 작업의 부분 부분이 서로 종속성이 없다는 것을 뜻한다

그 대표적인 경우를 txt파일에서 어떤 단어의 카운트를 하는 것이라고 할 수 있다.

txt파일에서 서로 연관성이 없기 때문에 파일을 나눠 가지고 각각의 카운트를 한 뒤에 취합해서 총 합을 구해주면 된다.

여기서, 각각의 카운트를 하는 과정:맵리듀스의 매퍼 역할

총 합을 구하는 과정: 맵리듀스의 리듀스 역할

위의 그림이 일련의 과정이다. 왼쪽에서 오른쪽으로 갈수록 맵의 크기가 작아지므로, 맵리듀스라고 부른다. 

맵리듀스 알고리즘은 가장 단순하게 만들어야한다. 그래야 수많은 서버에 흩어서 병렬로 처리할 수 있기 때문이다. 처리의 순서가 중요하다든지 실패했을때 다시하려면 몇단계 전으로 돌아가야 하는 상황은 있어서 안된다. 즉, 기준이 되는 값은 하나여야 한다.(이 말 매우 격공...알고리즘 풀 때 자꾸 예외에서 걸리는걸 느끼고 모든 경우를 고려하려면 단순해야 한다는걸 느낀 적이 있지)

 

자세한 설명은 아래 링크를..

https://cskstory.tistory.com/entry/%EB%A7%B5%EB%A6%AC%EB%93%80%EC%8A%A4-MapReduce-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

 

맵/리듀스 (Map/Reduce) 이해하기

빅데이터를 접하기 시작하면서 자주듣게 되는 용어가 있습니다. 맵/리듀스 라는 용어인데요, MR이라고도 많이 쓰구요, 빅데이터 처리에는 늘 맵리듀스 개념이 들어가죠. 그럼, 빅데이터 처리의 기본이되는 맵리듀..

cskstory.tistory.com

 

구성

-HDFS (공통 패키지)

-MaReduce (공통 패키지)

-OS level abstraction (공통 패키지)

-하둡 에코시스템(관련 패키지)

-Jar file

-하둡 구동 스크립트

 

 

 


확장

취사선택해서 아키텍쳐 구성하면 된다.(대신 릴리즈 호환성이 문제될 수 있으니 주의!)

 

 

취사선택해서 아키텍쳐 구성하면 된다.(대신 릴리즈 호환성이 문제될 수 있으니 주의!)

 

 

 

 

 

 

 

 

 

 

 

장점,쓰이는 곳

-오프라인 배치 프로세싱에 최적화

-소수의 비싼 서버보다 다수의 저렴한 서버 이용 가능

-데이터의 지역성을 최대한 이용함

-병렬도 높은 처리: Text Grep,Web Crawling..

-로그분석

-머신러닝:Search Ranking..

 

단점,주의할 점

-소규모이거나 대용량(페타바이트급) 처리가 필요하지 않으면 옮길 이유 없음

-스킬셋으로 가진 사람 드물고 서포트 부실

-추가는 가능하지만 수정은 파일전체 새로 써야함 (그래서 상용으로는 못쓰고 분석,시각화로만 쓴다)

-실시간 처리 불가


이 기술에 관한 고찰

-SPARK와의 비교

스트리밍 데이터 처리 가능과 불가능의 차이. 하지만 스파크도 결국 하둡 파일시스템을 쓰고  각각 다른 것이지

어느 것이 좋다고 비교할 수 없다. 스파크는 ram에서 돌리고 하둡은 애초에 ram에 올리기 너무 커서 느려도 디스크에서(?) 작업하되 병렬처리를 하는 것이기 때문이다. 매우매우 크지 않으면 스파크를 쓰는 것이 유연하다고 생각이 든다. 

더보기

데이터스택스(DataStax) 커뮤니티 관리자 스콧 헐맨 역시 "막대한 데이터를 포함한 대규모 분석은 앞으로도 계속 사용될 것이므로 일괄 처리는 사라지지 않을 것"이라면서, "스트리밍 분석에 대한 관심도 크지만 이 추세가 빅데이터의 미래에 미칠 영향에 대해 판단하기는 너무 이르다"고 말했다.

간단히 말해 스트리밍 분석(streaming analytics)은 '추가'일뿐, '양자 택일'의 문제가 아니다. 따라서 하둡과 같은 일괄 처리 지향 시스템을 시장에서 몰아내는 것이 아니라 보완하는 기술이 될 가능성이 높다.

 

-버전 1과의 비교

노드 다 올라오는거 확인하고 env파일 하나하나 안써도 되는거

 

'Skill > ETC' 카테고리의 다른 글

오픈소스 AI 온라인 교육 과정 [공개SW의 이해]  (0) 2020.04.14
깃허브 필수 내용  (0) 2020.01.22

*참고: http://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-isa-ko-4/s1-memory-concepts.html#S2-MEMORY-VIRT-SIMPLE*

*디맨드 페이징을 쓴다는 가정하에 포스팅*

What?

,실제 주기억장치보다 큰 메모리 영역을 제공하기 위해 운영체제가 제공하는 논리메모리이다. 

보조기억장치에 존재하며, 프로세스의 주소공간 중에서 필요한 부분만 가지고 있다. (이전편 참고)

또한, 캐시의 기능을 하며(논리메모리만 검색하면 됨) 공유메모리를 가능하게 한다.(어떻게?)

 

더보기

이 어플리케이션의 기계 코드 용량은 10000 바이트라고 가정해봅시다. 또한 데이터 저장 및 입/출력 버퍼에 5000 바이트가 필요하다고 가정합니다. 이러한 경우 이 어플리케이션을 실행하기 위해서는 최소한 15000 바이트의 RAM이 필요합니다. 만일 1 바이트라도 부족하다면 이 어플리케이션을 실행할 수가 없습니다.

하지만 메모리 접근은 순차적이고 지역화되어 있다는 내용을 다시 생각해보십시오. 이러한 특성으로 때문에 이 어플리케이션을 실행하는데 필요한 메모리 용량은 15000 바이트 보다 훨씬 적습니다. 단독 기계 명령어를 실행하기 위해 필요한 메모리 접근 방식을 예를 들어 보겠습니다:

  • 메모리에서 명령을 읽어옵니다.

  • 명령어가 필요로하는 데이터를 메모리에서 읽어옵니다.

  • 명령이 완료된 후 결과가 메모리에 다시 기록됩니다.

매번 메모리에 접근하는데 필요한 실제 바이트 수는 CPU 아키텍쳐 및 실제 명령어와 데이터 유형에 따라 달라집니다. 그러나 한 명령어를 실행하는데 각 메모리 접근 유형마다 100 바이트의 메모리가 필요하다고 가정해본다면 이 경우에는 300 바이트가 필요합니다. 즉 어플리케이션의 전체 15000 바이트 주소 공간을 사용하는 것보다 훨씬 적은 메모리 용량을 사용합니다. 따라서 만일 어플리케이션 실행시 필요한 메모리 요건을 기억할 수 있는 방법을 찾을 수가 있다면, 어플리케이션의 주소 공간 보다 적은 메모리를 사용하여 어플리케이션을 실행하는 것이 가능합니다.

어플리케이션의 나머지는 디스크에 남습니다.

Issue?

ex.

필요한 페이지만 실제메모리에 올려두고

아닌 페이지는 디스크(스왑아웃)로 보내두고

페이지 테이블엔 invalid 표시해둔다.(디맨드 페이징이라서 그럼)

 

접근할 때, invalid라면 페이지 폴트 난 것이므로

IO작업(커널도움)으로 디스크에서 가져와야한다.

(이것이 바로 소프트웨어 인터럽트!)

 

IO작업은 굉장히 느리므로

페이지폴트가 나는 횟수가 성능 좌우. 

 

즉,page 교체시 교체할건지 잘 골라야함.

(Optimal algorithm)

 

 

 

 

Solving?

 

 

 

 

 

 

 

 

 

OPT: 가장 먼 미래에 어떤 페이지 참조하는지 알고 있다는 가정하에, 그 페이지를 교체

but 이건 알고 있어야되기 때문에 실제에선 미래보단 과거를 본다

 

FIFO: 가장 일찍 들어온 것을 가장 먼저 내보낸다.

but 프레임 커질수록 폴트 더 발생(왜?..혹시 갯수가 늘어나면 그만큼 확률도 떨어져서 그런가)

 

LRU(Least Recently Used):제일 오래전에 사용한거를 내쫒는다

->FIFO랑 다른 점은 먼저 들어왔어도 재사용 됐으면 안쫓아낸다는 사실이다//이 방법 젤 많이 쓴다

->링크드리스트로 처음 들어오면 밑에 달고, 뺼 때는 젤 위에꺼 뺸다.비교 필요 없다. O(1)

but 이번에 한번만 들어오고 앞으로 안들어올 애를 두고, 꾸준히 많이 들어오는 애를 보낼수도.

 

LFU(Least Frequntly Used): 가장 참조횟수가 적은 페이지 순으로 내쫓는다.

->O(n)...heap으로 구현해서 O(logn)에 가능.

but 이제 많아지려는애를 쫓아낼수도

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

밑에 정리 필요

더보기

캐슁환경;한정된 빠른공간에 요청된 데이터 저장해 뒀다가 후속요청시 캐쉬로부터 직접 서비스하는 방식

페이징의 TLB,캐쉬,버퍼,웹(얘는 단일시스템 아니고 다른 시스템에서 가져옴. 내 컴터에서 저장된걸로 보여줌)

swap)페이징의 캐쉽 적용 환경

file)캐쉬(cpu와 메인메모리 사이)의 적용환경

 

사실 lru,lfu는 버퍼랑 웹캐싱에만 쓰이지 페이징에는 안됨.

폴트 발생해서 새로 올라가면 접근시간 알 수 있어도 이미 있는 경우라면 참조만 해가기 때문에 정보 모름.

lru비슷하게 구현한 알고리즘이 클락 알고리즘임.

 

할당은 어떻게 잘 해두나?  [사진]

ㄴ사실 lru.lfu같은 알고리즘 쓰면 알아서 조절되긴한다. (글로벌 리플레이스 활용)

<->로컬리플레이스(자신에게 할당된 프레임 내에서만 리플레이스..자기몫 나눠주고 알아서 바꿔써라)

 

+뭐가 더 좋을까?

 

폴트 너무 자주나면~~>Thrashing: 

 

막는 알고?

워킹셋 알고리즘)

 

 

 

 

 

 

 

 

환영합니다!

메모리 관리

컴퓨터에는 여러가지 메모리가 있다. 먼저 요약해서 그 관계를 얘기하자면, Disk(보조기억장치)에서 실행파일을 가상메모리에 올리고 페이지로 나눈다. 탐색시 보조디스크가 아닌 논리메모리만 탐색해서 필요한 페이지를 물리메모리에 적재시키고, 페이지테이블을 사용해서 그 순서를 기억한다.  

 

이 그림에 disk는 나와있지 않다

 

1.물리주소:주기억장치의 실제 저장위치 주소

2.가상메모리:보조기억장치를 주기억장치처럼 주소지정 가능하게 만든 저장공간 방법.

3.논리주소(가상주소):가상 메모리의 특정 위치에 배정된 주소 .각 프로세스 가상주소공간에서 0번지부터 시작. cpu가 보는 주소

4.가상주소공간:특정 프로세스에게 할당된 가상 주소의 영역

5.주소공간:특정 프로세스가 접근할 수 있는 메모리 주소의 영역

3.심볼릭 주소: 프로그래머 편의를 위한 변수

 

심볼릭 주소->컴파일->논리주소->주소바인딩->물리주소 과정을 거쳐서 메모리에 접근할 수 있다.

논리주소를 물리주소로 변환하는 바인딩 종류는 세 가지가 있다. 

 

컴파일타임바인딩:

논리주소에서 정한 주소를 물리주소에서 그대로 사용하기 때문에, 프로그램 쓰면 빈공간을 찾아서 쓰지 않으므로 비효율적이다.

 

로드타임바인딩:

롸?//논리주소에서 계산해서 사용

 

런타임바인딩:

cpu를 뺏겨 메모리에서 나갔다가 들어올때 마다 주소가 바뀐다.(하드웨어 mmu가 지원이 필요하고 현대에 채택함)

 

 

cpu는 논리주소를 사용한다. 즉, cpu가 준 논리주소를 mmu가 물리주소로 변환을 해서 메모리에 접근하는 것이다. 이 과정을 바인딩이라고 한다.

더보기

cpu가 논리주소만 볼 수 밖에 없는 이유??

컴파일을 하고나서 실행파일을 cpu가 읽는데, 파일한 환경과 파일을 실행할 환경이 다른 경우, 실제 메모리값을 미리 알 수 없으므로 당연히 논리주소를 사용하여야 한다.

 

 

mmu는 하드웨어 장치로서, 

접근하는 메모리 실제 주소=

가상주소공간의 0번쨰 논리주소에 해당하는 물리주소+cpu가 준 논리주소.

 

이때, 지정된 범위 벗어나는지 검사하는 소프트웨어 인터럽트가 존재한다.

 

 

 

 

 

 

 

 

 

 

 

 

주메모리에 접근해서 프로세스 주소공간이 배치된다. 

-연속배치(각 프로세스가 메모리에 연속적으로 배치)

-불연속배치(하나의 프로세스가 메모리에 나눠져서 배치 됨,현대):페이징,세그멘테이션

-고정분할(사용자메모리 영역을 미리 파티션으로 나눠둠 ):페이징

-가변분할(미리 나눠두지 않고 들어오는대로 받아들임):세그멘테이션

 

 

 

 

 

 

불연속 방법 종류

 

고정분할방식 가변분할방식
같은 크기든 다른 크기든 메모리를 미리 파티션으로 나눠둠 미리 나눠두지 않고 들어오는대로 배치한다
크기가 맞는 것이 나올때까지 건너뛰므로 외부단편화 발생 먼저 수행을 마친 프로세스가 나가서 중간에 외부단편화 발생
할당된 공간에 비해 필요한 공간이 작으면 내부단편화 발생 처음부터 필요한만큼 크기 할당받으므로 내부단편화는 없다

 

단편화 해결방법:(바인딩을 많이 해야되서 비용이 많이 들고 주소가 계속 바뀌므로 런타임바인딩이 지원되야 함)

 

배치전략

1.first fit:사이즈가 n이상인 것중 처음 발견되는 것

2.best fit:가장 갭이 작은 홀로

3.worst fit: 가장 큰 홀로(장기적으로 안좋다..더 큰 프로세스 왔을때 써야하는데..)

 

 

 

스와핑: 메모리에서 cpu우선순위 낮은 프로세스를 디스크로 쫓아내거나 불러오는 것.(중기스케줄러)

 

더보기

롸?//동적로딩(동적:필요할 때마다 쓴다 ,로딩: 메모리에 올리는 것):

개발자가 방어적인 코드(예외처리코드)처럼 자주 쓰지 않는 코드를 명시적으로 나타내서 필요할 때만 부름.

+어떤거?

 

동적링킹(링킹:내가 사용하는 라이브러리 등의 코드를 실행할 때 코드로 붙여주는 것 동적:필요할 때마다):

static linking-컴파일하면 내 코드에 그 코드들이 추가가 된다.

dynamic linking-파일로 라이브러리에 코드있고 그 주소로 가는 거만 저장해둬서 필요할 때 그 동작만 수행

ㄴ이래서 printf함수 입출력 함수 쓰면 오래 걸린다는거구나..

 

오버레이:

 

 


페이징

불연속 배치-페이징 

 

 

What? 

주메모리에서 사용하기 위해 2차 기억 장치로부터 데이터를 저장하고 검색하는 메모리 관리 기법이다.

 

How?

가상메모리를 모두 같은 크기의 페이지로 나누고 페이지는 같은 크기로 주메모리로부터 프레임을 할당받아서 적재된다.

인덱스로 바로 접근할 수 있는 페이지 테이블을 가지고 있다.

 

페이지 주소와 offset으로 이루어진 키값 테이블.

p,d => p페이지 d번째라는 뜻

(페이지 테이블에서 p에 해당하는 물리주소 f를 찾아서 d만큼 떨어진 실제주소를 찾는다.)

 

 

 

Where?

캐시에 넣기엔 너무 크고,에 넣기엔 빠르게 주소변환 해야하는데 부적절해서 메모리에 넣는다...

즉,

주메모리에 2번 접근한다<-속도 높이기 위해서 TLB(캐시역할하는 테이블,메인메모리와 cpu사이 하드웨어로 존재) 쓴다.

 

 

 

 

 

 

더보기

32bit에선 주소를 2^32까지 표현할 수 있다. 2^30은G이므로 4G.

이때, 주소 하나당 한 페이지인데 한 페이지는 최대 4K이므로

프로그램은 최대 4G/4K=100만개의 페이지로 구성되어 있다. 

페이지테이블의 엔트리가 4바이트이므로 프로세스마다 4메가의 페이지테이블이 필요하게 되어 메모리 공간이 낭비된다. 

 

2단계 페이지 테이블!

속도는 줄어들지 않아도

공간은 줄어든다. 

 

->비효율->2단계로 가자~~

->근데 2단계 페이지테이블까진 몬하게따 힘들다

 

프로세스가 공유하는 코드 있으면 메모리에 하나만 올림.

(shared code=pure code)<-read only여야함. ipc통신의 쉐어드 메모리랑은 다른 것

 

 

 

 

 

 

 

 

 

 


세그멘테이션

 

What? 

주메모리에서 사용하기 위해 2차 기억 장치로부터 데이터를 저장하고 검색하는 메모리 관리 기법이다.

 

How?

가상메모리를 의미적인 세그먼트로 나눈다.

(sharing하거나protection)

 

 

페이징은 크기 고정되어있지만 세그먼트는 가변적이므로 프로세스 초기위치 말고도 limit이 필요하다.limit 연산 시 할당크기 넘는다하면

할당 안함. 

 

 

 

 

페이징 세그멘테이션

엔트리에 권한값을 부여해 페이지마다

read only/write등을 달아줘야한다.

의미단위라 그런 문제는 없고
allocation문제가 발생하지 않는다. allocation문제가 발생할 수 있다.
테이블에 의한 메모리 낭비는 페이징이 더 크다.  
페이징은 갯수 알 수 있는데 갯수 추측 못함.

내부단편화 있고(페이지보다 작으면 무조건 발생)

외부단편화는 불연속이라서 없다

내부단편화는 없지만 외부단편화는 있다 

 

 

+새그맨트~페이지 섞어서 쓰기도..

+프로세스의 메모리 접근시 cpu가 바로 접근 가능. but IO장치 접근할때만 커널도움 받음.

 

1)한줄요약 : 멜론과 같은 음원 결제 및 다운로드 사이트를 제작

 

2)본인 역할 : 프로젝트리더.선행개발 및 본 개발로 MVC구조에 기반한 웹 서버 구조 설계 및 개발.

+선행개발: 검색 가능한 웹화면, 로그인,파일업로드 기능같이 부수적인 것들 미리 제작. Jsp와 BLOB 자료형 사용.

+팀원:ㄱㄱㅂ,ㅂㅊㅁ

 

3)본인이 사용한 스킬 : Java,Oracle Database,Spring,Jsp

+팀원스킬: JAVA,Oracle Database,Spring

 

4)힘들었던 점:  기술 이해의 불균형. 개발기간이 5일이어서 곧바로 분업했지만 수업에 완전히 참석하지 못한 팀원들이 이해에 어려움을 겪었다.

->2일이라도 스터디 제안,스터디에 가기 전 최대한 많은 내용을 공부하고 팀원의 이해를 도울 수 있는 자료를 만듬.

 

 

[주제를 정하기 위해서 SWOT 분석을 활용]

[구조도]

Main - 사용자가 원하는 기능을 선택하면 필요한 Controller의 메소드를 호출한다.

Controller - 각 기능에 필요한 서비스를 호출하고 관리한다.

Service

- UserServise : 사용자메뉴에 필요한 서비스를 포함한다.

- MusicService : 음원서비스에 필요한 서비스를 포함한다.

DAO

- UserRepository : 사용자 서비스에 필요한 insert,delete,find를 포함한다.

- MusicRepository : 음원 서비스에 필요한 insert,delete,find를 포함한다.

Database - 사용자데이터를 userdata에, 음원데이터를 musicdata에 저장한다.

 

[흐름도]

[본개발 시연 (DI구조를 선행개발과 합치지 못해서 콘솔창 구현)]

 

 

 

[주요 코드]

 

package com.watermelon.controller;

 

 

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.context.support.GenericXmlApplicationContext;

import org.springframework.jdbc.core.JdbcTemplate;

 

 

import com.watermelon.dao.IRepository;

 

 

public class RepositoryController {//   ICustomerService custService = new CustomerService();

       public IRepository repository;

       //AbstractApplicationContext context=new GenericXmlApplicationContext("application-config.xml");

       public RepositoryController(IRepository repository) {

          this.repository = repository;

       }   //원래는 여기서 서비스 선택해야됨

      

       public void run_insert() {

         repository.insert();

       }

}

 

package com.watermelon.dao;

public interface IRepository//같은 리포지터리로 많이 만들거니까 인터페이스

       void insert();

       void update();

       void print();

       void delete();

}

 

package com.watermelon.dao;

 

 

import java.util.Scanner;

 

 

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.context.support.GenericXmlApplicationContext;

import org.springframework.jdbc.core.JdbcTemplate;

import com.watermelon.model.Artist;

 

 

public class ArtistRepository implements IRepository//실체화된 리포지터리

    Scanner scan = new Scanner(System.in);

    //AbstractApplicationContext context = new GenericXmlApplicationContext("application-config.xml");

    JdbcTemplate jdbcTemplate;

    @Override

    public void insert() {

        System.out.print("번호 : ");

        int artist_num = scan.nextInt();

        System.out.print("이름 : ");

        String name = scan.next();

        System.out.print("날짜 : ");

        String create_date = scan.next();

        System.out.print("점수 : ");

        int score = scan.nextInt();

        Artist a = new Artist(artist_num, name, create_date, score);

        String sql = "insert into artist (artist_num, name, create_date, score)" + "values ('" + artist_num + "','"

                + name + "','" + create_date + "','" + score + "')";

        jdbcTemplate.update(sql);  //모델인 테이블에서 가져올거임

    }

    public void update() {

    }

    public void print() {

    }

    public void delete() {

    }

    public void setMethod(JdbcTemplate jdbcTemplate) {

        this.jdbcTemplate = jdbcTemplate;

    }

}

package com.watermelon.main;

 

 

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.context.support.GenericXmlApplicationContext;

import org.springframework.jdbc.core.JdbcTemplate;

 

 

import com.watermelon.dao.ArtistRepository;

 

 

public class WatermelonMain {

    public static void main(String[] arg) {

        AbstractApplicationContext context = new GenericXmlApplicationContext("application-config.xml");  //컨테이너 등록

        ArtistRepository a = context.getBean(ArtistRepository.class);  //컨테이너에선 손쉽게 생성하고 빈객체까지 취할수있음

        a.setMethod(context.getBean("jdbcTemplate",JdbcTemplate.class));  //jdbc도 빈객체로 설정되있을때 a빈객체에 넣어서 해당 과정 수행한다. 

        a.insert();  //사실 여기 메인에선 컨트롤러 만들어서 걔가 컨테이너 만들어서 위의 두줄 넣고 빈빼서 실행해야됐음

        }

}

 

<?xml version="1.0" encoding="UTF-8"?>

 

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

       <!-- The definition of the Root Spring Container shared by all Servlets and  Filters -->

       <context-param>

              <param-name>contextConfigLocation</param-name>

              <param-value>/WEB-INF/spring/root-context.xml</param-value>

       </context-param>

       

       <!-- Creates the Spring Container shared by all Servlets and Filters -->

       <listener>

              <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

       </listener>

       <!-- Processes application requests -->

       <servlet>

              <servlet-name>appServlet</servlet-name>

              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

              <init-param>

                     <param-name>contextConfigLocation</param-name>

                     <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>

              </init-param>

              <load-on-startup>1</load-on-startup>

       </servlet>

              

       <servlet-mapping>

              <servlet-name>appServlet</servlet-name>

              <url-pattern>/</url-pattern>

       </servlet-mapping>

</web-app>

 

//그리고 위처럼 음악파일도 똑같이 만들어서 뷰 파일로 결과 보내줘야함. jsp든 서블릿이든. 즉, 뷰와 컨트롤러 부분을 못만든 것이다.

 

 

 

[선행개발-논리적 데이터 모델]

 

 

 

[선행개발 시연]

 

 

[주요 코드]

 

메인 jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"

    pageEncoding="EUC-KR"%>

    <%@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>

http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">

<title>Insert title here</title>

</head>

<body>

<script language='javascript'>

function wrong_input(){

       alert("잘못된 정보를 입력하셨습니다.");

       history.back();

}

function no_exist_result(){

       alert("원하시는 결과가 없습니다");

       history.back();

}

</script>

<%

       Context ctx = new InitialContext();

       DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/sec");

       Connection conn = ds.getConnection();

       String keyword = request.getParameter("keyword");

       

       if (keyword == null) {

              %><script>

              wrong_input();

              </script>

              <%

       }

       String sqlQuery = "select * from attachment where file_name='";

       sqlQuery +=keyword;

       sqlQuery += "'";

       System.out.println("SQL: "+sqlQuery);

       PreparedStatement ps =conn.prepareStatement(sqlQuery);

       ResultSet rs = ps.executeQuery();

       

       while(rs.next()){

              %>

              <tr> <li><td><a href="file_down.jsp?file_id=<%=rs.getInt("id")%>">

                   <td><%=rs.getString("file_name")%>

              

              </tr>

              <%

         }

         //예외처리 만들어줘야     

       conn.commit();

       rs.close();

       ps.close();

       conn.close();

       %>

</body>

</html>

 

파일업로드 jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"

    pageEncoding="utf-8"%>

    <%@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>

<!DOCTYPE >

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">

<title>Upload files</title>

</head>

<body>

<script language='javascript'>

function wrong_input(){

       alert("로그인 하셔야죠!");

       window.location.href="login.html"; //history.back();

}

</script>

<%

String user_id=request.getParameter("user_id");

System.out.println(user_id);

if(user_id.equals("null"))

{%>

       

       <scripts>

       wrong_input();

       </scripts><%

}%>

    <div style="padding:5px; color:red;font-style:italic;">

       ${errorMessage}

    </div>

    

    <h2>Upload Files</h2>

    <form method="post" action="${pageContext.request.contextPath}/uploadToDB"

        enctype="multipart/form-data">

        

        Select file to upload:

        <br />

        <input type="file" name="file"  />

        <br />

        <input type="file" name="file" />

        <br />

        Description:

        <br />

        <input type="text" name="description" size="100" />

        <br />

        <br />

        <input type="submit" value="Upload" />

    </form>

</body>

</html>

 

 

클릭한 파일 다운로드

<%@ page language="java" contentType="text/html; charset=EUC-KR"

    pageEncoding="EUC-KR"%>

http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">

<title>Insert title here</title>

</head>

<body>

<%

String file_id=request.getParameter("file_id");

String str="http://localhost:8080/WaterMelon/downloadAttachment?id=";

str+=file_id;

System.out.println(str);

response.sendRedirect(str);

%>

<script>

              wrong_input();

</script>

</body>

</html>

 

BLOB 자료형으로 파일 클래스

import java.sql.Blob;

public class Attachment {

    private Long id;

    private Blob FileData;

    private String FileName;

    

    public Attachment(Long id,Blob FileData, String FileName) {

        this.id = id;

        this.FileData = FileData;

        this.FileName = FileName;

    }

    public Long getId() {

        return id;

    }

    public void setId(Long id) {

        this.id = id;

    }

    public Blob getFileData() {

        return FileData;

    }

    public void setFileData(Blob FileData) {

        this.FileData = FileData;

    }

    public String getFileName() {

        return FileName;

    }

    public void setFileName(String FileName) {

        this.FileName = FileName;

    }

}

 

 

 

import java.io.IOException;

import java.io.InputStream;

import java.sql.Blob;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

 

 

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.sql.DataSource;

 

 

@WebServlet("/downloadAttachment")

public class DownloadAttachmentServlet extends HttpServlet {

   private static final long serialVersionUID = 1L;

   @Override

   protected void doGet(HttpServletRequest request, HttpServletResponse response)  //다운로드는 빨라야 돼

           throws ServletException, IOException {

       Connection conn = null;

       try {

           // Get Database Connection.

           // (See more in JDBC Tutorial).

 

 

           Context ctx = new InitialContext();

           

            DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/sec");

           

            conn = ds.getConnection();

            conn.setAutoCommit(false);

 

 

           Long id = null;

           try {

               id = Long.parseLong(request.getParameter("id"));

           } catch (Exception e) {

           }

           Attachment atc = getAttachmentFromDB(conn, id);

           if (atc == null) {

               // No record found.

               response.getWriter().write("No data found");

               return;

           }

           // file1.zip, file2.zip

           String fileName = atc.getFileName();

           System.out.println("File Name: " + fileName);

           // abc.txt => text/plain

           // abc.zip => application/zip

           // abc.pdf => application/pdf

           String contentType = this.getServletContext().getMimeType(fileName);

           System.out.println("Content Type: " + contentType);

           response.setHeader("Content-Type", contentType);

           response.setHeader("Content-Length", String.valueOf(atc.getFileData().length()));

           response.setHeader("Content-Disposition", "inline; filename=\"" + atc.getFileName() + "\"");

           // For big BLOB data.

           Blob fileData = atc.getFileData();

           InputStream is = fileData.getBinaryStream();

           byte[] bytes = new byte[1024];

           int bytesRead;

           while ((bytesRead = is.read(bytes)) != -1) {

               // Write image data to Response.

               response.getOutputStream().write(bytes, 0, bytesRead);

           }

           is.close();

       } catch (Exception e) {

           throw new ServletException(e);

       } finally {

           this.closeQuietly(conn);

       }

   }

   private Attachment getAttachmentFromDB(Connection conn, Long id) throws SQLException {  

       String sql = "Select a.Id,a.File_Name,a.File_Data,a.Description "//

               + " from Attachment a where a.id = ?";

       PreparedStatement pstm = conn.prepareStatement(sql);

       pstm.setLong(1, id);

       ResultSet rs = pstm.executeQuery();

       if (rs.next()) {

           String fileName = rs.getString("File_Name");

           Blob fileData = rs.getBlob("File_Data");

           String description = rs.getString("Description");

           return new Attachment(id, fileData, description);

       }

       return null;

   }

   private void closeQuietly(Connection conn) {

       try {

           if (conn != null) {

               conn.close();

           }

       } catch (Exception e) {

       }

   }

}

 

 

 

import java.io.IOException;

import java.io.InputStream;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

 

 

import javax.naming.Context;

import java.sql.*;

import javax.sql.*;

import javax.naming.InitialContext;

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.annotation.MultipartConfig;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.Part;

import javax.sql.DataSource;

 

파일 업로드 DB 연동 클래스

@WebServlet("/uploadToDB")

@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, // 2MB

        maxFileSize = 1024 * 1024 * 10, // 10MB

        maxRequestSize = 1024 * 1024 * 50) // 50MB

public class UploadToDBServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override

    protected void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher("/WebContent/uploadToDB.jsp");

        dispatcher.forward(request, response);

    }

    @Override

    protected void doPost(HttpServletRequest request, HttpServletResponse response) //올리는건 ㄷ ㅓ신중히

            throws ServletException, IOException {

        Connection conn = null;

        try {

            // Connection to Database

            // (See more in JDBC Tutorial).

   

            Context ctx = new InitialContext();

            

            DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/sec");

            

            conn = ds.getConnection();

            conn.setAutoCommit(false);

            String description = request.getParameter("description");

            // Part list (multi files).

            for (Part part : request.getParts()) {

                String fileName = extractFileName(part);

                if (fileName != null && fileName.length() > 0) {

                    // File data

                    InputStream is = part.getInputStream();

                    // Write to file

                    this.writeToDB(conn, fileName, is, description);

                }

            }

            conn.commit();

            // Upload successfully!.

         

            response.sendRedirect(request.getContextPath() + "/uploadToDBResults");

           

            

        } catch (Exception e) {

            e.printStackTrace();

            request.setAttribute("errorMessage", "Error: " + e.getMessage());

            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/WebContent/uploadToDB.jsp");

            dispatcher.forward(request, response);

        } finally {

            this.closeQuietly(conn);

        }

    }

    private String extractFileName(Part part) {

        // form-data; name="file"; filename="C:\file1.zip"

        // form-data; name="file"; filename="C:\Note\file2.zip"

        String contentDisp = part.getHeader("content-disposition");

        String[] items = contentDisp.split(";");

        for (String s : items) {

            if (s.trim().startsWith("filename")) {

                // C:\file1.zip

                // C:\Note\file2.zip

                String clientFileName = s.substring(s.indexOf("=") + 2, s.length() - 1);

                clientFileName = clientFileName.replace("\\", "/");

                int i = clientFileName.lastIndexOf('/');

                // file1.zip

                // file2.zip

                return clientFileName.substring(i + 1);

            }

        }

        return null;

    }

    private Long getMaxAttachmentId(Connection conn) throws SQLException {

        String sql = "Select max(a.id) from Attachment a";

        PreparedStatement pstm = conn.prepareStatement(sql);

        ResultSet rs = pstm.executeQuery();

        if (rs.next()) {

            long max = rs.getLong(1);

            return max;

        }

        return 0L;

    }

    private void writeToDB(Connection conn, String fileName, InputStream is, String description) throws SQLException {

        String sql = "Insert into Attachment(Id,File_Name,File_Data,Description) " //

                + " values (?,?,?,?) ";

        PreparedStatement pstm = conn.prepareStatement(sql);

        Long id = this.getMaxAttachmentId(conn) + 1;

        pstm.setLong(1, id);

        pstm.setString(2, fileName);

        pstm.setBlob(3, is);

        pstm.setString(4, description);

        pstm.executeUpdate();

    }

    private void closeQuietly(Connection conn) {

        try {

            if (conn != null) {

                conn.close();

            }

        } catch (Exception e) {

        }

    }

}

 

 

 

 

 

 

 

 

'Project' 카테고리의 다른 글

[툰츄]  (0) 2019.11.06
[부귀영화-영화 추천 서비스]  (0) 2019.10.25
[Hearable App-청각장애인용 스마트 앱]  (3) 2019.10.25
[MARK- 길건너기 2D 게임]  (0) 2019.10.25
[hearable watch-청각장애인용 스마트 워치]  (0) 2019.10.25

+ Recent posts