データキャッシュのJava実装


目次
基礎概念と問題
キャッシュ関連の概念
キャッシュ関連の問題
ローカルキャッシュ
Guava Cache
EHCache
リモートキャッシュ
Redisクラスタ
 キャッシュについてはよく知られていないはずですが、キャッシュの核心は空間で実践を変えることであり、キャッシュ領域(一般的にはメモリ)を割り当てることでデータの読み書き効率を高めることであり、その実現の難点はクリアポリシーの実現であり、比較的合理的な考え方はタイミング回収とデータの期限切れの判断をタイムリーに結びつけることです.
   次の記事では、主にローカルキャッシュ、リモートキャッシュ、分散キャッシュクラスタのいくつかの面からキャッシュに関する概念を紹介します.皆さんの参考にして勉強します.
基礎概念と問題
キャッシュ関連の概念
  • ヒット率:ヒット率とは、要求回数と正確に結果を返す回数の割合を指し、その影響要因にはデータのリアルタイム性が含まれており、株式類のリアルタイム性が高いデータを要求する場合、キャッシュのヒット率は低い.キャッシュ粒度の問題で、KEY値に含まれる条件が多すぎると、キャッシュヒット率が特に低い場合があります.一般に、キャッシュヒット率を向上させる方法には、キャッシュ空間のサイズを大きくすることが含まれる.ホットスポットデータをリアルタイムで更新する.キャッシュKEYのアルゴリズムを調整し、キャッシュKEYの細粒度、例えばkey-valueを保証する.ビジネスのニーズに応じてキャッシュの期限切れポリシーを合理的に調整します.
  • 最大要素:キャッシュに格納できる要素の最大数.
  • クリアポリシーにはFIFOが含まれており、最初にキャッシュに入ったデータは、スペースが足りない場合に優先的にクリーンアップされます.LFUはこれまで最も少なく使用されていた要素がクリーンアップされ、キャッシュ要素にカウンタ実装を設定することができます.LRUが最近最も使用していないキャッシュ要素はクリーンアップされ、最近使用していないデータをタイムスタンプでクリーンアップできます.
  • 予熱戦略は全量予熱を含み、最初からすべてのデータをロードし、あまり変化しないデータ(地域データ)に適用する.インクリメンタルウォームで、クエリーが見つからないときにデータソースから取り出してキャッシュに入れます.

  • キャッシュ関連の問題
  • キャッシュスルー:一般的なキャッシュシステムは、keyに従ってクエリーをキャッシュします.対応するvalueが存在しない場合は、バックエンドシステム(DBなど)を検索する必要があります.keyに対応するvalueが必ず存在せず、そのkeyに対する同時要求量が大きい場合、バックエンドシステムに大きな圧力を与える.これをキャッシュスルーと呼びます.解決策は、クエリ結果が空の場合もキャッシュし、キャッシュ時間を短く設定し、keyに対応するデータinsertの後にキャッシュをクリーンアップすることを含む.存在しないkeyをフィルタリングする.
  • キャッシュ雪崩キャッシュサーバが再起動または大量のキャッシュがある期間に集中して失効すると、バックエンドシステム(例えばDB)に大きな圧力をもたらす.ソリューションには、キャッシュが無効になった後、ロックまたはキューを追加することによって、キーに対して1つのスレッドのみがデータとライトキャッシュを問合せ、他のスレッドが待機するなど、リード・データベースのライト・キャッシュのスレッド数を制御することが含まれます.異なるkeyは異なる期限を設定し、キャッシュが失効した時点をできるだけ均一にする.二次キャッシュを行い、A 1は元のキャッシュ、A 2はコピーキャッシュ、A 1が失効した場合、A 2にアクセスでき、A 1キャッシュの失効時間は短期、A 2は長期に設定されます.

  • ローカルキャッシュ
    Javaのローカルキャッシュには、原子操作、キャッシュ読み書き、キャッシュイベントリスナー、データ統計などの特性が要求される関連規格javax.cacheが早くから存在している.実際の作業では、ローカルキャッシュは主に特に頻繁な安定したデータに使用されます.そうしないと、データの一致が損なわれます.実際には、Guava Cacheがよく使用され、Springとの結合が良好なEhCacheが使用されます.
    Guava Cache
         これは全メモリのローカルキャッシュ実装であり、スレッドの安全な実装メカニズムを提供し、簡単で使いやすく、性能が良い.その作成方法は、cacheLoadercallable callbackの2種類を含み、前者はcache全体に対して、後者はgetの場合に比較的柔軟に指定することができる.CacheBuilder.newBuilder()メソッドcacheを作成する際に重要ないくつかのメソッドを以下に示します.その後は簡単な使用例です.maximumSize(long):容量サイズを設定し、それを超えると回収を開始します.expireAfterAccess(long, TimeUnit):この時間帯に読み取り/書き込みアクセスがないと回収されます.expireAfterWrite(long, TimeUnit):この時間帯に書き込みアクセスされないと回収されます.removalListener(RemovalListener):要素が削除されたときにリスニングされるイベントをリスニングします.
    @Service
    public class ConfigCenterServiceImpl implements ConfigCenterService {
        private final static long maximumSize = 20;
        /**
         *   20 ,     1 
         */
        private Cache> cache = CacheBuilder.newBuilder().maximumSize(maximumSize)
                .expireAfterWrite(1, TimeUnit.DAYS).build();
        @Autowired
        private ConfigAppSettingDAO configAppSettingDAO;
    
        @Override
        public ConfigAppSettingDto getByTypeNameAndKey(String configType, String appID, String key) {
            Map map = getByType(configType, appID);
            return map.get(key);
        }
    
        /**************************      ******************************/
        private Map getByType(String configType, String appID) {
            try {
                return cache.get(configType, new Callable>() {
                    @Override
                    public Map call() throws Exception {
                        Map result = Maps.newConcurrentMap();
                        List list = configAppSettingDAO.getByTypeName(configType, appID);
                        if (null != list && !list.isEmpty()) {
                            for (ConfigAppSetting item : list) {
                                result.put(item.getAppkey(), new ConfigAppSettingDto(item.getAppkey(), item.getAppvalue(),
                                        item.getDescription()));
                            }
                        }
                        return result;
                    }
                });
            } catch (ExecutionException ex) {
                throw new BizException(300, "  ConfigAppSetting      ");
            }
        }
    }

    EHCache
           EHCacheもフルメモリのローカルキャッシュ実装であり、javax.cache JSR-107の仕様に適合し、Hibernateに適用されている.過去に失効したキャッシュ要素がGCに落とされず、メモリ漏洩の原因となった問題があり、その主なタイプと使用例は以下の通りである.Element:キー値ペアを維持するキャッシュされた要素.Cache:Ehcacheのコアクラスで、複数のElementがあり、CacheManagerによって管理されており、キャッシュに対する論理的な動作を実現しています.CacheManager:Cacheのコンテナオブジェクトで、Cacheのライフサイクルを管理します.
    Spring Boot統合Ehcacheの例
    //maven  
    
        org.springframework.boot
        spring-boot-starter-cache
    
    
        net.sf.ehcache
        ehcache
    
    
    
    
    
    //  Cache
    @SpringBootApplication
    @EnableCaching
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    
    
    
    //  1
    @CacheConfig(cacheNames = "users")
    public interface UserRepository extends JpaRepository {
        @Cacheable
        User findByName(String name);
    }
    
    
    
    //  2
    @Service
    public class CacheUserServiceImpl implements CacheUserService {
        @Autowired
        private UserMapper userMapper;
        @Override
        public List getUsers() {
            return userMapper.findAll();
        }
        // Cacheable      ,      people ,    Key-Value
        @Override
        @Cacheable(value = "people", key = "#name")
        public User getUser(String name) {
            return userMapper.findUserByName(name);
        }
        //put   
        @CachePut(value = "people", key = "#user.userid")
        public User save(User user) {
            User finalUser = userMapper.insert(user);
            return finalUser;
        }
        //Evict   
        @CacheEvict(value = "people")
        public void remove(Long id) {
            userMapper.delete(id);
        }
    }
    
    
    
    // application.properties  spring.cache.type=ehcache  
    // src/main/resources   ehcache.xml
    
        
        
    

     
    リモートキャッシュ
          一般的なリモートキャッシュコンポーネントにはmemcached、redisなどがあります.前者はパフォーマンスが効率的で使いやすいが、機能は比較的単一で、文字列タイプのデータのみをサポートし、シーケンス化プロトコルと組み合わせてキャッシュとしてしか使用できない.後者は現在最も流行しているキャッシュサーバで、効率的なアクセス速度、高い同時スループット、豊富なデータ型を持ち、持続化をサポートしています.したがって、データキャッシュ、分散キュー、分散ロック、メッセージミドルウェアなど、アプリケーションシーンは非常に多い.
         Redisは、文字列(strings)、ハッシュ(hashes)、リスト(lists)、セット(sets)、順序付きセット(sorted sets)、範囲クエリー、bitmaps、hyperlogs、地理空間(geospatial)インデックス半径クエリーなど、より豊富なデータ構造をサポートします.さらに、Redisにはレプリケーション(replication)、LUAスクリプト(Lua scripting)、LRU駆動イベント(LRU eviction)、トランザクション(transactions)、および異なるレベルのディスク持続化(persistence)が内蔵されており、Redis哨兵(Sentinal)、自動パーティション(Cluster)によって高可用性(highavailability)が提供されています.Redisはキャッシュシステムとデータベースのいくつかの特性を兼ね備えているため、豊富な応用シーンを持っていると言える.この論文ではSpring BootにおけるRedisの2つの典型的な応用シーンを紹介する.シーン1:データキャッシュ
    //maven  
      
        org.springframework.boot  
        spring-boot-starter-redis  
    
    
    //application.properties  
    # Redis     (   0)
    spring.redis.database=0  
    # Redis     
    spring.redis.host=localhost
    # Redis       
    spring.redis.port=6379  
    # Redis       (    )
    spring.redis.password=  
    #         
    spring.redis.pool.max-active=8  
    #            (          )
    spring.redis.pool.max-wait=-1  
    #            
    spring.redis.pool.max-idle=8  
    #            
    spring.redis.pool.min-idle=0
    
    //  1
    @Configuration
    @EnableCaching
    public class CacheConfig {
        @Autowired
        private JedisConnectionFactory jedisConnectionFactory;
        @Bean
        public RedisCacheManager cacheManager() {
            RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
            return redisCacheManager;
        }
        @Bean
        public RedisTemplate redisTemplate() {
            RedisTemplate redisTemplate = new RedisTemplate();
            redisTemplate.setConnectionFactory(jedisConnectionFactory);
            //       
            redisTemplate.setEnableTransactionSupport(true);
            //   String        
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            redisTemplate.setKeySerializer(stringRedisSerializer);
            redisTemplate.setHashKeySerializer(stringRedisSerializer);
            return redisTemplate;
        }
    }
    
    //  2,   Ehcache    

    シーン2:共有セッション
    //maven  
    
        org.springframework.session
        spring-session-data-redis
    
    //Session  
    @Configuration
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*)//
    public class SessionConfig {
    }
    //  
    @RequestMapping("/session")
    @RestController
    public class SessionController {
        @Autowired
        private UserRepository userRepository;
    
        @RequestMapping("/user/{id}")
        public User getUser(@PathVariable Long id, HttpSession session) {
            User user = (User) session.getAttribute("user" + id);
            if (null == user) {
                user = userRepository.findOne(id);
                session.setAttribute("user" + id, user);
            }
            return user;
        }
    }

      Spring RedisのデフォルトではJDKを使用してシーケンス化と逆シーケンス化が行われているため、キャッシュされたオブジェクトはjava.io.Serializableインタフェースを実装する必要があります.そうしないと、キャッシュエラーが発生します.
     
    Redisクラスタ
    実装には、従来の大クライアントスライスおよびエージェントモードに比べてルーティングクエリの方式が比較的新規である3つの方式が含まれ、具体的な解決策はredis−clusterを推奨する.
  • クライアントスライス:jedisを含む一部のクライアントは、クライアントスライスメカニズムを実現している.
  • エージェントのスライス:Twemproxy、codisに基づいて、クライアントは1つのエージェントに要求を送信し、エージェントはクライアントのデータを解析し、要求を正しいノードに転送し、結果をクライアントに返信する.
  • ルーティングクエリ:Redis-cluster,要求を任意のノードに送信し,要求を受信したノードはクエリ要求を正しいノードに送信して実行する.

  •   redisクラスタの具体的な実装例は、原文を参照することができる.まだ完全に理解していないので、ここで抜粋しません.
     
      記事ソース:Javaキャッシュの詳細