In today's Internet applications, ranking functions are almost everywhere! Whether it is the sales list of e-commerce platforms, the ranking of players in the game, or the popularity list of social media, a real-time and efficient ranking system is the key to improving user experience. So the question is: How to quickly build a high-performance real-time ranking list with Spring Boot and Redisson? Today we will talk about this technical solution in detail!
Why choose Redisson
First of all, Redisson is a Java client based on Redis. It not only encapsulates the basic operations of Redis, but also provides advanced functions such as distributed locks, Bloom filters, rankings, etc. Compared to directly operating Redis, Redisson's API is more in line with the habits of Java developers and is optimized very well. For example, its RLexSortedSet and RScoredSortedSet can be directly used to implement rankings and support millisecond real-time updates!
// Example: Initialize the Redisson clientConfig config = new Config(); ().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = (config); // Get an ordered set with fractionsRScoredSortedSet<String> ranking = ("user_ranking");
How Spring Boot integrates Redisson
The integration process is very simple! Just a few steps:
Add dependencies: Add Redisson's Spring Boot Starter.
<dependency> <groupId></groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.16.8</version> </dependency>
Configure Redis connection: Fill in the Redis address and password.
spring: redis: host: 127.0.0.1 port: 6379
Inject RedissonClient: You can use Redisson's functions directly through @Autowired.
@Autowired private RedissonClient redissonClient;
Isn't it very simple? But don't worry, this is just the beginning! Next is the real core logic.
Key logic for realizing real-time rankings
The core functions of the rankings usually include:
- Update scores: For example, the user increases points after completing an order.
- Get Ranking: Query a user's current ranking.
- Get Top N: Showcase the top 100 list.
Implementing these functions with Redisson is very intuitive:
// Update user scores("user1", 100); // Get user ranking (from high to low)int rank = ("user1"); // Get the top 10Collection<String> top10 = (0, 9);
Here is a tip: Redisson's valueRangeReversed method can directly return the reverse order result, avoiding the overhead of manual sorting!
Performance optimization and practical pitfalls
In actual projects, rankings may face the problem of high concurrent updates. For example, during Double Eleven, the sales list of e-commerce platforms will be updated thousands of times per second! At this time, the following points need to be considered:
- Batch operation: Redisson supports pipelines and batch commands, which can significantly reduce network overhead.
- Distributed lock: If complex calculations are involved (such as integral weighting), RLock can be used to avoid concurrency problems.
- Memory optimization: Redis's zset uses ziplist to store a small amount of data by default, but when the data volume is large, it will automatically be converted to skiplist. At this time, you should pay attention to memory usage.
//Use pipeline batch updateRBatch batch = (); ("ranking").addScoreAsync("user1", 10); ("ranking").addScoreAsync("user2", 20); ();
Extension: Multi-dimensional ranking
Sometimes we need multi-dimensional rankings, such as the coexistence of "weekly list" and "total list". At this time, you can use Redisson's RScoredSortedSet to cooperate with different keys to achieve:
RScoredSortedSet<String> weeklyRanking = ("ranking:weekly"); RScoredSortedSet<String> totalRanking = ("ranking:total"); // Clear the weekly list every week();
Conclusion
With Spring Boot and Redisson, we can easily implement a high-performance real-time ranking system. From basic functions to performance optimization, Redisson provides a simple and powerful API. If you are facing similar needs, you might as well try it! Don’t panic when you encounter problems. Check more documents and communicate more. This is how technical growth comes step by step.
Method supplement
SpringBoot+Redission implements ranking function
1. Introduce Redis and Redission dependencies
<!-- redis --> <dependency> <groupId></groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redisson --> <dependency> <groupId></groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.20.1</version> </dependency>
Configuration
--- # redis configurationspring: redis: # address host: localhost # port, default is 6379 port: 6379 # Database Index database: 0 # Password (please comment out if there is no password) # password: # Connection timeout timeout: 10s # Whether to enable ssl ssl: false --- # redisson configurationredisson: # redis key prefix keyPrefix: ${} # Number of thread pools threads: 4 #Netty thread pool number nettyThreads: 8 # Single node configuration singleServerConfig: # Client name clientName: ${} # Minimum number of idle connections connectionMinimumIdleSize: 8 # Connection pool size connectionPoolSize: 32 # Connection idle timeout, unit: milliseconds idleConnectionTimeout: 10000 # Command waiting timeout, unit: milliseconds timeout: 3000 # Publish and Subscribe Connection Pool Size subscriptionConnectionPoolSize: 50
Code
Constant
/** * @author Baidu * @classname RankingConstant * @description Ranking constant data * @since 2024/5/6 */ public class RankingConstant { public static final Long BASIC_QUANTITY = 10000000000000L; public static final Long MAXIMUM_TIME_TIMIT = 29991231235959L; }
Controller
import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import .*; import ; import ; import ; /** * @author Baisu * @since 2024/4/28 */ @RestController public class DemoRankingController { @Value("${}") private String applicationName; /** * Project start testing method * * @return applicationName */ @GetMapping("") public String demo() { return applicationName; } /** * Generate test data * * @return ok */ @GetMapping("/generate_test_data") public R<Object> generateTestData() { ((), 1L, "10001"); ((), 2L, "10002"); ((), 3L, "10003"); ((), 4L, "10004"); ((), 5L, "10005"); return (); } /** * Get ranking data * * @param top quantity * @return ranking data */ @GetMapping("/get_ranking") public R<Object> getRanking(@RequestParam("top") Integer top) { Collection<ScoredEntry<Object>> ranking = ((), 0, top - 1); if (() == 0) { return ("No ranking data yet"); } List<RankingVo> list = new ArrayList<>(); for (ScoredEntry<Object> entry : ranking) { RankingVo vo = new RankingVo(); (().toString()); ((())); ((())); (vo); } return (list); } /** * Increase member score value * * @param member * @return Whether it increases success */ @GetMapping("/add_score_by_member") public R<Object> addScoreByMember(@RequestParam("member") String member) { Double scoreByMember = ((), member); if (scoreByMember == null) { scoreByMember = 0.0; } ((), (scoreByMember) + 1, member); return (); } /** * Get member score value * * @param member * @return Fraction value */ @GetMapping("/get_score_by_member") public R<Object> getScoreByMember(@RequestParam("member") String member) { Double scoreByMember = ((), member); if (scoreByMember == null) { return ("This member does not exist"); } RankingVo vo = new RankingVo(); (member); ((scoreByMember)); ((scoreByMember)); return (vo); } }
Domain
import ; /** * @author Baidu * @classname RankingVo * @description Ranking Display Class * @since 2024/5/6 */ @Data public class RankingVo { /** * Members */ private String member; /** * Score value */ private Long score; /** * time */ private String time; }
Utils
/** * @author Baidu * @classname RedisKey * @description Redis index * @since 2024/5/6 */ public class RedisKey { private static final String RANKING_DEMO_KEY = "ranking_demo"; public static String getRankingDemoKey() { return RANKING_DEMO_KEY; } }
import ; import ; import ; import ; import ; import ; import ; import ; /** * @author Baidu * @classname RedisUtil * @description Redis tool class * @since 2024/5/6 */ public class RedisUtil { private static final RedissonClient REDISSON_CLIENT = (); /** * Add a member of the specified score to the ordered set * * @param key Ordered set index * @param score * @param member * @return Success */ public static boolean addScoreByMember(String key, Long score, String member) { RScoredSortedSet<String> rScoredSortedSet = REDISSON_CLIENT.getScoredSortedSet(key); double v = score * RankingConstant.BASIC_QUANTITY + (RankingConstant.MAXIMUM_TIME_TIMIT - (((), ))); return (v, member); } /** * Returns the score value of the members in the ordered set * * @param key Ordered set index * @param member * @return Score value (Double) */ public static Double getScoreByMember(String key, String member) { RScoredSortedSet<Object> scoredSortedSet = REDISSON_CLIENT.getScoredSortedSet(key); return (member); } /** * Returns a set of members in the specified location in the ordered set * * @param key Ordered set index * @param start Start indexing * @param end end index * @return Member collection */ public static Collection<ScoredEntry<Object>> getRanking(String key, int start, int end) { RScoredSortedSet<Object> rScoredSortedSet = REDISSON_CLIENT.getScoredSortedSet(key); return (start, end); } }
import ; import ; /** * @author Baidu * @classname RankingUtil * @description ranking tool category * @since 2024/5/7 */ public class RankingUtil { public static final String FORMAT = "yyyyMMddHHmmss"; public static Long getScore(Double score) { return ((score / RankingConstant.BASIC_QUANTITY)); } public static String getTimeStr(Double score) { return (((RankingConstant.MAXIMUM_TIME_TIMIT - ((score)) % RankingConstant.BASIC_QUANTITY))); } }
This is the article about SpringBoot integrating Redisson to achieve high-performance real-time rankings. For more relevant SpringBoot Redisson real-time rankings, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!