>  기사  >  데이터 베이스  >  Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

青灯夜游
青灯夜游앞으로
2019-02-26 10:09:222103검색

이 글의 내용은 Redis의 지속성 및 마스터-슬레이브 복제 메커니즘을 소개하는 것입니다. 이는 특정 참조 가치가 있으므로 도움이 될 수 있습니다.

Redis 지속성

Redis는 다양한 수준에서 다양한 지속성 방법을 제공합니다.

RDB 지속성은 지정된 시간 간격 내에서 데이터 세트의 특정 시점 스냅샷을 생성할 수 있습니다.

AOF는 모든 쓰기를 지속적으로 기록합니다. 서버가 실행하는 작업 명령을 다시 실행하고, 서버 시작 시 해당 명령을 다시 실행하여 설정된 데이터를 복원합니다. AOF 파일의 모든 명령은 Redis 프로토콜 형식으로 저장되며, 파일 끝에 새로운 명령이 추가됩니다. Redis는 AOF 파일의 크기가 데이터 세트 상태를 저장하는 데 필요한 실제 크기를 초과하지 않도록 백그라운드에서 AOF 파일을 다시 작성할 수도 있습니다.

Redis는 AOF 지속성과 RDB 지속성을 동시에 사용할 수도 있습니다. 이 경우 Redis가 다시 시작되면 AOF 파일을 사용하여 데이터 세트를 복원하는 데 우선 순위가 부여됩니다. 왜냐하면 AOF 파일에 저장된 데이터 세트는 일반적으로 RDB 파일에 저장된 데이터 세트보다 더 완전하기 때문입니다.
서버가 실행되는 동안에만 데이터가 존재하도록 지속성을 끌 수도 있습니다.

RDB (Redis DataBase)

Rdb: 지정된 시간 간격 내에 메모리에 있는 데이터 세트의 스냅샷을 디스크에 기록하며, 이는 전문 용어로 스냅샷이기도 합니다. 메모리에 직접.

Redis는 지속성을 위해 별도의 하위 프로세스를 생성(포크)합니다. 먼저 데이터를 임시 파일에 씁니다. 지속성 프로세스가 완료된 후 이 임시 파일은 마지막으로 지속된 파일을 대체하는 데 사용됩니다. 전체 프로세스에서 메인 프로세스는 IO 작업을 수행하지 않으므로 매우 높은 성능을 보장합니다. 대규모 데이터 복구가 필요하고 데이터 복구의 무결성이 그다지 중요하지 않은 경우 RDB 방법이 AOF 방법보다 효율적입니다. .고효율. RDB의 단점은 마지막 지속성 이후의 데이터가 손실될 수 있다는 것입니다.

포크는 현재 프로세스와 동일한 프로세스를 복사하는 것입니다. 새로운 프로세스의 모든 데이터(변수, 환경 변수, 프로그램 카운터 등)는 원래 프로세스와 동일한 값을 가지지만, 완전히 새로운 프로세스이며 원래 프로세스의 하위 역할을 합니다. 프로세스

숨겨진 위험: 현재 프로세스에 많은 양의 데이터가 있는 경우 포크 * 2 이후의 데이터 양은 서버와 운영 성능을 저하시킵니다.

Rdb는 dump.rdb 파일을 저장합니다.

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

테스트 중: flashAll 명령을 실행하고 shutdownDown을 사용하여 프로세스를 직접 닫을 때 redis는 dump.rdb 파일이 열릴 때 자동으로 읽습니다. 두 번째는 복구되지만 모두 비어 있습니다. (이유: 종료 시 Redis 시스템은 원래 캐시 파일을 대체하기 위해 빈 dump.rdb를 저장합니다. 따라서 Redis 시스템이 두 번째 열릴 때 빈 값 파일을 자동으로 읽습니다.)

RDB 저장 작업

Rdb는 전체 메모리의 압축된 스냅샷입니다. RDB 데이터 구조는 스냅샷 트리거 조건을 충족하도록 구성할 수 있습니다. 기본값은 1분에 10,000개 변경이며, 또는 15분마다 한 번씩. ;
저장 비활성화: RDB 지속성 전략을 비활성화하려면 저장 지침을 설정하지 않거나 빈 문자열 매개변수를 전달하여 저장하세요.

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

------> save 명령: 작업 개체를 즉시 저장합니다.

RDB 스냅샷을 실행하는 방법

저장: 저장할 때만 저장하고, 다른 것은 무시하고, 모두 차단합니다.

Bgsave: redis는 스냅샷 작업 중에 클라이언트 요청에 응답할 수도 있습니다. lastsave 명령을 통해 마지막으로 성공한 스냅샷 실행 시간을 얻을 수도 있습니다.

fluhall 명령을 실행하면 dump.rdb 파일도 생성되지만 비어 있습니다.

복원 방법:

백업 파일(dump.rdb)을 Redis 설치 디렉터리로 이동하고 서비스를 시작합니다.
디렉토리를 가져오기 위해 get dir 명령을 구성합니다.

중지 방법

동적으로 중지하는 방법 RDB 저장 규칙 : redis -cli config set save ""

AOF(Append Only File)

은 각 쓰기 작업을 로그 형식으로 기록하고, redis가 실행하는 모든 쓰기 명령을 기록합니다(읽기 작업은 기록되지 않음). 파일만 추가할 수 있지만 다시 쓸 수는 없습니다. redis가 시작되면 파일을 읽어 데이터를 재구성합니다. 즉, redis가 다시 시작되면 로그 내용에 따라 쓰기 명령이 앞에서 뒤로 실행됩니다. 파일을 복구하여 데이터 복구 작업을 완료하세요.
======APPEND ONLY MODE======

Enable aof: 추가 전용 yes(기본값은 no)

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

참고:

실제 작업 및 프로덕션에서 aof 파일 손상이 자주 발생합니다( 네트워크 전송 또는 기타 문제로 인해 aof 파일이 손상될 수 있습니다)

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개

서버가 시작되고 오류가 보고됩니다(그러나 dump.rdb 파일은 완료됨). 시작 시 aof 파일이 먼저 로드되었음을 나타냅니다.

# 🎜🎜#해결책: redis- check-aof --fix aof file 명령 실행 [aof 구문과 일치하지 않는 필드를 자동으로 확인 및 삭제]

Aof strategy

# 🎜🎜#

Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개# 🎜🎜#

Appendfsync 매개변수:

Always 동기 지속성. 즉시 디스크에 기록됩니다. 성능은 좋지 않지만 데이터 무결성은 상대적으로 낮습니다. Everysec: 공장 기본 권장 사항, 비동기 작업, 1초마다 녹화, 1초 후 다운타임, 데이터 손실

No: fsync 안 함: 처리를 위해 데이터를 운영 체제에 넘겨줍니다. 더 빠르고 덜 안전한 옵션입니다.



Rewrite

개념: AOF는 파일 추가를 사용하므로 파일이 점점 더 커집니다. 이런 일이 발생하면 aof 파일의 크기가 설정된 임계값을 초과하면 redis는 자동으로 aof 파일의 내용을 압축하고 데이터를 복원할 수 있는 최소 명령 세트를 유지할 수 있습니다. bgrewirteaof 명령을 사용하십시오.

다시 쓰기의 원리: aof 파일이 계속해서 커지고 커지면 파일을 다시 쓰기 위해 새로운 프로세스가 포크됩니다(즉,

은 임시 파일을 먼저 쓰고 그 다음 이름 바꾸기), 프로세스의 메모리에 있는 데이터의 경우 각 레코드에는 set 문이 있습니다. aof 파일을 다시 쓰는 작업은 이전 aof 파일을 읽지 않지만 전체 메모리 데이터베이스 내용을 새 파일로 다시 씁니다. 명령을 사용합니다.aof 파일은 스냅샷과 다소 유사합니다.

트리거 메커니즘: redis는 마지막으로 다시 쓴 aof의 크기를 기록합니다. 마지막으로 다시 쓴 후 aof 파일 크기가 두 배가 되고 파일이 64M(3G)보다 크면 기본 구성이 트리거됩니다.#🎜 🎜#

no-appendfsync-on-rewrite no: 다시 쓸 때 Appendfsync를 사용할 수 있나요? 데이터 보안을 보장하려면 기본 no를 사용하세요.

auto-aof -rewrite -percentage 벤치마크 값을 배수로 설정Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개auto-aof-rewrite-min-size 벤치마크 값 크기 설정



AOF 장점

# 🎜🎜#AOF 지속성을 사용하면 Redis의 내구성이 매우 높아집니다. fsync 없음, 매초마다 fsync 또는 쓰기 명령이 실행될 때마다 fsync와 같은 다양한 fsync 전략을 설정할 수 있습니다. AOF의 기본 정책은 초당 한 번씩 fsync하는 것입니다. 이 구성에서 Redis는 여전히 좋은 성능을 유지할 수 있으며, 오류가 발생하더라도 최대 1초의 데이터만 손실됩니다. (fsync는 백그라운드 스레드에서 실행됩니다. 따라서 메인 스레드는 계속해서 명령 요청을 열심히 처리할 수 있습니다. AOF 파일은 추가 작업만 수행하는 로그 파일(로그만 추가)이므로 로그에 어떤 이유로 기록되지 않은 파일이 포함되어 있어도 AOF 파일에 쓸 때 검색이 필요하지 않습니다. -check-aof 도구를 사용하면 이 문제를 쉽게 해결할 수도 있습니다.

Redis는 AOF 파일 크기가 너무 커지면 백그라운드에서 AOF를 자동으로 다시 작성할 수 있습니다. 다시 작성된 새 AOF 파일에는 현재 데이터 세트를 복원하는 데 필요한 최소 명령 세트가 포함되어 있습니다. Redis는 새 AOF 파일을 생성하는 과정에서 계속해서 기존 AOF 파일에 명령을 추가하므로 전체 재작성 작업은 절대적으로 안전합니다. 재작성 프로세스 중에 종료가 발생하더라도 기존 AOF 파일은 손실되지 않습니다. . 새 AOF 파일이 생성되면 Redis는 이전 AOF 파일에서 새 AOF 파일로 전환하고 새 AOF 파일에 추가하기 시작합니다.

AOF 파일은 데이터베이스에서 수행되는 모든 쓰기 작업을 Redis 프로토콜 형식으로 저장하므로 AOF 파일의 내용을 매우 쉽게 읽을 수 있습니다. 분석(파싱)도 쉽습니다. AOF 파일 내보내기(내보내기)도 매우 간단합니다. 예를 들어 실수로 FLUSHALL 명령을 실행했지만 AOF 파일을 덮어쓰지 않은 경우 서버를 중지하고 AOF 끝에서 FLUSHALL 명령을 제거합니다. 파일을 저장하고 Redis를 다시 시작하면 FLUSHALL이 실행되기 전의 상태로 데이터 세트를 복원할 수 있습니다.

AOF 단점

동일한 데이터 세트의 경우 일반적으로 AOF 파일의 양이 그보다 큽니다. of RDB 파일의 크기입니다. 사용된 fsync 전략에 따라 AOF는 RDB보다 느릴 수 있습니다. 일반적인 상황에서 초당 fsync 성능은 여전히 ​​매우 높으며, fsync를 끄면 로드가 심한 경우에도 AOF가 RDB만큼 빨라질 수 있습니다. 그러나 RDB는 대규모 쓰기 로드를 처리할 때 더 보장된 최대 지연 시간을 제공할 수 있습니다.

AOF에는 과거에 이러한 버그가 있었습니다. 특정 명령으로 인해 AOF 파일을 다시 로드하면 데이터 세트를 저장했을 때의 원래 상태로 복원할 수 없습니다. (예를 들어 BRPOPLPUSH 차단 명령으로 인해 이러한 버그가 발생한 적이 있습니다.)

이 상황을 위해 테스트 모음에 테스트가 추가되었습니다. 테스트는 무작위의 복잡한 데이터 세트를 자동으로 생성하고 다시 로드하여 모든 것이 제대로 작동하는지 확인합니다. AOF 파일에서는 이런 종류의 버그가 흔하지 않지만, 이에 비해 RDB에서는 이런 종류의 버그가 거의 불가능합니다.

Redis 데이터 백업

데이터베이스를 꼭 백업하세요!

디스크 오류, 노드 오류 및 기타 문제로 인해 데이터가 사라질 수 있습니다. 백업하지 않는 것은 매우 위험합니다.

Redis는 서버가 실행되는 동안 RDB 파일을 복사할 수 있기 때문에 데이터 백업에 매우 친숙합니다. RDB 파일이 생성되면 수정이 이루어지지 않습니다. 서버가 새 RDB 파일을 생성하려고 하면 먼저 파일 내용을 임시 파일에 저장합니다. 임시 파일이 작성되면 프로그램은 rename(2)을 사용하여 원본 RDB 파일을 임시 파일로 자동으로 바꿉니다.

이는 언제든지 RDB 파일을 복사하는 것이 절대적으로 안전하다는 것을 의미합니다.

권장 사항:

정기 작업(cron 작업)을 만들어 매시간 RDB 파일을 폴더에 백업하고 매일 RDB 파일을 다른 폴더에 백업하세요.

스냅샷 백업에 해당 날짜 및 시간 정보가 있는지 확인하세요. 일반 작업 스크립트를 실행할 때마다 find 명령을 사용하여 만료된 스냅샷을 삭제하세요. 예를 들어 지난 48시간 동안의 시간별 스냅샷을 보관하거나 지난 한두 달의 일일 스냅샷입니다.

적어도 하루에 한 번 데이터 센터 외부 또는 적어도 Redis 서버를 실행 중인 물리적 머신 외부에 RDB를 백업하세요.

재해 복구 및 백업

Redis의 재해 복구 백업은 기본적으로 데이터를 백업하고 이러한 백업을 여러 외부 데이터 센터로 전송하는 것을 의미합니다.

재난 복구 백업은 Redis가 실행되고 스냅샷을 생성하는 메인 데이터 센터에 심각한 문제가 발생하더라도 데이터를 안전한 상태로 유지할 수 있습니다.

일부 Redis 사용자는 기업가이므로 낭비할 돈이 많지 않으므로 다음은 실용적이고 저렴한 재해 복구 백업 방법입니다.

Amazon S3 및 S3와 유사한 기타 서비스는 다음과 같습니다. 재해 백업 시스템을 구축합니다. 가장 쉬운 방법은 시간별 또는 일일 RDB 백업을 암호화하여 S3로 전송하는 것입니다. 데이터 암호화는 gpg -c 명령(대칭 암호화 모드)을 사용하여 수행할 수 있습니다. 비밀번호를 여러 가지 안전한 장소에 보관하는 것을 잊지 마세요. 예를 들어 조직에서 가장 중요한 사람들에게 비밀번호를 복사할 수 있습니다. 여러 스토리지 서비스를 사용하여 동시에 데이터 파일을 저장하면 데이터 보안이 향상될 수 있습니다.

SCP(SSH의 구성 요소)를 사용하여 스냅샷 전송을 수행할 수 있습니다. 다음은 간단하고 안전한 전송 방법입니다. 데이터 센터에서 멀리 떨어진 VPS(Virtual Private Server)를 구입하고 SSH를 설치하고 비밀번호 없는 SSH 클라이언트 키를 생성한 다음 이 키를 VPS의 Authorized_keys 파일에 추가하면 스냅샷 백업이 완료됩니다. 파일을 이 VPS로 전송할 수 있습니다. 최고의 데이터 보안을 위해 재해 복구를 위해 최소 두 곳 이상의 다른 공급자로부터 VPS를 구입하세요.

이러한 유형의 재해 복구 시스템은 주의 깊게 다루지 않으면 쉽게 실패할 수 있다는 점에 유의해야 합니다.

최소한 파일 전송이 완료된 후에는 전송된 백업 파일의 크기가 원본 스냅샷 파일의 크기와 동일한지 확인해야 합니다. VPS를 사용하는 경우 파일의 SHA1 체크섬을 비교하여 파일이 완전히 전송되었는지 확인할 수도 있습니다.

또한 백업 파일 전송을 담당하는 전송(전송)이 실패할 경우 이를 알려주는 독립적인 경보 시스템도 필요합니다.

Redis 마스터-슬레이브 복제

Redis는 간단하고 사용하기 쉬운 마스터-슬레이브 복제 기능을 지원하므로 슬레이브 서버가 마스터 서버의 정확한 복사본이 될 수 있습니다.

다음은 Redis 복제 기능에 대한 몇 가지 중요한 측면입니다.

Redis는 비동기 복제를 사용합니다. Redis 2.8부터 슬레이브 서버는 복제 스트림의 처리 진행 상황을 초당 한 번씩 마스터 서버에 보고합니다.

마스터 서버에는 여러 개의 슬레이브 서버가 있을 수 있습니다.

마스터 서버가 슬레이브 서버를 가질 수 있을 뿐만 아니라, 슬레이브 서버가 자체 슬레이브 서버를 가질 수도 있습니다. 여러 슬레이브 서버가 그래프와 같은 구조를 형성할 수 있습니다.

복제 기능은 마스터 서버를 차단하지 않습니다. 하나 이상의 슬레이브 서버가 초기 동기화를 진행 중이더라도 마스터 서버는 계속해서 명령 요청을 처리할 수 있습니다.

복제 기능은 슬레이브 서버를 차단하지 않습니다. redis.conf 파일에 해당 설정이 지정되어 있는 한 서버는 슬레이브 서버가 초기 작업을 진행 중이더라도 이전 버전의 데이터 세트를 사용하여 명령 쿼리를 처리할 수 있습니다. 동기화.

단, 이전 버전의 데이터 세트가 서버에서 삭제되고 새 버전의 데이터 세트가 로드되는 기간 동안에는 연결 요청이 차단됩니다.

마스터 서버와의 연결이 끊어지면 클라이언트에 오류를 보내도록 슬레이브 서버를 구성할 수도 있습니다.

복제 기능은 데이터 중복성을 위해서만 사용할 수도 있고, 여러 슬레이브 서버가 읽기 전용 명령 요청을 처리하도록 하여 확장성을 향상할 수도 있습니다. 예를 들어, 무거운 SORT 명령을 보조 노드에 부여하여 실행할 수 있습니다. .
복제 기능을 사용하면 마스터 서버가 지속성 작업을 수행하지 않도록 할 수 있습니다. 마스터 서버의 지속성 기능을 끄고 슬레이브 서버가 지속성 작업을 수행하도록 하세요.

메인 서버 지속성이 꺼지면 복제 기능의 데이터 보안이 보장됩니다.

Redis 복제 기능을 구성할 때 메인 서버의 지속성 기능을 켜는 것이 좋습니다. 그렇지 않으면 배포된 서비스가 대기 시간 및 기타 문제로 인해 자동으로 풀업되는 것을 방지해야 합니다.

Case:

  1. 노드 A가 메인 서버라고 가정합니다. 지속성은 꺼집니다. 그리고 노드 B와 노드 C는 노드 A

  2. 노드 A에서 데이터를 복사한 후 자동으로 서비스를 가져와 노드 A를 다시 시작합니다. 종료하므로 다시 시작하면 데이터가 없습니다

  3. 노드 B와 노드 C는 노드 A에서 데이터를 복사하지만 A의 데이터가 비어 있으므로 스스로 저장합니다. 데이터 사본이 삭제되었습니다.

메인 서버의 지속성을 끄고 동시에 자동 풀업 프로세스를 켜는 경우 Redis의 고가용성을 달성하기 위해 Sentinel을 사용하더라도 매우 위험합니다. 메인 서버가 너무 빨리 풀업되어 Sentinel이 구성된 하트비트 간격 내에 메인 서버가 다시 시작되었음을 감지하지 못할 수 있으므로 위의 데이터 손실 프로세스가 계속 수행됩니다.

데이터 보안은 항상 매우 중요하므로 메인 서버가 꺼졌을 때 자동으로 지속성을 가져오는 것을 금지해야 합니다.

슬레이브 서버 구성

슬레이브 서버 구성은 매우 간단합니다. 구성에 다음을 추가하기만 하면 됩니다. file 다음 줄은 다음과 같습니다:
slaveof 192.168.1.1 6379
또 다른 방법은 SLAVEOF 명령을 호출하고 주 서버의 IP와 포트를 입력한 다음
127.0 동기화를 시작하는 것입니다. 0.1:6379> ; SLAVEOF 192.168.1.1 10086
OK

읽기 전용 슬레이브 서버

# 🎜🎜 #From Redis 2 .6 초기에 슬레이브 서버는 읽기 전용 모드를 지원하며, 이 모드가 슬레이브 서버의 기본 모드입니다.

읽기 전용 모드는 redis.conf 파일의 슬레이브 읽기 전용 옵션으로 제어됩니다. 이 모드는 CONFIG SET 명령을 통해 켜거나 끌 수도 있습니다.

읽기 전용 슬레이브 서버는 쓰기 명령 실행을 거부하므로 작동 오류로 인해 실수로 슬레이브 서버에 데이터가 기록되는 일이 없습니다.

또한 슬레이브 서버에서 SLAVEOF NO ONE 명령을 실행하면 슬레이브 서버가 복제 기능을 끄고 슬레이브 서버에서 다시 마스터 서버로 전환됩니다. 폐기되어서는 안 된다.

"SLAVEOF NO ONE은 동기화된 데이터 세트를 삭제하지 않습니다" 기능을 사용하면 기본 서버에 장애가 발생하면 슬레이브 서버를 새로운 기본 서버로 사용할 수 있어 중단 없는 운영이 가능합니다.

슬레이브 서버 관련 구성:

마스터 서버가 requirepass 옵션을 통해 비밀번호를 설정한 경우 슬레이브 서버에서의 동기화 작업이 원활하게 진행될 수 있도록 슬레이브 서버에 대한 인증 설정도 이루어져야 합니다.

실행 중인 서버의 경우 클라이언트를 사용하여 다음 명령을 입력할 수 있습니다.

config set masterauth
이 비밀번호를 영구적으로 설정하려면 추가할 수 있습니다. 구성 파일:
masterauth

마스터 서버는 N개 이상의 슬레이브 서버가 있는 경우에만 쓰기 작업을 수행합니다.

Slave Redis 2.8부터 시작, 데이터 보안을 보장하기 위해 현재 연결된 슬레이브 서버가 N개 이상일 때만 쓰기 명령을 실행하도록 마스터 서버를 구성할 수 있습니다.

그러나 Redis는 비동기 복제를 사용하기 때문에 마스터 서버에서 보낸 쓰기 데이터가 슬레이브 서버에서 수신되지 않을 수 있으므로 데이터 손실 가능성은 여전히 ​​존재합니다.

이 기능의 작동 방식은 다음과 같습니다.

슬레이브는 서버에 초당 한 번씩 핑을 보내고 보고합니다. 복제 스트림 처리에 관한 것입니다.

마스터 서버는 각 슬레이브 서버가 마지막으로 PING을 보낸 시간을 기록합니다.

사용자는 구성을 통해 최대 네트워크 지연 min-slaves-max-lag와 쓰기 작업 min-slaves-to-write를 수행하는 데 필요한 최소 슬레이브 서버 수를 지정할 수 있습니다.

최소한 최소 슬레이브-쓰기 슬레이브 서버가 있고 이러한 서버의 지연 값이 min-slaves-max-lag 초보다 작으면 마스터 서버 클라이언트 요청 쓰기 작업을 실행합니다.

반면, min-slaves-to-write 및 min-slaves-max-lag에 지정된 조건을 충족하지 않으면 쓰기 작업이 실행되지 않으며, 주 서버는 쓰기 작업을 요청한 클라이언트가 오류를 반환했다고 보고합니다.

다음은 이 기능의 두 가지 옵션과 필수 매개변수입니다.

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

위는 이 기사의 전체 내용입니다. 모든 사람의 학습에 도움이 되기를 바랍니다. 더 흥미로운 내용을 보려면 PHP 중국어 웹사이트의 관련 튜토리얼 열을 주의 깊게 살펴보세요! ! !

위 내용은 Redis 지속성 및 마스터-슬레이브 복제 메커니즘 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 https://segmentfault.com/a/1190000012196599에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제