tokuhirom's Blog

spring-session-data-redis に含まれる RedisSessionRepository を利用して redis の容量を節約する

spring-session-data-redis のデフォルト実装である RedisIndexedSessionRepository を利用すると以下の問題があります。

これに対して、大規模サービス用のよりシンプルな実装として RedisSessionRepository が提供されている。これを用いれば、既存実装の問題点から開放されることができる。

検証

RedisIndexedSessionRepository

↓RedisIndexedSessionRepository で、ログインするまでに実行される redis のコードは以下のようになっている。一人がログインするだけなのに、めちゃくちゃ実行コマンドが多い。

1646916911.858574 [0 127.0.0.1:59916] "HMSET" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xc2\xe7" "maxInactiveInterval" "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b" "creationTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xc2\xe7" "sessionAttr:SPRING_SECURITY_SAVED_REQUEST" "\xac\xed\x00\x05sr\x00Aorg.springframework.security.web.savedrequest.DefaultSavedRequest\x1e@HD\xf96d\x94\x02\x00\x0eI\x00\nserverPortL\x00\x0bcontextPatht\x00\x12Ljava/lang/String;L\x00\acookiest\x00\x15Ljava/util/ArrayList;L\x00\aheaderst\x00\x0fLjava/util/Map;L\x00\alocalesq\x00~\x00\x02L\x00\x06methodq\x00~\x00\x01L\x00\nparametersq\x00~\x00\x03L\x00\bpathInfoq\x00~\x00\x01L\x00\x0bqueryStringq\x00~\x00\x01L\x00\nrequestURIq\x00~\x00\x01L\x00\nrequestURLq\x00~\x00\x01L\x00\x06schemeq\x00~\x00\x01L\x00\nserverNameq\x00~\x00\x01L\x00\x0bservletPathq\x00~\x00\x01xp\x00\x00\x1f\x90t\x00\x00sr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xsr\x00\x11java.util.TreeMap\x0c\xc1\xf6>-%j\xe6\x03\x00\x01L\x00\ncomparatort\x00\x16Ljava/util/Comparator;xpsr\x00*java.lang.String$CaseInsensitiveComparatorw\x03\\}\\P\xe5\xce\x02\x00\x00xpw\x04\x00\x00\x00\x10t\x00\x06acceptsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x87text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9xt\x00\x0faccept-encodingsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x11gzip, deflate, brxt\x00\x0faccept-languagesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00#ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7xt\x00\rcache-controlsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\tmax-age=0xt\x00\nconnectionsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\nkeep-alivext\x00\x04hostsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x0elocalhost:8080xt\x00\areferersq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x1bhttp://localhost:8080/loginxt\x00\tsec-ch-uasq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00@\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"xt\x00\x10sec-ch-ua-mobilesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x02?0xt\x00\x12sec-ch-ua-platformsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\a\"macOS\"xt\x00\x0esec-fetch-destsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\bdocumentxt\x00\x0esec-fetch-modesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\bnavigatext\x00\x0esec-fetch-sitesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x0bsame-originxt\x00\x0esec-fetch-usersq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x02?1xt\x00\x19upgrade-insecure-requestssq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x011xt\x00\nuser-agentsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00yMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36xxsq\x00~\x00\x06\x00\x00\x00\x04w\x04\x00\x00\x00\x04sr\x00\x10java.util.Locale~\xf8\x11`\x9c0\xf9\xec\x03\x00\x06I\x00\bhashcodeL\x00\acountryq\x00~\x00\x01L\x00\nextensionsq\x00~\x00\x01L\x00\blanguageq\x00~\x00\x01L\x00\x06scriptq\x00~\x00\x01L\x00\avariantq\x00~\x00\x01xp\xff\xff\xff\xfft\x00\x02JPq\x00~\x00\x05t\x00\x02jaq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xffq\x00~\x00\x05q\x00~\x00\x05q\x00~\x00Aq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xfft\x00\x02USq\x00~\x00\x05t\x00\x02enq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xffq\x00~\x00\x05q\x00~\x00\x05q\x00~\x00Eq\x00~\x00\x05q\x00~\x00\x05xxt\x00\x03GETsq\x00~\x00\bpw\x04\x00\x00\x00\x00xppt\x00\x01/t\x00\x16http://localhost:8080/t\x00\x04httpt\x00\tlocalhostt\x00\x01/"
1646916911.860858 [0 127.0.0.1:59916] "SADD" "spring:session:expirations:1646918760000" "\xac\xed\x00\x05t\x00,expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916911.862692 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:expirations:1646918760000" "2100000"
1646916911.864704 [0 127.0.0.1:59916] "APPEND" "spring:session:sessions:expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2" ""
1646916911.865652 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "1800000"
1646916911.866575 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "2100000"
1646916911.868053 [0 127.0.0.1:59916] "PUBLISH" "spring:session:event:0:created:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "\xac\xed\x00\x05sr\x00\x11java.util.HashMap\x05\a\xda\xc1\xc3\x16`\xd1\x03\x00\x02F\x00\nloadFactorI\x00\tthresholdxp?@\x00\x00\x00\x00\x00\x04w\b\x00\x00\x00\x04\x00\x00\x00\x00x"
1646916911.882439 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916911.887132 [0 127.0.0.1:59916] "HMSET" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xc3\x0c" "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" "\xac\xed\x00\x05sr\x006org.springframework.security.web.csrf.DefaultCsrfTokenZ\xef\xb7\xc8/\xa2\xfb\xd5\x02\x00\x03L\x00\nheaderNamet\x00\x12Ljava/lang/String;L\x00\rparameterNameq\x00~\x00\x01L\x00\x05tokenq\x00~\x00\x01xpt\x00\x0cX-CSRF-TOKENt\x00\x05_csrft\x00$31641e92-2d3d-486b-82e4-efcad96ee8fe"
1646916911.887987 [0 127.0.0.1:59916] "SADD" "spring:session:expirations:1646918760000" "\xac\xed\x00\x05t\x00,expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916911.888732 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:expirations:1646918760000" "2100000"
1646916911.889398 [0 127.0.0.1:59916] "APPEND" "spring:session:sessions:expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2" ""
1646916911.890051 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "1800000"
1646916911.890638 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "2100000"
1646916911.891258 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916911.892703 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916914.624004 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916914.825021 [0 127.0.0.1:59916] "RENAME" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.825777 [0 127.0.0.1:59916] "RENAME" "spring:session:sessions:expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.829586 [0 127.0.0.1:59916] "HMSET" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xcd\xc4" "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION" "" "sessionAttr:SPRING_SECURITY_CONTEXT" "\xac\xed\x00\x05sr\x00=org.springframework.security.core.context.SecurityContextImpl\x00\x00\x00\x00\x00\x00\x020\x02\x00\x01L\x00\x0eauthenticationt\x002Lorg/springframework/security/core/Authentication;xpsr\x00Oorg.springframework.security.authentication.UsernamePasswordAuthenticationToken\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\x0bcredentialst\x00\x12Ljava/lang/Object;L\x00\tprincipalq\x00~\x00\x04xr\x00Gorg.springframework.security.authentication.AbstractAuthenticationToken\xd3\xaa(~nGd\x0e\x02\x00\x03Z\x00\rauthenticatedL\x00\x0bauthoritiest\x00\x16Ljava/util/Collection;L\x00\adetailsq\x00~\x00\x04xp\x01sr\x00&java.util.Collections$UnmodifiableList\xfc\x0f%1\xb5\xec\x8e\x10\x02\x00\x01L\x00\x04listt\x00\x10Ljava/util/List;xr\x00,java.util.Collections$UnmodifiableCollection\x19B\x00\x80\xcb^\xf7\x1e\x02\x00\x01L\x00\x01cq\x00~\x00\x06xpsr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xq\x00~\x00\rsr\x00Horg.springframework.security.web.authentication.WebAuthenticationDetails\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\rremoteAddresst\x00\x12Ljava/lang/String;L\x00\tsessionIdq\x00~\x00\x0fxpt\x00\x0f0:0:0:0:0:0:0:1t\x00$c332c966-2d8b-4cb9-a940-fcced7ba25d2psr\x002org.springframework.security.core.userdetails.User\x00\x00\x00\x00\x00\x00\x020\x02\x00\aZ\x00\x11accountNonExpiredZ\x00\x10accountNonLockedZ\x00\x15credentialsNonExpiredZ\x00\aenabledL\x00\x0bauthoritiest\x00\x0fLjava/util/Set;L\x00\bpasswordq\x00~\x00\x0fL\x00\busernameq\x00~\x00\x0fxp\x01\x01\x01\x01sr\x00%java.util.Collections$UnmodifiableSet\x80\x1d\x92\xd1\x8f\x9b\x80U\x02\x00\x00xq\x00~\x00\nsr\x00\x11java.util.TreeSet\xdd\x98P\x93\x95\xed\x87[\x03\x00\x00xpsr\x00Forg.springframework.security.core.userdetails.User$AuthorityComparator\x00\x00\x00\x00\x00\x00\x020\x02\x00\x00xpw\x04\x00\x00\x00\x00xpt\x00\x04user" "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" ""
1646916914.831427 [0 127.0.0.1:59916] "SADD" "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user" "\xac\xed\x00\x05t\x00$44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.832225 [0 127.0.0.1:59916] "SADD" "spring:session:expirations:1646918760000" "\xac\xed\x00\x05t\x00,expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.832900 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:expirations:1646918760000" "2100000"
1646916914.833575 [0 127.0.0.1:59916] "APPEND" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" ""
1646916914.834209 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "1800000"
1646916914.834850 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "2100000"
1646916914.835507 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916914.836309 [0 127.0.0.1:59916] "HMSET" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "sessionAttr:SPRING_SECURITY_CONTEXT" "\xac\xed\x00\x05sr\x00=org.springframework.security.core.context.SecurityContextImpl\x00\x00\x00\x00\x00\x00\x020\x02\x00\x01L\x00\x0eauthenticationt\x002Lorg/springframework/security/core/Authentication;xpsr\x00Oorg.springframework.security.authentication.UsernamePasswordAuthenticationToken\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\x0bcredentialst\x00\x12Ljava/lang/Object;L\x00\tprincipalq\x00~\x00\x04xr\x00Gorg.springframework.security.authentication.AbstractAuthenticationToken\xd3\xaa(~nGd\x0e\x02\x00\x03Z\x00\rauthenticatedL\x00\x0bauthoritiest\x00\x16Ljava/util/Collection;L\x00\adetailsq\x00~\x00\x04xp\x01sr\x00&java.util.Collections$UnmodifiableList\xfc\x0f%1\xb5\xec\x8e\x10\x02\x00\x01L\x00\x04listt\x00\x10Ljava/util/List;xr\x00,java.util.Collections$UnmodifiableCollection\x19B\x00\x80\xcb^\xf7\x1e\x02\x00\x01L\x00\x01cq\x00~\x00\x06xpsr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xq\x00~\x00\rsr\x00Horg.springframework.security.web.authentication.WebAuthenticationDetails\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\rremoteAddresst\x00\x12Ljava/lang/String;L\x00\tsessionIdq\x00~\x00\x0fxpt\x00\x0f0:0:0:0:0:0:0:1t\x00$c332c966-2d8b-4cb9-a940-fcced7ba25d2psr\x002org.springframework.security.core.userdetails.User\x00\x00\x00\x00\x00\x00\x020\x02\x00\aZ\x00\x11accountNonExpiredZ\x00\x10accountNonLockedZ\x00\x15credentialsNonExpiredZ\x00\aenabledL\x00\x0bauthoritiest\x00\x0fLjava/util/Set;L\x00\bpasswordq\x00~\x00\x0fL\x00\busernameq\x00~\x00\x0fxp\x01\x01\x01\x01sr\x00%java.util.Collections$UnmodifiableSet\x80\x1d\x92\xd1\x8f\x9b\x80U\x02\x00\x00xq\x00~\x00\nsr\x00\x11java.util.TreeSet\xdd\x98P\x93\x95\xed\x87[\x03\x00\x00xpsr\x00Forg.springframework.security.core.userdetails.User$AuthorityComparator\x00\x00\x00\x00\x00\x00\x020\x02\x00\x00xpw\x04\x00\x00\x00\x00xpt\x00\x04user"
1646916914.837401 [0 127.0.0.1:59916] "SREM" "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user" "\xac\xed\x00\x05t\x00$44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.838195 [0 127.0.0.1:59916] "SADD" "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user" "\xac\xed\x00\x05t\x00$44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.838894 [0 127.0.0.1:59916] "SADD" "spring:session:expirations:1646918760000" "\xac\xed\x00\x05t\x00,expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.839500 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:expirations:1646918760000" "2100000"
1646916914.840189 [0 127.0.0.1:59916] "APPEND" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" ""
1646916914.840861 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "1800000"
1646916914.841486 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "2100000"
1646916914.842081 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
1646916914.847443 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.856865 [0 127.0.0.1:59916] "HMSET" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xce\xa0" "sessionAttr:SPRING_SECURITY_SAVED_REQUEST" ""
1646916914.860546 [0 127.0.0.1:59916] "SADD" "spring:session:expirations:1646918760000" "\xac\xed\x00\x05t\x00,expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.861292 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:expirations:1646918760000" "2100000"
1646916914.861985 [0 127.0.0.1:59916] "APPEND" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" ""
1646916914.862693 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "1800000"
1646916914.864418 [0 127.0.0.1:59916] "PEXPIRE" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48" "2100000"
1646916914.864982 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.866710 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
1646916914.887045 [0 127.0.0.1:59916] "HGETALL" "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"

↓ご存知のとおり、 TTL が設定されていないキーが一つある し、無駄が多そう。 このキーは、spring-security を有効化していると、設定されるようになる ようだ。

127.0.0.1:6379> eval "local t = {} local i = 1 for _,v in ipairs(redis.call('KEYS', '*')) do if redis.call('TTL',v) == -1 then t[i] = v i = i + 1 end end return t" 0
1) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user"
127.0.0.1:6379> keys *
1) "spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
2) "spring:session:expirations:1646918760000"
3) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user"
4) "spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
127.0.0.1:6379> hgetall spring:session:sessions:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48
 1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
 2) ""
 3) "sessionAttr:SPRING_SECURITY_CONTEXT"
 4) "\xac\xed\x00\x05sr\x00=org.springframework.security.core.context.SecurityContextImpl\x00\x00\x00\x00\x00\x00\x020\x02\x00\x01L\x00\x0eauthenticationt\x002Lorg/springframework/security/core/Authentication;xpsr\x00Oorg.springframework.security.authentication.UsernamePasswordAuthenticationToken\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\x0bcredentialst\x00\x12Ljava/lang/Object;L\x00\tprincipalq\x00~\x00\x04xr\x00Gorg.springframework.security.authentication.AbstractAuthenticationToken\xd3\xaa(~nGd\x0e\x02\x00\x03Z\x00\rauthenticatedL\x00\x0bauthoritiest\x00\x16Ljava/util/Collection;L\x00\adetailsq\x00~\x00\x04xp\x01sr\x00&java.util.Collections$UnmodifiableList\xfc\x0f%1\xb5\xec\x8e\x10\x02\x00\x01L\x00\x04listt\x00\x10Ljava/util/List;xr\x00,java.util.Collections$UnmodifiableCollection\x19B\x00\x80\xcb^\xf7\x1e\x02\x00\x01L\x00\x01cq\x00~\x00\x06xpsr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xq\x00~\x00\rsr\x00Horg.springframework.security.web.authentication.WebAuthenticationDetails\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\rremoteAddresst\x00\x12Ljava/lang/String;L\x00\tsessionIdq\x00~\x00\x0fxpt\x00\x0f0:0:0:0:0:0:0:1t\x00$c332c966-2d8b-4cb9-a940-fcced7ba25d2psr\x002org.springframework.security.core.userdetails.User\x00\x00\x00\x00\x00\x00\x020\x02\x00\aZ\x00\x11accountNonExpiredZ\x00\x10accountNonLockedZ\x00\x15credentialsNonExpiredZ\x00\aenabledL\x00\x0bauthoritiest\x00\x0fLjava/util/Set;L\x00\bpasswordq\x00~\x00\x0fL\x00\busernameq\x00~\x00\x0fxp\x01\x01\x01\x01sr\x00%java.util.Collections$UnmodifiableSet\x80\x1d\x92\xd1\x8f\x9b\x80U\x02\x00\x00xq\x00~\x00\nsr\x00\x11java.util.TreeSet\xdd\x98P\x93\x95\xed\x87[\x03\x00\x00xpsr\x00Forg.springframework.security.core.userdetails.User$AuthorityComparator\x00\x00\x00\x00\x00\x00\x020\x02\x00\x00xpw\x04\x00\x00\x00\x00xpt\x00\x04user"
 5) "sessionAttr:SPRING_SECURITY_SAVED_REQUEST"
 6) ""
 7) "creationTime"
 8) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xc2\xe7"
 9) "maxInactiveInterval"
10) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
11) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
12) ""
13) "lastAccessedTime"
14) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe5\xce\xa0"
127.0.0.1:6379> smembers spring:session:expirations:1646918760000
1) "\xac\xed\x00\x05t\x00,expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
2) "\xac\xed\x00\x05t\x00,expires:c332c966-2d8b-4cb9-a940-fcced7ba25d2"
127.0.0.1:6379> smembers spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user
1) "\xac\xed\x00\x05t\x00$44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48"
127.0.0.1:6379> get spring:session:sessions:expires:44b8a9c4-db68-4bbf-be7e-6f9dd5a01d48
""

ここから、1分間ごとに spring:session:expirations:1646918760000 をなめて消す処理が走る。しかし、ここには以下のような問題がある。

特定ユーザーのログインセッションを一括で消す機能があって便利だが、これもまぁ別に RedisSessionRepository をベースに自前で用意したほうが良いかもしれない。

RedisSessionRepository

RedisSessionRepository はよりシンプルな新しいクラスである。https://github.com/spring-projects/spring-session/issues/1278 の PR で導入されていて、複雑すぎる RedisIndexedSessionRepository に対する代替案として提示されているものである。今後はこっちをデフォルトにする計画もあるっぽいです。 https://github.com/spring-projects/spring-session/issues/1711

(SimpleRedisOperationsSessionRepositoryという名前から変更された)

↓RedisSessionRepository での実行結果。そこそこ多いが、だいぶマシである。

1646916589.099128 [0 127.0.0.1:59338] "HMSET" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xd6!" "maxInactiveInterval" "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b" "sessionAttr:SPRING_SECURITY_SAVED_REQUEST" "\xac\xed\x00\x05sr\x00Aorg.springframework.security.web.savedrequest.DefaultSavedRequest\x1e@HD\xf96d\x94\x02\x00\x0eI\x00\nserverPortL\x00\x0bcontextPatht\x00\x12Ljava/lang/String;L\x00\acookiest\x00\x15Ljava/util/ArrayList;L\x00\aheaderst\x00\x0fLjava/util/Map;L\x00\alocalesq\x00~\x00\x02L\x00\x06methodq\x00~\x00\x01L\x00\nparametersq\x00~\x00\x03L\x00\bpathInfoq\x00~\x00\x01L\x00\x0bqueryStringq\x00~\x00\x01L\x00\nrequestURIq\x00~\x00\x01L\x00\nrequestURLq\x00~\x00\x01L\x00\x06schemeq\x00~\x00\x01L\x00\nserverNameq\x00~\x00\x01L\x00\x0bservletPathq\x00~\x00\x01xp\x00\x00\x1f\x90t\x00\x00sr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xsr\x00\x11java.util.TreeMap\x0c\xc1\xf6>-%j\xe6\x03\x00\x01L\x00\ncomparatort\x00\x16Ljava/util/Comparator;xpsr\x00*java.lang.String$CaseInsensitiveComparatorw\x03\\}\\P\xe5\xce\x02\x00\x00xpw\x04\x00\x00\x00\x10t\x00\x06acceptsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x87text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9xt\x00\x0faccept-encodingsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x11gzip, deflate, brxt\x00\x0faccept-languagesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00#ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7xt\x00\rcache-controlsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\tmax-age=0xt\x00\nconnectionsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\nkeep-alivext\x00\x04hostsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x0elocalhost:8080xt\x00\areferersq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x1bhttp://localhost:8080/loginxt\x00\tsec-ch-uasq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00@\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"xt\x00\x10sec-ch-ua-mobilesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x02?0xt\x00\x12sec-ch-ua-platformsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\a\"macOS\"xt\x00\x0esec-fetch-destsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\bdocumentxt\x00\x0esec-fetch-modesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\bnavigatext\x00\x0esec-fetch-sitesq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x0bsame-originxt\x00\x0esec-fetch-usersq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x02?1xt\x00\x19upgrade-insecure-requestssq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00\x011xt\x00\nuser-agentsq\x00~\x00\x06\x00\x00\x00\x01w\x04\x00\x00\x00\x01t\x00yMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36xxsq\x00~\x00\x06\x00\x00\x00\x04w\x04\x00\x00\x00\x04sr\x00\x10java.util.Locale~\xf8\x11`\x9c0\xf9\xec\x03\x00\x06I\x00\bhashcodeL\x00\acountryq\x00~\x00\x01L\x00\nextensionsq\x00~\x00\x01L\x00\blanguageq\x00~\x00\x01L\x00\x06scriptq\x00~\x00\x01L\x00\avariantq\x00~\x00\x01xp\xff\xff\xff\xfft\x00\x02JPq\x00~\x00\x05t\x00\x02jaq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xffq\x00~\x00\x05q\x00~\x00\x05q\x00~\x00Aq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xfft\x00\x02USq\x00~\x00\x05t\x00\x02enq\x00~\x00\x05q\x00~\x00\x05xsq\x00~\x00>\xff\xff\xff\xffq\x00~\x00\x05q\x00~\x00\x05q\x00~\x00Eq\x00~\x00\x05q\x00~\x00\x05xxt\x00\x03GETsq\x00~\x00\bpw\x04\x00\x00\x00\x00xppt\x00\x01/t\x00\x16http://localhost:8080/t\x00\x04httpt\x00\tlocalhostt\x00\x01/" "creationTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xd6!"
1646916589.102109 [0 127.0.0.1:59338] "PEXPIREAT" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90" "1646918389089"
1646916589.105447 [0 127.0.0.1:59338] "EXISTS" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916589.116953 [0 127.0.0.1:59338] "HGETALL" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916589.122376 [0 127.0.0.1:59338] "EXISTS" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916589.125151 [0 127.0.0.1:59338] "HMSET" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xd6@" "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" "\xac\xed\x00\x05sr\x006org.springframework.security.web.csrf.DefaultCsrfTokenZ\xef\xb7\xc8/\xa2\xfb\xd5\x02\x00\x03L\x00\nheaderNamet\x00\x12Ljava/lang/String;L\x00\rparameterNameq\x00~\x00\x01L\x00\x05tokenq\x00~\x00\x01xpt\x00\x0cX-CSRF-TOKENt\x00\x05_csrft\x00$49938ae3-2c5a-4343-a983-3b941ec5fe34"
1646916589.127423 [0 127.0.0.1:59338] "PEXPIREAT" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90" "1646918389120"
1646916589.129688 [0 127.0.0.1:59338] "HGETALL" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916589.133727 [0 127.0.0.1:59338] "EXISTS" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916589.135493 [0 127.0.0.1:59338] "HGETALL" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916592.188724 [0 127.0.0.1:59338] "HGETALL" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916592.312255 [0 127.0.0.1:59338] "EXISTS" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90"
1646916592.313174 [0 127.0.0.1:59338] "RENAME" "spring:session:sessions:82b6e568-278f-41bf-8ac5-ca7861460d90" "spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0"
1646916592.314158 [0 127.0.0.1:59338] "HMSET" "spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0" "lastAccessedTime" "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xe2>" "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION" "" "sessionAttr:SPRING_SECURITY_CONTEXT" "\xac\xed\x00\x05sr\x00=org.springframework.security.core.context.SecurityContextImpl\x00\x00\x00\x00\x00\x00\x020\x02\x00\x01L\x00\x0eauthenticationt\x002Lorg/springframework/security/core/Authentication;xpsr\x00Oorg.springframework.security.authentication.UsernamePasswordAuthenticationToken\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\x0bcredentialst\x00\x12Ljava/lang/Object;L\x00\tprincipalq\x00~\x00\x04xr\x00Gorg.springframework.security.authentication.AbstractAuthenticationToken\xd3\xaa(~nGd\x0e\x02\x00\x03Z\x00\rauthenticatedL\x00\x0bauthoritiest\x00\x16Ljava/util/Collection;L\x00\adetailsq\x00~\x00\x04xp\x01sr\x00&java.util.Collections$UnmodifiableList\xfc\x0f%1\xb5\xec\x8e\x10\x02\x00\x01L\x00\x04listt\x00\x10Ljava/util/List;xr\x00,java.util.Collections$UnmodifiableCollection\x19B\x00\x80\xcb^\xf7\x1e\x02\x00\x01L\x00\x01cq\x00~\x00\x06xpsr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xq\x00~\x00\rsr\x00Horg.springframework.security.web.authentication.WebAuthenticationDetails\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\rremoteAddresst\x00\x12Ljava/lang/String;L\x00\tsessionIdq\x00~\x00\x0fxpt\x00\x0f0:0:0:0:0:0:0:1t\x00$82b6e568-278f-41bf-8ac5-ca7861460d90psr\x002org.springframework.security.core.userdetails.User\x00\x00\x00\x00\x00\x00\x020\x02\x00\aZ\x00\x11accountNonExpiredZ\x00\x10accountNonLockedZ\x00\x15credentialsNonExpiredZ\x00\aenabledL\x00\x0bauthoritiest\x00\x0fLjava/util/Set;L\x00\bpasswordq\x00~\x00\x0fL\x00\busernameq\x00~\x00\x0fxp\x01\x01\x01\x01sr\x00%java.util.Collections$UnmodifiableSet\x80\x1d\x92\xd1\x8f\x9b\x80U\x02\x00\x00xq\x00~\x00\nsr\x00\x11java.util.TreeSet\xdd\x98P\x93\x95\xed\x87[\x03\x00\x00xpsr\x00Forg.springframework.security.core.userdetails.User$AuthorityComparator\x00\x00\x00\x00\x00\x00\x020\x02\x00\x00xpw\x04\x00\x00\x00\x00xpt\x00\x04user" "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN" ""

↓ ** TTL が設定されていないキーは存在しないし、1セッションにつき1つのハッシュのみがセットされていて、大きくデータ量を削減することができる。**

(デフォルトで30分の TTL っぽい)

127.0.0.1:6379> eval "local t = {} local i = 1 for _,v in ipairs(redis.call('KEYS', '*')) do if redis.call('TTL',v) == -1 then t[i] = v i = i + 1 end end return t" 0
(empty array)
127.0.0.1:6379> keys *
1) "spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0"
127.0.0.1:6379> type spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0
hash
127.0.0.1:6379> hgetall spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0
 1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
 2) ""
 3) "sessionAttr:SPRING_SECURITY_CONTEXT"
 4) "\xac\xed\x00\x05sr\x00=org.springframework.security.core.context.SecurityContextImpl\x00\x00\x00\x00\x00\x00\x020\x02\x00\x01L\x00\x0eauthenticationt\x002Lorg/springframework/security/core/Authentication;xpsr\x00Oorg.springframework.security.authentication.UsernamePasswordAuthenticationToken\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\x0bcredentialst\x00\x12Ljava/lang/Object;L\x00\tprincipalq\x00~\x00\x04xr\x00Gorg.springframework.security.authentication.AbstractAuthenticationToken\xd3\xaa(~nGd\x0e\x02\x00\x03Z\x00\rauthenticatedL\x00\x0bauthoritiest\x00\x16Ljava/util/Collection;L\x00\adetailsq\x00~\x00\x04xp\x01sr\x00&java.util.Collections$UnmodifiableList\xfc\x0f%1\xb5\xec\x8e\x10\x02\x00\x01L\x00\x04listt\x00\x10Ljava/util/List;xr\x00,java.util.Collections$UnmodifiableCollection\x19B\x00\x80\xcb^\xf7\x1e\x02\x00\x01L\x00\x01cq\x00~\x00\x06xpsr\x00\x13java.util.ArrayListx\x81\xd2\x1d\x99\xc7a\x9d\x03\x00\x01I\x00\x04sizexp\x00\x00\x00\x00w\x04\x00\x00\x00\x00xq\x00~\x00\rsr\x00Horg.springframework.security.web.authentication.WebAuthenticationDetails\x00\x00\x00\x00\x00\x00\x020\x02\x00\x02L\x00\rremoteAddresst\x00\x12Ljava/lang/String;L\x00\tsessionIdq\x00~\x00\x0fxpt\x00\x0f0:0:0:0:0:0:0:1t\x00$82b6e568-278f-41bf-8ac5-ca7861460d90psr\x002org.springframework.security.core.userdetails.User\x00\x00\x00\x00\x00\x00\x020\x02\x00\aZ\x00\x11accountNonExpiredZ\x00\x10accountNonLockedZ\x00\x15credentialsNonExpiredZ\x00\aenabledL\x00\x0bauthoritiest\x00\x0fLjava/util/Set;L\x00\bpasswordq\x00~\x00\x0fL\x00\busernameq\x00~\x00\x0fxp\x01\x01\x01\x01sr\x00%java.util.Collections$UnmodifiableSet\x80\x1d\x92\xd1\x8f\x9b\x80U\x02\x00\x00xq\x00~\x00\nsr\x00\x11java.util.TreeSet\xdd\x98P\x93\x95\xed\x87[\x03\x00\x00xpsr\x00Forg.springframework.security.core.userdetails.User$AuthorityComparator\x00\x00\x00\x00\x00\x00\x020\x02\x00\x00xpw\x04\x00\x00\x00\x00xpt\x00\x04user"
 5) "sessionAttr:SPRING_SECURITY_SAVED_REQUEST"
 6) ""
 7) "creationTime"
 8) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xd6!"
 9) "maxInactiveInterval"
10) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
11) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
12) ""
13) "lastAccessedTime"
14) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01\x7fs\xe0\xe2\xc6"
 
127.0.0.1:6379> ttl spring:session:sessions:a7133f51-f57f-4e05-80ca-ddfbbf2286d0
(integer) 1764

現在は、RedisSessionRepository は、デフォルトの実装ではないこともあってドキュメントが少ない。

https://spring.io/blog/2019/06/18/spring-session-corn-m2-and-spring-session-bean-sr6-released

https://github.com/spring-projects/spring-session/tree/main/spring-session-samples/spring-session-sample-boot-redis-simple

このあたりのドキュメントしかないのでこのへんを参照のこと。

↓のように設定すれば、RedisSessionRepository を利用できる。

package com.example.demo;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
import org.springframework.session.data.redis.RedisSessionRepository;
 
@EnableSpringHttpSession
@Configuration(proxyBeanMethods = false)
public class MySessionConfiguration {
    @Bean
    public RedisOperations<String, Object> sessionRedisOperations(RedisConnectionFactory redisConnectionFactory) {
        org.springframework.data.redis.core.RedisTemplate<String, Object> redisTemplate = new org.springframework.data.redis.core.RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
 
    @Bean
    public RedisSessionRepository redisSessionRepository(RedisOperations<String, Object> sessionRedisOperations) {
        return new RedisSessionRepository(sessionRedisOperations);
    }
}

See also

https://kagamihoge.hatenablog.com/entry/2018/05/19/163524