GeniusRank 是一个开发者评估应用,致力于为用户提供 GitHub 用户数据查看、分析、评价与国籍猜测等服务。
- GeniusRank 专注于对 GitHub 上的开发者进行全面的能力评估和国籍猜测。在开发者能力评估方面,通过分析项目重要程度以及开发者在项目中的贡献度,采用类似 Google 搜索的 PageRank 机制,指数退避算法和 osu 的 pp 算法对开发者技术能力进行评价和评级。
- GeniusRank 接入了 ChatGLM 大模型,对于开发者的国籍信息,若其 Profile 中未明确写明,可通过其关系网络进行猜测。
- GeniusRank 提供排行榜查看,可根据开发者的领域进行搜索匹配,并按 TalentRank 排序,Nation 可作为可选筛选项,方便用户仅查看特定国家 / 地区的开发者。
- GeniusRank 提供分数卡片导出,支持在 Github 个人页面展示自己的分数和评级
- 前端使用了 Remix 和 TS 语言开发,除了实现 OAuth 登录,对开发者技术能力进行评价和评级,搜索 Github 用户分析数据,排行榜等众多基础功能之外,GeniusRank 还提供了卡片导出,ChatGLM 特色评估等特色功能,提高了功能的完备性。
- 后端部分使用 Java 语言微服务框架 SpringCloud,以 MyBatis-Plus 作为 ORM 框架,Nacos 作为服务的注册和发现,Redis 作为缓存,MySQL 进行持久化。使用 XXL-JOB 进行定时任务分配。使用 RocketMQ 作为消息队列,实现服务之间的解耦和流量削峰。
- 系统可观测性上,GeniusRank 引入 Sentinel 进行服务熔断和限流。使用 SkyWalking,实现对服务性能和资源的实时监控和可视化展示
团队成员 | 主要工作 |
---|---|
王朝伟 | 后端架构设计,用户模块,大模型模块,算法设计,缓存设计,限流,服务监控等 |
陆永祥 | 前端架构设计,布局设计,GitHub 用户数据获取、查看、分析,代码审查,服务端渲染等 |
张润诚 | 前端架构设计,UI 设计,国籍猜测模块、猜测与置信度算法设计等 |
git clone [email protected]:Team-DuiDuiDui/GeniusRank.git
IDEA 导入 Maven 项目,等待依赖下载完成。( jdk 版本要求为 17,maven 版本要求为 3.9.6+)
在 gateway-service,user-service,analyze-service 包下修改 shardingsphere-config-dev.yaml 中配置 mysql 数据库连接信息 执行 resources/database 包 project.sql 初始化数据库表结构。并将项目启动方式从 prod 正式环境改成 dev 开发环境。
在 gateway, user, analyze 包下修改 application.yml 中配置 redis 连接信息
rocketmq:
name-server: # RocketMQ name-server
producer:
group: # RocketMQ producer-group
send-message-timeout: 2000
retry-times-when-send-failed: 1
retry-times-when-send-async-failed: 1
mail:
enable: false #是否开启邮箱验证码服务
host: smtp.qq.com #邮箱服务器地址
username: #发送者邮箱
password: #发送者邮箱授权码
project-name: GeniusRank #项目名称
qiniu:
access-key: #请从七牛云工作台-个人中心-密钥管理获取
secret-key: #请从七牛云工作台-个人中心-密钥管理获取
bucket: #七牛云存储空间名称
directory: #自定义存储空间内目录
domain: #存储空间自定义域名,请提前在存储空间中进行配置
首先先在本地启动 redis,nacos,rocketmq 服务 然后再依次启动 user-service, analyze-service, gateway-service 服务即可。
首先确保你已经安装了 Node.js v22.2 或以上并已启用了 Corepack
执行以下命令安装依赖
$ yarn
在前端文件根目录下创建.dev.vars
文件,按注释在 GitHub 生成并写入相应信息
# 生成的 GitHub Fine-grained personal access tokens
GITHUB_ACCESS_TOKEN =
# 生成的 GitHub OAuth Client ID
GITHUB_CLIENT_ID =
# 生成的 GitHub OAuth Client Secret
GITHUB_CLIENT_SECRET =
# 后端 BASE_URL
BASE_URL =
执行以下命令运行项目
$ yarn dev
由于使用了 Remix CloudFlare Adaptor,需部署在 CloudFlare Pages 上。构建前需设置 Secret。
- 前端框架:Remix.js
- 编程语言:TypeScript
- 实用工具库:React Countup、lodash
- UI库:Mantine、React hot toast
- CSS框架: Tailwind
- 前端构建工具:Vite
- 网络请求库:Axios
- 部分网络请求方式:fetch
- 包管理工具:[email protected]
- 类型检查库: Zod
- 版本控制工具:Git
- 微服务框架:Spring-Cloud
- 数据库: MySQL
- ORM 框架:Mybatis-Plus
- 缓存:Redis
- 消息队列:RocketMQ
- 定时任务:XXL-JOB
- 管理面板:Sentinel、SkyWalking
- 服务发现:Nacos
- 对象存储:七牛云
- 大语言模型:ChatGLM、DeepSeek
服务名 | 作用 |
---|---|
User 服务 | 提供 OAuth 登录、注册、修改个人信息、上传图片和鉴权服务 |
Score 服务 | 提供 Github 用户分数算法,提供用户 Github 数据分析、评价。接入 ChatGLM 服务提供 Github 用户特色分析 |
Nation 服务 | 提供 Github 用户国籍猜测算法,若其 Profile 中未明确写明,可通过其关系网络进行猜测。接入 ChatGLM 服务提供分析。 |
DevelopType 服务 | 记录 Github 用户开发者领域信息 |
Rank 服务 | 提供排行榜查看,可根据开发者的领域进行搜索匹配,并按 TalentRank 排序,Nation 可作为可选筛选项,方便用户仅查看特定国家 / 地区的开发者 |
ChatGLM 服务 | 支持 Prompt 修改,同步和流式请求,接入大模型给 Github 用户提供服务 |
GeniusRank 前端及其服务端使用 Remix.js,后端使用 Spring-Cloud 作为微服务框架,包括 API 层和 RPC 层。API 层与前端交互,提供功能中间件。RPC 层实现业务逻辑,使用 Nacos 进行服务注册和发现。存储方面,使用 MySQL 持久化、 Redis 作为缓存、RocketMQ 作为消息队列。算法支持包括得分算法,国籍猜测算法和语言大模型。服务可观测性通过链路追踪和服务监控实现。
使用 Remix.js 框架构建(包含用户界面与 Remix 服务端),以 Tailwind 作为 CSS 框架,利用 TypeScript 与 Zod 进行类型检查,使用 i18next 实现多语言服务,以 Mantine 为前端 UI 与图表组件库,部署于 CloudFlare Pages。
支持服务端渲染(SSR),在必要处均遵循渐进增强原则,可以在无 JavaScript 的情况下使用最基本功能;同时支持增量静态生成(ISSG)与静态生成(SSG),减少 Remix 服务端压力,提升用户体验。
选择了基于 Spring Boot 3 和 JDK17 进行底层建设,同时组件库的版本大多也是最新的。这样做既能享受新技术带来的性能提升,也能体验到新特性带来的惊喜。 技术架构涵盖了 SpringBoot 3、SpringCloudAlibaba、Nacos、Sentinel、Skywalking、RocketMQ 5.x、Redis、MySQL、EasyExcel、Redisson、XXL-JOB 等技术。 框架技术和版本号关系如下表格所示。
序号 | 技术 | 名称 | 版本 | 官网 |
---|---|---|---|---|
1 | Spring Boot | 基础框架 | 3.0.7 | https://spring.io/projects/spring-boot |
2 | SpringCloud Alibaba | 分布式框架 | 2022.0.0.0-RC2 | https://github.com/alibaba/spring-cloud-alibaba |
3 | SpringCloud Gateway | 网关框架 | 2022.0.3 | https://spring.io/projects/spring-cloud-gateway |
4 | MyBatis-Plus | 持久层框架 | 3.5.7 | https://baomidou.com |
5 | MySQL | OLTP 关系型数据库 | 5.7.36 | https://www.mysql.com/cn |
6 | Redis | 分布式缓存数据库 | Latest | https://redis.io |
7 | RocketMQ | 消息队列 | 2.3.0 | https://rocketmq.apache.org |
8 | ShardingSphere | 数据库生态系统 | 5.3.2 | https://shardingsphere.apache.org |
9 | FastJson2 | JSON 序列化工具 | 2.0.36 | https://github.com/alibaba/fastjson2 |
10 | Canal | BinLog 订阅组件 | 1.1.6 | https://github.com/alibaba/canal |
11 | HuTool | 小而全的工具集项目 | 5.8.27 | https://hutool.cn |
12 | Maven | 项目构建管理 | 3.9.1 | http://maven.apache.org |
13 | Redisson | Redis Java 客户端 | 3.27.2 | https://redisson.org |
14 | Sentinel | 流控防护框架 | 1.8.6 | https://github.com/alibaba/Sentinel |
在前端开发中,我们通过渐进增强技术确保页面在不同浏览器和不同执行环境下的兼容性。实现渐进增强的关键措施包括:
- 特性检测:如果当前执行环境支持 JavaScript ,则会提供更好的用户交互体验。比如侧边栏的展开和主页面动画的无限滚动
- 合理的资源加载顺序:采用分层加载策略。首先加载基础 HTML 内容,然后通过外部 CSS 文件进行样式增强,最后通过外部 JavaScript 提供高级交互。
- 非阻塞加载策略:无论执行环境是怎样的,是否支持 JavaScript ,都能够体验到最基本的功能。比如就算没有侧边栏的情况下每个路由都在当前页面上或者跳转的页面上有入口。
无论是否启用 JavaScript,用户均可访问核心内容和主要功能。
这一方法确保页面在基础浏览器上实现核心功能,同时为高级浏览器用户提供更美观和丰富的体验。
为了保护用户数据,本项目采取了多层次的安全措施:
-
防止 XSS(跨站脚本攻击)
本项目涉及从 GitHub 获取用户 OAuth AccessToken。如果传统的放在 localstorage 中做持久化处理,很容易本各种恶及脚本盗取。为了保护该敏感数据,采用以下措施:- HttpOnly Cookies:所有敏感数据存储于
HttpOnly
Cookie 中,避免 JavaScript 访问,防止潜在 XSS 攻击者通过注入代码获取用户数据。 - 内容安全策略(CSP):配置严格的 CSP 头部,限制页面加载的外部资源来源,减少 XSS 攻击面。例如:
Content-Security-Policy: default-src 'self'
- 输入验证和输出编码:对于所有用户输入的数据,进行严格的验证和输出编码,避免潜在恶意脚本注入。
- HttpOnly Cookies:所有敏感数据存储于
-
防止 MITM(中间人攻击)
通过以下措施提高传输安全性:- Secure Cookie:将所有敏感数据设置为
Secure
Cookie,确保仅在 HTTPS 环境中传输,防止 HTTP 传输泄露信息。
- Secure Cookie:将所有敏感数据设置为
为了提升网站的搜索引擎友好性,我们采用了服务端渲染(SSR)和其他 SEO 优化手段:
- 结构化数据:在 HTML 中嵌入 JSON-LD 结构化数据和 meta 源标签,帮助搜索引擎更好地理解页面内容。
- 避免阻塞渲染的资源:移除或延迟加载阻塞渲染的 CSS 和 JavaScript 文件,例如, Vite 中会对于 TailwindCSS 中的类名进行封装,只会将用到的类名和 style 封装并且传递,减少 CSS 文件大小
这些措施确保页面能够在搜索引擎中更高效地索引,提高页面排名与用户访问量。
主页内容以静态页面为主,数据远程获取不会影响用户的直接操作,适合使用 ISSG 进行优化。Remix 虽然没有原生 ISSG 支持,但我们通过以下方法实现类似效果:
- Cloudflare Workers 和 Cache API 协同:借助 Cloudflare Workers 截获请求并检查缓存,若缓存存在则直接返回;否则发起远程请求,获取最新内容并将其缓存。
- 自定义缓存刷新策略:根据页面内容的时效性,设置合适的缓存刷新策略,例如使用短期缓存 TTL(Time-To-Live)定期刷新 user 或者 detail 路由下页面。
此方法提高了页面响应速度,同时减少了服务器的性能开销,保持页面更新和响应的平衡。
为了进一步优化用户体验,页面通过以下方式配置了缓存策略:
- Cache-Control 指令的细粒度控制:根据页面内容的时效性,设置合适的
Cache-Control
头,例如对于更新频率较高的页面设置为Cache-Control: no-cache
,而对于相对静态的页面则设置为Cache-Control: public, max-age=3600
。 - 服务端出现问题的缓存续用策略:如果在特定时段服务端出现问题,浏览器会通过缓存中的内容进行选择使用
- 应用缓存和预加载策略:利用 Service Worker 实现特定资源的预加载和缓存,如首次加载后预缓存静态资源,减少后续访问时的加载时间。
这一缓存策略优化显著提升了用户体验,减少页面加载时间的同时确保内容的及时性。
网站实现了全面的国际化功能,原生支持 中文
/ 英文
两种语言,确保不同语言用户的无障碍访问。国际化设计包括以下关键点:
- 多语言内容管理:所有界面文本和静态内容均通过国际化管理系统维护,避免硬编码文本,确保内容随时更新和切换。
- 自动语言检测:通过浏览器的语言首选项自动检测用户的语言偏好,并根据用户的设置自动切换语言,为用户提供一致的访问体验。
- 动态加载语言资源:根据用户的语言选择,动态加载相应的语言包,减少加载不必要资源造成的性能开销。
通过这些细节处理,实现了真正无障碍的多语言支持,为非中文用户提供了几乎无门槛的访问体验。
- 响应式布局:每个路由对应的页面都有完全的响应式,无论是移动端还是桌面端、甚至是折叠屏和平板等大小的设备。都有对应的布局,保证所有情况下都能体验到完整的功能和美观的 UI
- 无缝布局切换:如果在桌面端,就算是直接调整浏览器窗口大小,也能无缝在三种布局之间切换,不用刷新页面重新从服务端渲染页面。而且就算没有 JavaScript 的支持也能够做到模拟组件的不同布局不同渲染
- 亮 / 暗色模式:网站所有 UI 适配 Light Mode & Dark Mode,能够适应各种人群的各种展示环境
本项目采用微服务架构,将系统拆分为多个独立的服务模块,每个模块负责特定的功能。这种架构设计具有以下优点:
- 独立部署:每个服务模块可以独立部署,提高系统的可维护性和可扩展性。
- 模块化开发:开发人员可以专注于特定模块的开发,提高开发效率。
- 高可用性:通过负载均衡和故障转移机制,提高系统的可用性。
- 可扩展性:可以根据业务需求,灵活地增加或减少服务模块,实现系统的可扩展性。
- 可维护性:通过模块化设计,使系统更易于维护和升级。
- 安全性:通过服务隔离,降低单个服务模块的攻击风险。
- 可测试性:每个服务模块可以独立测试,提高系统的可测试性。
- 可复用性:每个服务模块可以独立复用,提高系统的可复用性。
本项目采用 RocketMQ 消息队列,实现服务之间的解耦和异步通信。RocketMQ 具有以下优点:
- 高性能:RocketMQ 具有高性能,可以处理大量消息,满足高并发场景的需求。
- 高吞吐量:RocketMQ 具有高吞吐量,可以处理大量消息,满足高并发场景的需求。
- 高可靠性:RocketMQ 具有高可靠性,确保消息的持久化和投递,保证消息不丢失。
- 可扩展性:RocketMQ 支持集群部署,可以水平扩展,满足大规模系统的需求。
- 高可用性:RocketMQ 支持故障转移和自动恢复,提高系统的可用性。
- 灵活的消息模型:RocketMQ 支持多种消息模型,如发布/订阅、点对点等,满足不同场景的需求。
- 丰富的功能:RocketMQ 提供了丰富的功能,如消息过滤、消息重试、消息追踪等,方便开发者使用。
- 社区活跃:RocketMQ 社区活跃,有丰富的文档和示例代码,方便开发者学习和使用。
- 兼容性:RocketMQ 兼容多种编程语言,如 Java、Python、Go 等,方便开发者使用。
- 易于集成:RocketMQ 提供了多种集成方式,如 Spring Boot、Spring Cloud 等,方便开发者集成到现有系统中。
- Cache Aside Pattern(旁路缓存模式):Cache Aside Pattern 中服务端需要同时维系 DB 和 cache,并且是以 DB 的结果为准,适用于读多写少的场景,采用「先更新数据库 + 再删除缓存」的方案,保证数据一致性
- Read/Write Through Pattern(读写穿透):Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 DB,从而减轻了应用程序的职责。
- Write Behind Pattern(异步缓存写入):Read/Write Through 是同步更新 cache 和 DB,而 Write Behind Caching 则是只更新缓存,不直接更新 DB,而是改为异步批量的方式来更新 DB
布隆过滤器是一种高效的概率性数据结构,主要用于检查一个元素是否在一个集合中。它的特点是可以提供快速的查询,但允许一定的误判。这种特性使得布隆过滤器在很多需要快速判断是否存在元素的场景中非常有用,比如网络爬虫、数据库的缓存、去重处理等。以下是布隆过滤器的基本工作原理和一些优势:
- 高效的空间利用:相比直接存储所有元素,布隆过滤器通过使用位数组和哈希函数来显著减少内存占用。
- 快速查询:查询速度非常快,通常可以在常数时间内完成。
- 可扩展性:可以动态增加元素,只需在添加新元素时更新位数组和哈希值即可。
- 灵活性:可以根据需要调整位数组的大小和哈希函数的数量,以平衡空间和准确性。
├─app
│ ├─api // api 封装
│ │ ├─backend // 后端 api
│ │ │ └─typings // 后端 api 返回类型
│ │ └─github // GitHub api
│ │ ├─graphql // GitHub 的 GraphQL api
│ │ │ └─typings // GitHub 的 GraphQL api 返回类型
│ │ └─rest // GitHub 的 RESTful api
│ │ ├─schema // zod 类型规范
│ │ └─typings // GitHub 的 RESTful api 返回类型
│ ├─assets // 一些资源文件
│ │ └─css // css 资源文件
│ ├─components // 组件
│ │ ├─constant // 通用组件
│ │ ├─ranking // ranking 路由下的组件
│ │ ├─userinfo // 未登录状态下的用户页面使用组件
│ │ │ └─detail // 登录状态下的用户页面使用组件
│ │ └─*.* // 其他组件
│ ├─config // 配置常量
│ ├─hooks // 一些自定义 hook
│ ├─locales // i18n 翻译资源
│ ├─modules // 其他模块资源
│ ├─routes // 路由管理
│ │ ├─card.$name // /card/:name 路由
│ │ ├─detail.$name // /detail/:name 路由
│ │ ├─user.$name // /user/:name 路由
│ │ └─*.* // 其他路由
│ └─utils // 工具函数
│ ├─auto-animate-plugin // 动画资源
│ ├─region // nation 推测
| └─*.* // 其他工具函数
├─functions // CloudFlare Pages 路由挂载
├─public // 静态资源根目录
├─.dev.vars // 应有的环境变量
├─.eslintignore // eslint 配置文件
├─.eslintrc.cjs // eslint 配置文件
├─.gitignore // git 配置文件
├─.yarnrc.yml // yarn 配置文件
├─load-context.ts // 环境变量加载
├─package.json // 包管理
├─postcss.config.js // postcss 配置文件
├─tailwind.config.js // tailwind 原子化 css 配置文件
├─tsconfig.json // ts 配置文件
├─vite.config.ts // vite 打包工具配置文件
├─wrangler.toml // CloudFlare 命令行配置
└─yarn.lock // yarn 的包版本固定文件
├─aggregation-service // 聚合服务
│ ├─src
│ │ └─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─nine
│ │ │ └─project
│ │ │ └─aggregation // 聚合逻辑相关实现
│ │ └─resources // 资源文件
├─analyze-service // 分析服务
│ ├─src
│ │ └─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─nine
│ │ │ └─project
│ │ │ └─analyze // 数据分析相关实现
│ │ │ ├─config // 配置文件
│ │ │ ├─constant // 常量定义
│ │ │ ├─controller // 控制层
│ │ │ ├─dao // 数据访问层
│ │ │ │ ├─entity // 实体类
│ │ │ │ └─mapper // 数据库映射
│ │ │ ├─dto // 数据传输对象
│ │ │ │ ├─req // 请求对象
│ │ │ │ └─resp // 响应对象
│ │ │ ├─mq // 消息队列相关实现
│ │ │ │ ├─consumer // 消费者
│ │ │ │ ├─event // 事件
│ │ │ │ └─produce // 生产者
│ │ │ ├─service // 服务层
│ │ │ │ └─impl // 服务实现层
│ │ │ └─toolkit // 工具类
│ │ └─resources // 资源文件
│ │ └─mapper // 映射文件
├─framework // 通用模块
│ ├─src
│ │ └─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─nine
│ │ │ └─project
│ │ │ └─framework // 通用功能实现
│ │ │ ├─biz // 业务逻辑模块
│ │ │ │ └─user // 用户相关业务
│ │ │ ├─config // 配置管理
│ │ │ ├─database // 数据库访问层
│ │ │ │ ├─base // 基础数据库操作
│ │ │ │ ├─config // 数据库配置
│ │ │ │ ├─handler // 数据库操作处理
│ │ │ │ └─page // 分页操作
│ │ │ ├─errorcode // 错误代码定义
│ │ │ ├─exception // 异常处理
│ │ │ ├─result // 结果封装
│ │ │ ├─toolkit // 工具类
│ │ │ └─web // Web 相关功能
│ │ └─resources // 资源文件
│ │ └─META-INF // 元数据定义
│ │ └─spring // Spring 相关配置
├─gateway-service // 网关服务
│ ├─src
│ │ └─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─nine
│ │ │ └─project
│ │ │ └─gateway // 服务网关实现
│ │ │ ├─config // 配置文件
│ │ │ ├─constant // 常量定义
│ │ │ └─filter // 过滤器实现
│ │ └─resources // 资源文件
├─resources // 资源文件
│ ├─api // API 文档
│ └─database // 数据库配置相关文件
└─user-service // 用户服务
├─src
│ └─main
│ ├─java
│ │ └─com
│ │ └─nine
│ │ └─project
│ │ └─user // 用户相关功能实现
│ │ ├─common // 公共模块
│ │ │ ├─constant // 常量定义
│ │ │ └─serialize // 序列化逻辑
│ │ ├─config // 配置文件
│ │ ├─controller // 控制层
│ │ ├─dao // 数据访问层
│ │ │ ├─entity // 实体类
│ │ │ └─mapper // 数据库映射
│ │ ├─dto // 数据传输对象
│ │ │ ├─req // 请求对象
│ │ │ └─resp // 响应对象
│ │ ├─job // 定时任务
│ │ ├─mq // 消息队列相关实现
│ │ │ ├─consumer // 消费者
│ │ │ ├─event // 事件
│ │ │ └─produce // 生产者
│ │ ├─remote // 远程服务调用
│ │ │ └─dto // 远程服务数据传输对象
│ │ │ ├─req // 请求对象
│ │ │ └─resp // 响应对象
│ │ ├─service // 服务层
│ │ │ └─impl // 服务实现层
│ │ └─toolkit // 工具类
│ └─resources // 资源文件
全部功能文档可查询对应 ApiFox 文档示例和说明