Python+Flask 액세스 속도 최적화, ElasticSearch+Redis 캐싱 전략 튜닝
2023-03-17 · 1342 · 1 min
# 머리말
[이 사이트] (https://tstrs.me)를 구축 할 때 ElasticSearch를 데이터베이스 Redis를 캐시 구성 요소로 사용했는데 처음에는 문제없이 사용하다가 버전 반복, 모듈 추가 및 지속적인 페이지 개선으로 인해 사용되었습니다. 많은 곳의 데이터를 Redis로 채워야 하고, 심지어 일부 페이지도 수십 또는 수백 번 쿼리해야 하므로 로딩 속도가 느려지고 시스템 부하가 증가합니다. 이 항목에서는 웹 사이트 버그를 수정하고, 시스템 로드를 최적화하고, 캐시 정책을 조정하는 데 중점을 둡니다.
# 시스템 모듈 소개
본문 내용
처음에는 오래된 블로그 게시물을 새 시스템으로 가져올 계획이 없었기 때문에 새 페이지 링크 형식, 즉 '\result\article ID'를 디자인했습니다.이 ID는 고유하고 길이가 20 비트로 고정되어 있기 때문에 캐싱 시스템에서 디자인 한 KV (Key-Value Pair)는 기사 ID : 기사 내용입니다.
hXia44YBlyC2E8nCuWW5:[기사 내용]
이것의 장점은 매우 간단하고 빠르며, 기사가 캐시되었는지 여부를 쿼리해야 할 때 ID를 직접 확인할 수 있으며, 그렇지 않은 경우 데이터베이스에 드롭된 다음 Redis에 던져집니다.
추천 도서
나중에 [추천 도서]가 페이지 측면에 추가되어 처음에는 ElasticSearch 인기도 쿼리를 사용하다가 인기도 목록이 기본적으로 변경되지 않고 의미가 없다고 느꼈기 때문에 임의 반환으로 변경되어 새로 고칠 때마다 변경되었습니다. 그러나 ElasticSearch에 대한 모든 쿼리는 느리기 때문에 무작위로 키를 반환 할 수있는 Redis의 randomkey 기능을 사용하고 키를 기반으로 기사의 세부 정보를 얻습니다.
우선, 여기에서 추천하는 내용은 반복 할 수 없으며, 둘째, 내 웹 사이트는 영어와 중국어로 이중 언어를 사용하기 때문에 중국어 페이지에서 항상 영어 기사를 추천 할 수는 없으며 그 반대의 경우도 마찬가지입니다.
그래서 이 모듈에서는 while 루프를 사용했는데, 총 10개의 항목을 쿼리한 후 즉시 반환하여 언어가 본문 내용과 일치하는지 여부를 확인하고, 일관성이 있는 경우 카운트가 10에 도달할 때까지 +1을 더하고 계산합니다. 어떤 사람들은 이해하지 못할 수도 있습니다, 다음은 모듈 코드의이 부분입니다, 언어에 대한 L을 입력하십시오 :
'''자바
def getrandomkeyredis (l) : #随机获取文章
idlist = []#id
rawinfolist = []#详细内容
동안 len(rawinfolist) < 11:#直到列表大于11停止
onepagesid = str(pagecache.randomkey(), 'utf-8')#从redis 데이터 반환 및 바이트-문자열 데이터를 임의로 가져옵니다.
idlist에 onepagesid 없다면 :#不在列表内
pcs = getpc(onepagesid) #获取文章详情
if pcs['언어'] == l :#语言一致
a = {['문서 세부 정보']}#构造返回
rawinfolist. 부록 (a) #将构造好的返回打包到组里面
idlist. 부가onepagesid #计数
반환 rawinfo_list
우선, 여기에 언어가 있는 이유는 이 데이터를 사용할 수 있는지 여부를 알기 위해 매번 쿼리해야 하고, 각 쿼리에 대한 구성 반환을 완료하는 데 30-40배가 걸리지만, 그렇다고 해도 ElasticSearch를 직접 사용하는 것보다 빠릅니다.
### 다른 걸 봐
이제 기사 페이지 하단에 "다른 것을 보세요"를 추가했는데, 이는 사이드바와 다르며 카드 스타일입니다. 그리고 그 당시에는 편리하고 빠르게하기 위해 사이드 바는 '이름, 링크, 시간, 인기도'의 4 개 필드 만 반환하고 '미리보기 이미지, 소개'라는 두 개의 필드가 더 있었는데 별도의 모듈을 만들었지 만 코드 부분은 기본적으로 몇 가지 변경 사항만으로 동일했습니다.
![](https://pic.saltyleo.com/i/17108282981.webp)
인터페이스가 보기 좋고 콘텐츠가 풍부하지만 쿼리가 너무 많아 각 페이지는 기본적으로 출력하는 데 80-100ms가 필요하며 이는 용납할 수 없으며 잦은 IO 읽기 및 쓰기로 인해 시스템이 지연되어 액세스 속도 자체가 더 느려집니다.
그것은 내가 전에 팠던 구멍이며, 최근에 모든 것을 최적화했습니다. 솔루션 아이디어와 실제 코드는 아래에서 공유됩니다.
## 버그 해결
우선, 이 문제는 전체 아키텍처가 후속 버전 반복의 요구 사항을 따라갈 수 없으며 이 문제를 해결하기 위해 일부 핵심 모듈을 리팩토링해야 한다는 사실로 귀결됩니다. 이와 관련하여 테이블을 직접 들어 올려 다시 참여 시켰는데, 이전 코드를 최적화하는 대신 혼란을 빠르게 잘라내어 리팩토링하는 것이 좋습니다.
기사 세부 정보 페이지 측면에 있는 10개의 기사와 하단에 있는 6개의 기사를 기반으로 총 16개의 정보 세트를 만들었습니다. ElasticSearch 데이터베이스에서 해당 언어에 대한 16개의 임의 반환을 직접 가져오고 각 반환은 '이름, 링크, 시간, 인기도, 미리보기 지도, 소개'와 같은 6개의 레코드만 가져와 메모리를 절약합니다. 쿼리 코드는 다음과 같습니다.
es.search(index="why", body={"query":{"bool":{"must":{"multimatch":{"query":'tttt',"fields":['so']}},"filter":{"match":{"language":l}} ,"mustnot":{"match":{"edit":' 편집 '}}}}},"from":0,"size":16,"sort": {"_script": {"script": "Math.random()","type": "number"}}})
사람의 말로 번역하면 [L이 있는 데이터베이스의 쿼리 언어와 편집되지 않은 기사를 제공하고 16개의 데이터를 무작위로 반환합니다]입니다. 쿼리의 'tttt'는 내가 설정 한 일반 쿼리 매개 변수입니다. 언어 문제를 근본적으로 해결하기 위해 쿼리 시간을 낭비하지 않기 위해 중국어와 영어 Redis 라이브러리를 직접 분리했습니다.
위의 쿼리 내용을 현재 사용하고 있는 키 키인 Redis에 작성하면 어차피 필요하지 않고 유일한 키만 필요합니다.
def setrdm(l): #给redis添加一组缓存, 해당 언어에 해당
l == 'zh'인 경우:
zhrdmcache.set(round(time.time()),json.dumps(esact.random(l)),ex=3600)
elif l == 'en':
enrdmcache.set(round(time.time()),json.dumps(esact._random(l)),ex=3600)
또한 읽기가 매우 간단하며 다음 코드를 사용하여 해당 언어로 권장 읽기를 읽을 수 있습니다.
def getrdm(l): 해당 언어에 해당하는 #从 redis에서 임의 반환 집합을 가져옵니다.
l == 'zh'인 경우:
반환 json.loads(zhrdmcache.get(zhrdmcache.randomkey()))
elif l == 'en':
반환 json.loads(enrdmcache.get(enrdm_cache.randomkey()))
```
이 작업 후 각 페이지는 본문을 한 번만 쿼리하고 임의의 권장 사항을 쿼리하면 되며 총 시간 소비는 기본적으로 10ms 이내일 수 있습니다.
# 포스트 스크립트
따라서 간단할수록 속도가 빠르고 성능이 낭비되기 쉬우며 성능이 뛰어난 서버에서는 큰 변화를 느끼지 못할 수 있지만 구성이 낮은 서버에서는 약간의 최적화가 큰 개선을 가져올 수 있습니다.