学习

使用 Redis 构建实时排行榜应用程序

Ajeet Raina
作者
Ajeet Raina, Redis 前开发者增长经理

排行榜的概念——显示领先竞争者的排名名称和当前分数(或其他数据点)的记分牌——对于计算机游戏世界至关重要,但排行榜现在不仅仅是关于游戏。它们是关于游戏化,一种更广泛的实现,可以包括任何具有共同目标的人群(同事、学生、销售团队、健身团队、志愿者等等)。

排行榜可以通过公开显示每个小组成员的当前排名来鼓励小组之间的健康竞争。它们还提供了一种清晰的方式来查看整个团队的持续成就,因为成员朝着目标努力。通过排行榜对任务和目标进行游戏化,是一种通过向人们提供他们在与其他小组成员相比的排名位置的持续反馈来激励他们的好方法。如果做得好的话,这会导致健康的竞争,从而建立团队凝聚力。

步骤 1. 安装以下软件#

步骤 2. 克隆存储库#

git clone https://github.com/redis-developer/basic-redis-leaderboard-demo-java

步骤 3. 运行 docker compose#

docker network create global
docker-compose up -d --build

步骤 4. 验证容器是否已启动并正在运行#

 docker-compose ps
            Name                           Command               State             Ports
--------------------------------------------------------------------------------------------------
redis.redisleaderboard.docker   docker-entrypoint.sh redis ...   Up      127.0.0.1:55000->6379/tcp

步骤 5. 复制 .env.example 以创建 .env#

提供环境变量的值(如果需要)

- REDIS_URL: Redis database endpoint URL
- REDIS_HOST: Redis server host
- REDIS_PORT: Redis server port
- REDIS_DB: Redis server db index
- REDIS_PASSWORD: Redis server password

如果您使用的是 Redis Cloud,则必须提供 DB 端点、密码、端口和数据库名称。在本地系统的情况下,条目看起来像下面所示

REDIS_URL=
REDIS_HOST=redis://localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=

步骤 6. 运行后端#

  • 安装 gradle

请访问以下链接 https://gradle.org.cn/install/ 获取您的 MacOS

brew install gradle
  • 安装 JDK

请访问以下链接 https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm 获取您的 MacOS

export $(cat .env | xargs)

步骤 7. 运行包装程序任务#

要使用包装程序,我们需要生成一些特定的文件。我们将使用名为 wrapper 的内置 Gradle 任务来生成这些文件。请注意,我们只需要生成这些文件一次。

现在,让我们在项目目录中运行包装程序任务

gradle wrapper

它应该显示以下结果

Welcome to Gradle 6.8.3!

Here are the highlights of this release:
 - Faster Kotlin DSL script compilation
 - Vendor selection for Java toolchains
 - Convenient execution of tasks in composite builds
 - Consistent dependency resolution

For more details see https://docs.gradle.org.cn/6.8.3/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 29s
1 actionable task: 1 executed

步骤 8. 执行构建任务#

现在可以使用 Gradle 包装程序来构建您的项目。现在是时候运行包装程序脚本来执行构建任务了。

./gradlew build
% ./gradlew build
Downloading https://services.gradle.org/distributions/gradle-6.8.3-bin.zip
..........10%..........20%..........30%...........40%..........50%..........60%..........70%...........80%..........90%..........100%
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

> Task :test
2021-03-01 07:08:42.962  INFO 3624 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

BUILD SUCCESSFUL in 1m 13s
12 actionable tasks: 12 executed

步骤 9. 运行您的应用程序#

./gradlew run
> Task :run

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.1)

2021-03-01 07:09:59.610  INFO 3672 --- [  restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Starting BasicRedisLeaderLoardDemoJavaApplication using Java 13.0.2 on Ajeets-MacBook-Pro.local with PID 3672 (/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/build/classes/java/main started by ajeetraina in /Users/ajeetraina/projects/basic-redis-leaderboard-demo-java)
2021-03-01 07:09:59.614  INFO 3672 --- [  restartedMain] BasicRedisLeaderLoardDemoJavaApplication : No active profile set, falling back to default profiles: default
2021-03-01 07:09:59.661  INFO 3672 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2021-03-01 07:09:59.661  INFO 3672 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2021-03-01 07:10:00.481  INFO 3672 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 5000 (http)
2021-03-01 07:10:00.492  INFO 3672 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-03-01 07:10:00.492  INFO 3672 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-03-01 07:10:00.551  INFO 3672 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-03-01 07:10:00.551  INFO 3672 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 889 ms
2021-03-01 07:10:00.756  INFO 3672 --- [  restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-01 07:10:00.845  INFO 3672 --- [  restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: URL [file:/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/assets/index.html]
2021-03-01 07:10:00.949  INFO 3672 --- [  restartedMain] .s.s.UserDetailsServiceAutoConfiguration :

Using generated security password: ea2d5326-b04c-4f93-b771-57bcb53f656e

2021-03-01 07:10:01.016  INFO 3672 --- [  restartedMain] o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@583fa06c, org.springframework.security.web.context.SecurityContextPersistenceFilter@524c0386, org.springframework.security.web.header.HeaderWriterFilter@c6e5d4e, org.springframework.security.web.authentication.logout.LogoutFilter@3e1f33e9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6790427f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@40ddf86, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1412ffa9, org.springframework.security.web.session.SessionManagementFilter@3eb6c20f, org.springframework.security.web.access.ExceptionTranslationFilter@21646e94, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@649e1b25]
2021-03-01 07:10:01.043  INFO 3672 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2021-03-01 07:10:01.065  INFO 3672 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 5000 (http) with context path ''
2021-03-01 07:10:01.093  INFO 3672 --- [  restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Started BasicRedisLeaderLoardDemoJavaApplication in 1.937 seconds (JVM running for 2.327)
<=========----> 75% EXECUTING [17s]
> :run

步骤 10. 访问排行榜应用程序#

它是如何工作的?#

数据是如何存储的:#

AAPL 的详细信息——2.6 万亿美元的市值和美国起源——存储在如下所示的哈希中

 HSET "company:AAPL" symbol "AAPL" market_cap "2600000000000" country USA

AAPL 的 2.6 万亿美元的排名存储在 ZSET 中。

 ZADD  companyLeaderboard 2600000000000 company:AAPL

数据是如何访问的:#

前 10 家公司

 ZREVRANGE companyLeaderboard 0 9 WITHSCORES

所有公司

 ZREVRANGE companyLeaderboard 0 -1 WITHSCORES

后 10 家公司

 ZRANGE companyLeaderboard 0 9 WITHSCORES

排名 10 到 15 之间

 ZREVRANGE companyLeaderboard 9 14 WITHSCORES

显示 AAPL、FB 和 TSLA 的排名

 ZREVRANGE  companyLeaderBoard company:AAPL company:FB company:TSLA

将 FB 公司的市值增加 10 亿美元

 ZINCRBY companyLeaderBoard 1000000000 "company:FB"

将 FB 公司的市值减少 10 亿美元

 ZINCRBY companyLeaderBoard -1000000000 "company:FB"

市值在 5000 亿美元到 1 万亿美元之间的公司

 ZCOUNT companyLeaderBoard 500000000000 1000000000000

市值超过 1 万亿美元的公司

 ZCOUNT companyLeaderBoard 1000000000000 +inf

参考资料#