SpringBoot 프로젝트 에 서 는 Jedis 와 일반적인 설정 을 사용 합 니 다.
블 로그 주소:https://www.cnblogs.com/keatsCoder/p/12609109.html 전재 출처 를 밝 혀 주 십시오.감사합니다.
Redis 의 자바 클 라 이언 트 는 매우 많은 데 Jedis 는 그 중에서 사용 이 비교적 광범 위 하고 성능 이 비교적 안정 적 인 것 이다.또한 API 와 RedisAPI 이름 스타일 이 유사 하 므 로 사용 을 추천 합 니 다.
프로젝트 에 Jedis 도입
Maven 을 통 해 직접 도입 할 수 있 으 며,현재 최신 버 전 은 3.2.0 이다.
redis.clients
jedis
3.2.0
직접 연결 및 사용 연결 탱크
제 디 스 직 련
Jedis 를 도입 하면 프로젝트 는 new 방식 으로 Jedis 를 가 져 올 수 있 습 니 다.
@SpringBootTest(classes = RedisCliApplication.class)
@RunWith(SpringRunner.class)
public class JedisConnectionDemo {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private int port;
@Test
public void testConnection(){
//
Jedis jedis = new Jedis(host, port);
// key-value。 OK
String setResult = jedis.set("name", "keats");
Assert.assertEquals("OK", setResult);
// key value
String value = jedis.get("name");
Assert.assertEquals("keats", value);
//
jedis.close();
}
}
연결 풀 사용
연결 하면 매번 TCP 연결 을 새로 만 들 고 TCP 연결 을 끊 는 다.이 과정 은 시간 이 많이 걸 리 기 때문에 Redis 와 같은 빈번 한 접근 과 효율 적 인 접근 이 필요 한 소프트웨어 는 분명 적합 하지 않다.연결 관리 도 불편 하 다.데이터베이스 연결 풀 사상 과 유사 하 게 제 디 스 도 제 디 스 풀 연결 풀 을 제공 해 연결 풀 관 리 를 한다.모든 Jedis 대상 은 JedisPool 에 미리 놓 여 있 고 클 라 이언 트 가 사용 해 야 할 때 연못 에서 빌려 쓰 고 다 쓴 후에 연못 에 돌려 줍 니 다.이렇게 하면 TCP 연결 을 자주 구축 하고 끊 는 네트워크 비용 을 피 할 수 있 고 속도 가 매우 빠르다.또한 합 리 적 인 배 치 를 통 해 합 리 적 인 관리 연결 을 실현 하고 연결 을 분배 할 수 있다.
@Test
public void testConnectionWithPool(){
//
JedisPool jedisPool = new JedisPool(host, port);
Jedis jedis = jedisPool.getResource();
// doSomething
//
jedis.close();
}
마지막 으로 사용 하 는 close()방법 은 연결 을 닫 는 것 처럼 보이 지만 실제로 누 르 면 dataSource(연결 풀)가 비어 있 지 않 으 면 연결 을 되 돌려 주 는 방법 을 실행 할 수 있 습 니 다.
@Override
public void close() {
if (dataSource != null) {
if (client.isBroken()) {
this.dataSource.returnBrokenResource(this);
} else {
this.dataSource.returnResource(this);
}
} else {
client.close();
}
}
연결 탱크 에서 흔히 볼 수 있 는 문제
위 에서 연결 을 돌려 주 는 방법 에 문제 가 있 습 니까?임 무 를 수행 할 때 이상 신 고 를 하면 close()방법 을 수행 할 수 없 을 것 이 고 오 랜 시간 동안 연못 에 있 는 Jedis 연결 이 소 진 되 어 전체 서 비 스 를 사용 할 수 없 을 것 이 라 고 생각해 보 세 요.이 문 제 는 개발 과 테스트 환경 에서 쉽게 발견 되 지 않 지만 생산 환경 은 사용량 이 늘 어 나 면 드러난다.
JedisPool 의 기본 최대 연결 수 는 8 개 입 니 다.기본 으로 풀 에서 연결 을 가 져 오 는 시간 초과 시간 은-1 입 니 다.
연결 을 돌려 주지 않 는 오 류 를 보 여주 기 위해 다음 코드 를 썼 습 니 다.
@Test
public void testConnectionNotClose(){
//
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxWaitMillis(5000L); // Jedis
JedisPool jedisPool = new JedisPool(poolConfig, host, port);
try {
for (int i = 1; i <= 10; i++) {
Jedis jedis = jedisPool.getResource();
System.out.println(i);
// doSomething
}
} catch (Exception e) {
e.printStackTrace();
}
}
8 회 전 까지 풀 에서 연결 을 가 져 와 사용 하고 돌려 주지 않 습 니 다.9 번 째 때 연결 을 가 져 오 려 면 이미 없습니다.기본 적 인 상황 에서 기다 릴 겁 니 다.그리고 제 가 설정 을 변경 한 것 은 5S 입 니 다.5S 를 기다 리 면 오류 가 발생 합 니 다.오류 정 보 는 다음 과 같 습 니 다.
1
2
3
4
5
6
7
8
redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:51)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:99)
at cn.keats.rediscli.jedis.JedisConnectionDemo.testConnectionNotClose(JedisConnectionDemo.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:439)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:349)
at redis.clients.util.Pool.getResource(Pool.java:49)
... 32 more
잘못 을 보고 하 든 기다 리 든 생산 환경 에서 지연 되 는 것 과 다름없다.그 러 니까 이 조작 은 피해 야 돼.그럼 제 가 실행 코드 의 마지막 문장 에 close()를 쓰 면 안심 이 되 지 않 을까요?진지 하 게 앞에서 다 오 는 애 들 은 아니 라 고 할 거 야.코드 가 이상 하 게 나 오 면close()방법 을 실행 할 수 없습니다.
@Test
public void testConnectionWithException() {
//
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxWaitMillis(5000L); // Jedis
JedisPool jedisPool = new JedisPool(poolConfig, host, port);
for (int i = 1; i <= 8; i++) {
System.out.println(i);
try {
new Thread(() -> {
Jedis jedis = jedisPool.getResource();
// doSomething
//
int j = 1 / 0;
jedis.close();
}).run();
} catch (Exception e) {
// 8 , close
}
}
// 9
Jedis jedis = jedisPool.getResource();
}
이렇게 하면 위 와 같은 잘못 도 보고 할 수 있다.자바 7 이후 의 try with resources 쓰기 로 연결 반환 을 완료 하 는 것 을 추천 합 니 다.
try (Jedis jedis = jedisPool.getResource()) {
new Thread(() -> {
// doSomething
//
int j = 1 / 0;
jedis.close();
}).run();
} catch (Exception e) {
//
}
이렇게 하면 finally 를 쓴 셈 이다.정상적으로 실행/오류 가 발생 했 을 때 close()방법 으로 연결 을 닫 습 니 다.코드 에 순환 이 없 는 한
이렇게 쓰 면 또 하나의 단점 은 일부 동료 들 이 반환 을 잊 어 버 릴 수도 있다 는 것 이다.작 가 는 오래된 돈 으로 강제 반환 하 는 연결 탱크 관리 방법 을 소개 했다.
특수 한 사용자 정의 RedisPool 대상 을 통 해 JedisPool 대상 을 숨 기 고 프로그래머 가 getResource 방법 을 직접 사용 해서 반환 하 는 것 을 잊 지 않도록 합 니 다.프로그래머 가 RedisPool 대상 을 사용 할 때 리 셋 클래스 를 제공 해 야 Jedis 대상 을 사용 할 수 있 습 니 다.자바 8 의 Lambda 표현 식 을 결합 합 니 다.사용 해도 괜 찮 습 니 다.그러나 이 로 인해 패 킷 을 닫 는 문제 가 발생 했 고 람 다 의 익명 내부 클래스 는 외부 변수 에 접근 할 수 없습니다.그 는 또 방문 목적 을 달성 하기 위해 Hodler 를 사용 했다.사내 의 방법 은 매우 대단 하 다.그러나 개인 적 으로 이런 코드 의 복잡 도가 많이 높 아 졌 다.리 소스 를 사용 하고 돌려 주지 않 은 프로그래머 에 게 는 쓰기 가 복잡 할 수 있 습 니 다.그래서 블 로그 에 안 붙 였 어 요.관심 있 는 파트너 는 옛날 돈의 책 을 읽 거나 나의 GITHUB 에서 옛날 돈의 코드 를 찾 아 볼 수 있다.우아 한 Jedis-옛날 돈
연결 탱크 설정 상세 설명
연결 풀 을 기본 구조 로 초기 화 하 는 것 외 에 Jedis 는 설정 클래스 를 제공 하여 초기 화 합 니 다.
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxWaitMillis(5000L); // Jedis
JedisPool jedisPool = new JedisPool(poolConfig, host, port);
설정 클래스 에서 자주 사용 하 는 매개 변 수 는 다음 과 같 습 니 다.
매개 변수 이름
속뜻
기본 값
maxActive
연결 풀 의 최대 연결 수
8
maxIdle(minIdle)
연결 풀 의 최대(작은)남 은 연결 수
8(0)
maxWaitMillis
링크 풀 이 연결 되 지 않 았 을 때 호출 자의 최대 대기 시간,단 위 는 밀리초 입 니 다.기본 값 사용 을 권장 하지 않 습 니 다.
-1 기다리다
jmxEnabled
jmx 모니터링 시작 여부
minEvictableIdleTimeMillis
연결 의 최소 남 은 시간,이 값 에 도달 하면 남 은 연결 이 삭 제 됩 니 다.
1800000 L 30 분
numTestsPerEvictionRun
남 은 연결 검 사 를 할 때,매번 샘플링 수
3
testOnBorrow
연결 풀 에 연결 을 빌 릴 때 연결 유효성 검사(Ping)를 할 지 여부 가 잘못 되면 연결 이 삭 제 됩 니 다.
false
testOnReturn
주기 적 인 남 은 검사 할 지 여부
false
testWhileIdle
연결 풀 에 연결 을 빌 릴 때 남 은 검 사 를 할 지 여부 입 니 다.남 은 시간 이 초과 되면 삭 제 됩 니 다.
false
timeBetweenEvictionRunsMillis
남 은 연결 검사 주기,단 위 는 밀리초 입 니 다.
-1 검 사 를 안 해 요.
blockWhenExhausted
연결 탱크 자원 이 다 떨 어 졌 을 때 호출 자 는 기 다 려 야 합 니까?maxWaitMillis 와 대응 합 니 다.true 일 때 maxWaitMillis 가 적 용 됩 니 다.
true
PipeLine 은 한 번 에 여러 명령 을 수행 합 니 다.
Redis 는 mset,mget 등 방법 을 제 공 했 지만하지만 mdel 방법 은 제공 되 지 않 았 다.저 희 는 업무 중 에 mget 을 한 번 만난 후에 삭제 해 야 할 key 가 여러 개 있 으 면 PipeLine 을 통 해 mdel 을 모 의 할 수 있 습 니 다.비록 조작 은 원자 성 이 아니 지만 대부분 상황 에서 도 요 구 를 만족 시 킬 수 있다.
@Test
public void testPipeline() {
//
JedisPool jedisPool = new JedisPool(host, port);
try (Jedis jedis = jedisPool.getResource()){
Pipeline pipelined = jedis.pipelined();
// doSomething keys
List keys = new ArrayList<>();
// pipelined
for (String key : keys) {
pipelined.del(key);
}
//
pipelined.sync();
}
}
프로젝트 코드
레 디 스 를 공부 하 는 과정 에서 저 는 블 로그 의 코드 를 모두 Github 에 올 려 서 아이들 이 확인 할 수 있 도록 했 습 니 다.항목 주소:https://github.com/keatsCoder/redis-cli
참고 문헌
《Redis 개발 과 운 비》---부 레이 장 익 군
《Redis 심도 있 는 모험:핵심 원리 와 응용 실천》---돈 과 물품
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.