目次
はじめに
ルーティングアルゴリズム
単純なルーティングアルゴリズム
一貫性のあるハッシュ
一貫性のあるハッシュは完全ではなく、拡張中に負荷の不均衡を引き起こす可能性があります。最新バージョンでは仮想ノードの設計が追加され、さらに使いやすさが向上しました。拡張すると、クラスター内の既存のサーバーにより均等に影響し、負荷が均等に分散されます。ここではこれ以上の詳細は説明しません。
内存管理
存储方式
内存结构
注意事项" >注意事项
使用场景
安装启动" >安装启动
python操作memcached
python访问memcached
torando项目中使用memcached
代码
测试结果
小结
ホームページ バックエンド開発 Python チュートリアル Pythonでのmemcachedの操作を詳しく解説(画像と文章)

Pythonでのmemcachedの操作を詳しく解説(画像と文章)

May 07, 2017 am 10:57 AM


はじめに

多くの Web アプリケーションは、MySQL などの リレーショナル データベース 管理システムにデータを保存し、アプリケーション サーバーはそこからデータを読み取ってブラウザに表示します。 しかし、データ量が増加しアクセスが集中すると、データベースへの負担の増加、データベースのレスポンスの低下、Webサイトの表示の遅延などの弊害が生じます。分散キャッシュは、Web サイトのパフォーマンスを最適化するための重要な手段であり、多くのサイトがスケーラブルなサーバー クラスターを通じて大規模なホット データ キャッシュ サービスを提供しています。 データ ライブラリ クエリ の結果をキャッシュし、データベース アクセスの数を減らすことにより、動的 Web アプリケーションの速度とスケーラビリティを大幅に向上させることができます。業界で一般的に使用されているものには、redismemcachedなどが含まれます。今日は、pythonプロジェクトでmemcachedキャッシュサービスを使用する方法について話したいと思います。

memcachedはじめに

memcached は、オープンソースの高性能分散メモリ オブジェクト キャッシュ システム であり、その主な目的は、キャッシュを必要とするさまざまなシナリオに適用できます。データベースアプリへのアクセス。
memcached 自体は、実際には分散ソリューションを提供しません。サーバー側では、memcached クラスター環境は実際には memcached サーバーの集合体であり、環境構築は主に クライアント 上で実装され、分散ソリューションの目的はクライアントのルーティング処理。クライアントルーティングの原理は非常に単純です。アプリケーションサーバーが特定の key の値にアクセスするたびに、ルーティングアルゴリズムを通じてそのキーを特定の memcached サーバーノード A にマッピングするため、このキーに対するすべての操作はノード A で実行されます。サーバーがデータをキャッシュしている限り、キャッシュ ヒットが保証されます。
Pythonでのmemcachedの操作を詳しく解説(画像と文章)

ルーティングアルゴリズム

単純なルーティングアルゴリズム

剰余を使用した単純なルーティングアルゴリズムハッシュ: キャッシュされたデータキーのハッシュ値をサーバーの数で割ると、剰余は以下の表の数値になります。サーバーリスト。このアルゴリズムは、キャッシュされたデータを memcached クラスター全体に均等に分散でき、ほとんどのキャッシュ ルーティング要件も満たします。
ただし、me​​mcached クラスターを拡張する必要がある場合、問題が発生します。たとえば、Web サイトでは 3 台のキャッシュ サーバーの容量を 4 台のキャッシュ サーバーに拡張する必要があります。サーバー リストを変更した後も、残りのハッシュを使用すると、リクエストの 75% がキャッシュにヒットしないことが簡単に計算できます。サーバー クラスターのサイズが大きくなると、ミス率が高くなります。

1%3 = 1    
1%4 = 1
2%3 = 2    
2%4 = 2
3%3 = 0    
3%4 = 3
4%4 = 1    
4%4 = 0
#以此类推
ログイン後にコピー

このような拡張操作は非常に危険であり、データベースに瞬間的に大きな負荷がかかり、データベースがクラッシュする可能性もあります。この問題を解決するには 2 つの方法があります。1. アクセスが少ないときに容量を拡張し、拡張後にデータをウォームアップします。2. より適切なルーティング アルゴリズムを使用します。現在最も一般的に使用されているアルゴリズムは、一貫性のあるハッシュ アルゴリズムです。

一貫性のあるハッシュ

図に示すように、memcached クライアントはルーティング戦略として一貫性のあるハッシュ アルゴリズムを使用できます。一般的なハッシュ (単純なモジュラスなど) アルゴリズムと比較して、一貫性のあるハッシュ アルゴリズムはハッシュ値を計算するだけではありません。キーだけでなく、各サーバーに対応するハッシュ値も計算され、これらのハッシュ値は限られた値の範囲 (0~2^32 など) にマッピングされます。 hash(key) より大きいハッシュ値を持つ最小のサーバーを見つけることにより、そのサーバーがキー データを保存するターゲット サーバーとして使用されます。見つからない場合は、ハッシュ値が最も小さいサーバーがそのままターゲットサーバーとして使用されます。同時に、拡張の問題はある程度解決され、単一ノードの追加または削除はクラスター全体に大きな影響を与えません。
Pythonでのmemcachedの操作を詳しく解説(画像と文章)仮想レイヤー

一貫性のあるハッシュは完全ではなく、拡張中に負荷の不均衡を引き起こす可能性があります。最新バージョンでは仮想ノードの設計が追加され、さらに使いやすさが向上しました。拡張すると、クラスター内の既存のサーバーにより均等に影響し、負荷が均等に分散されます。ここではこれ以上の詳細は説明しません。

内存管理

存储方式

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,缓存的内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached本身是为缓存而设计的服务,因此并没有过多考虑数据的永久性问题。

内存结构

memcached仅支持基础的key-value键值对类型数据存储。在memcached内存结构中有两个非常重要的概念:slab和chunk。
slab是一个内存块,它是memcached一次申请内存的最小单位。在启动memcached的时候一般会使用参数-m指定其可用内存,但是并不是在启动的那一刻所有的内存就全部分配出去了,只有在需要的时候才会去申请,而且每次申请一定是一个slab。Slab的大小固定为1M(1048576 Byte),一个slab由若干个大小相等的chunk组成。每个chunk中都保存了一个item结构体、一对key和value。

虽然在同一个slab中chunk的大小相等的,但是在不同的slab中chunk的大小并不一定相等,在memcached中按照chunk的大小不同,可以把slab分为很多种类(class),默认情况下memcached把slab分为40类(class1~class40),在class 1中,chunk的大小为80字节,由于一个slab的大小是固定的1048576字节(1M),因此在class1中最多可以有13107个chunk(也就是这个slab能存最多13107个小于80字节的key-value数据)。
Pythonでのmemcachedの操作を詳しく解説(画像と文章)

memcached内存管理采取预分配、分组管理的方式,分组管理就是我们上面提到的slab class,按照chunk的大小slab被分为很多种类。内存预分配过程是怎样的呢?向memcached添加一个item时候,memcached首先会根据item的大小,来选择最合适的slab class:例如item的大小为190字节,默认情况下class 4的chunk大小为160字节显然不合适,class 5的chunk大小为200字节,大于190字节,因此该item将放在class 5中(显然这里会有10字节的浪费是不可避免的),计算好所要放入的chunk之后,memcached会去检查该类大小的chunk还有没有空闲的,如果没有,将会申请1M(1个slab)的空间并划分为该种类chunk。例如我们第一次向memcached中放入一个190字节的item时,memcached会产生一个slab class 2(也叫一个page),并会用去一个chunk,剩余5241个chunk供下次有适合大小item时使用,当我们用完这所有的5242个chunk之后,下次再有一个在160~200字节之间的item添加进来时,memcached会再次产生一个class 5的slab(这样就存在了2个pages)。

注意事项

  • chunk是在page里面划分的,而page固定为1m,所以chunk最大不能超过1m。

  • chunk实际占用内存要加48B,因为chunk数据结构本身需要占用48B。

  • 如果用户数据大于1m,则memcached会将其切割,放到多个chunk内。

  • 已分配出去的page不能回收。

  • -对于key-value信息,最好不要超过1m的大小;同时信息长度最好相对是比较均衡稳定的,这样能够保障最大限度的使用内存;同时,memcached采用的LRU清理策略,合理甚至过期时间,提高命中率。

使用场景

key-value能满足需求的前提下,使用memcached分布式集群是较好的选择,搭建与操作使用都比较简单;分布式集群在单点故障时,只影响小部分数据异常,目前还可以通过Magent缓存代理模式,做单点备份,提升高可用;整个缓存都是基于内存的,因此响应时间是很快,不需要额外的序列化、反序列化的程序,但同时由于基于内存,数据没有持久化,集群故障重启数据无法恢复。高版本的memcached已经支持CAS模式的原子操作,可以低成本的解决并发控制问题。

安装启动

$ sudo apt-get install memcached
$ memcached -m 32 -p 11211 -d
# memcached将会以守护程序的形式启动 memcached(-d),为其分配32M内存(-m 32),并指定监听 localhost的11211端口。
ログイン後にコピー

python操作memcached

在python中可通过memcache库来操作memcached,这个库使用很简单,声明一个client就可以读写memcached缓存了。

python访问memcached

#!/usr/bin/env pythonimport memcache

mc = memcache.Client(['127.0.0.1:12000'],debug=0)

mc.set("some_key", "Some value")
value = mc.get("some_key")

mc.set("another_key", 3)
mc.delete("another_key")

mc.set("key", "1")   # note that the key used for incr/decr must be a string.
mc.incr("key")
mc.decr("key")
ログイン後にコピー

然而,python-memcached默认的路由策略没有使用一致性哈希。

    def _get_server(self, key):
        if isinstance(key, tuple):
            serverhash, key = key        
            else:
            serverhash = serverHashFunction(key)        
            if not self.buckets:            
            return None, None

        for i in range(Client._SERVER_RETRIES):
            server = self.buckets[serverhash % len(self.buckets)]            
            if server.connect():                
            # print("(using server %s)" % server,)
                return server, key
            serverhash = serverHashFunction(str(serverhash) + str(i))        
            return None, None
ログイン後にコピー

从源码中可以看到:server = self.buckets[serverhash % len(self.buckets)],只是根据key进行了简单的取模。我们可以通过重写_get_server方法,让python-memcached支持一致性哈希。

import memcacheimport typesfrom hash_ring import HashRingclass MemcacheRing(memcache.Client):
    """Extends python-memcache so it uses consistent hashing to
    distribute the keys.
    """
    def init(self, servers, *k, **kw):
        self.hash_ring = HashRing(servers)
        memcache.Client.init(self, servers, *k, **kw)
        self.server_mapping = {}        
        for server_uri, server_obj in zip(servers, self.servers):
            self.server_mapping[server_uri] = server_obj    
            def _get_server(self, key):
        if type(key) == types.TupleType:            
        return memcache.Client._get_server(key)        
        for i in range(self._SERVER_RETRIES):
            iterator = self.hash_ring.iterate_nodes(key)            
            for server_uri in iterator:
                server_obj = self.server_mapping[server_uri]                
                if server_obj.connect():                    
                return server_obj, key        
                return None, None
ログイン後にコピー

torando项目中使用memcached

这里采用的策略是:1. 应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。2. 应用程序从cache中取数据,取到后返回。缓存更新是一个很复杂的问题,一般是先把数据存到数据库中,成功后,再让缓存失效。后面会再写文单独讨论memcached缓存更新的问题。

代码

# coding: utf-8import sysimport tornado.ioloopimport tornado.webimport loggingimport memcacheimport jsonimport urllib# 初始化memcache clientmc = memcache.Client(['127.0.0.1:11211'], debug=0)
mc_prefix = 'demo'class BaseHandler(tornado.web.RequestHandler):
    """ 把缓存处理抽象到BaseHandler基类 """
    USE_CACHE = False  # 控制是否使用缓存

    def format_args(self):
        arg_list = []        
        for a in self.request.arguments:            
        for value in self.request.arguments[a]:
                arg_list.append('%s=%s' % (a, urllib.quote(value.replace(' ', ''))))        
                # 根据请求的URL产生key
        arg_list.sort()
        key = '%s?%s' % (self.request.path, '&'.join(arg_list)) if arg_list else self.request.path
        key = '%s_%s' % (mc_prefix, key)        
        # key太长,不进行缓存处理
        if len(key) > 250:
            logging.error('key out of length: %s', key)            
            return None

        return key    def get(self, *args, **kwargs):
        if self.USE_CACHE:            
        try:                
        # 根据请求获取key
                self.key = self.format_args()                
                if self.key:
                    data = mc.get(self.key)  
                    # 若缓存命中,则直接返回数据
                    if data:
                        logging.info('get data from memecahce')
                        self.finish(data)                        
                        return
            except Exception, e:
                logging.exception(e)        
                # 若未命中缓存,调用do_get处理请求,获取数据
        data = self.do_get()
        data_str = json.dumps(data)        
        # 把成功获取到的数据,放入memcache缓存
        if self.USE_CACHE and data and data.get('result', -1) == 0 and self.key:            
        try:
                mc.set(self.key, data_str, 60)            
                except Exception, e:
                logging.exception(e)

        self.finish(data_str)    def do_get(self):
        return Noneclass DemoHandler(BaseHandler):
    USE_CACHE = True

    def do_get(self):
        a = self.get_argument('a', 'test')
        b = self.get_argument('b', 'test')        
        # 访问数据库获取数据,此处略去
        data = {'result': 0, 'a': a, 'b': b}        return datadef make_app():
    return tornado.web.Application([
        (r"/", DemoHandler),
    ])if name == "main":
    logging.basicConfig(stream=sys.stdout, level=logging.INFO,
                    format='%(asctime)s %(levelno)s %(message)s',
                    )

    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()
ログイン後にコピー

测试结果

在浏览器访问http://127.0.0.1:8888/?a=1&b=3,终端打印的log如下:

2017-02-21 22:45:05,987 20 304 GET /?a=1&b=2 (127.0.0.1) 3.11ms
2017-02-21 22:45:07,427 20 get data from memecahce
2017-02-21 22:45:07,427 20 304 GET /?a=1&b=2 (127.0.0.1) 0.71ms
2017-02-21 22:45:10,350 20 200 GET /?a=1&b=3 (127.0.0.1) 0.82ms
2017-02-21 22:45:13,586 20 get data from memecahce
ログイン後にコピー

从日志可以看到,缓存命中的情况。

小结

本文介绍了memcached的路由算法、内存管理、使用场景等基本概念,然后举例说明了在python项目中如何使用memcached缓存。缓存更新的问题还需要进一步分析讨论。

以上がPythonでのmemcachedの操作を詳しく解説(画像と文章)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHPおよびPython:さまざまなパラダイムが説明されています PHPおよびPython:さまざまなパラダイムが説明されています Apr 18, 2025 am 12:26 AM

PHPは主に手順プログラミングですが、オブジェクト指向プログラミング(OOP)もサポートしています。 Pythonは、OOP、機能、手続き上のプログラミングなど、さまざまなパラダイムをサポートしています。 PHPはWeb開発に適しており、Pythonはデータ分析や機械学習などのさまざまなアプリケーションに適しています。

PHPとPythonの選択:ガイド PHPとPythonの選択:ガイド Apr 18, 2025 am 12:24 AM

PHPはWeb開発と迅速なプロトタイピングに適しており、Pythonはデータサイエンスと機械学習に適しています。 1.PHPは、単純な構文と迅速な開発に適した動的なWeb開発に使用されます。 2。Pythonには簡潔な構文があり、複数のフィールドに適しており、強力なライブラリエコシステムがあります。

Windows 8でコードを実行できます Windows 8でコードを実行できます Apr 15, 2025 pm 07:24 PM

VSコードはWindows 8で実行できますが、エクスペリエンスは大きくない場合があります。まず、システムが最新のパッチに更新されていることを確認してから、システムアーキテクチャに一致するVSコードインストールパッケージをダウンロードして、プロンプトとしてインストールします。インストール後、一部の拡張機能はWindows 8と互換性があり、代替拡張機能を探すか、仮想マシンで新しいWindowsシステムを使用する必要があることに注意してください。必要な拡張機能をインストールして、適切に動作するかどうかを確認します。 Windows 8ではVSコードは実行可能ですが、開発エクスペリエンスとセキュリティを向上させるために、新しいWindowsシステムにアップグレードすることをお勧めします。

VSCODE拡張機能は悪意がありますか? VSCODE拡張機能は悪意がありますか? Apr 15, 2025 pm 07:57 PM

VSコード拡張機能は、悪意のあるコードの隠れ、脆弱性の活用、合法的な拡張機能としての自慰行為など、悪意のあるリスクを引き起こします。悪意のある拡張機能を識別する方法には、パブリッシャーのチェック、コメントの読み取り、コードのチェック、およびインストールに注意してください。セキュリティ対策には、セキュリティ認識、良好な習慣、定期的な更新、ウイルス対策ソフトウェアも含まれます。

ターミナルVSCODEでプログラムを実行する方法 ターミナルVSCODEでプログラムを実行する方法 Apr 15, 2025 pm 06:42 PM

VSコードでは、次の手順を通じて端末でプログラムを実行できます。コードを準備し、統合端子を開き、コードディレクトリが端末作業ディレクトリと一致していることを確認します。プログラミング言語(pythonのpython your_file_name.pyなど)に従って実行コマンドを選択して、それが正常に実行されるかどうかを確認し、エラーを解決します。デバッガーを使用して、デバッグ効率を向上させます。

Visual StudioコードはPythonで使用できますか Visual StudioコードはPythonで使用できますか Apr 15, 2025 pm 08:18 PM

VSコードはPythonの書き込みに使用でき、Pythonアプリケーションを開発するための理想的なツールになる多くの機能を提供できます。ユーザーは以下を可能にします。Python拡張機能をインストールして、コードの完了、構文の強調表示、デバッグなどの関数を取得できます。デバッガーを使用して、コードを段階的に追跡し、エラーを見つけて修正します。バージョンコントロールのためにGitを統合します。コードフォーマットツールを使用して、コードの一貫性を維持します。糸くずツールを使用して、事前に潜在的な問題を発見します。

vscodeはMacに使用できますか vscodeはMacに使用できますか Apr 15, 2025 pm 07:36 PM

VSコードはMacで利用できます。強力な拡張機能、GIT統合、ターミナル、デバッガーがあり、豊富なセットアップオプションも提供しています。ただし、特に大規模なプロジェクトまたは非常に専門的な開発の場合、コードと機能的な制限がある場合があります。

vscodeはipynbを実行できます vscodeはipynbを実行できます Apr 15, 2025 pm 07:30 PM

VSコードでJupyterノートブックを実行するための鍵は、Python環境が適切に構成されていることを確認し、コードの実行順序がセルの順序と一致していることを理解し、パフォーマンスに影響を与える可能性のある大きなファイルまたは外部ライブラリに注意することです。 VSコードで提供されるコードの完了とデバッグ機能は、コーディング効率を大幅に改善し、エラーを減らすことができます。

See all articles