跳到主要内容

Hasura详解

Hasura概述

Hasura是一个开源的GraphQL引擎,能够自动将PostgreSQL数据库转换为GraphQL API。它提供了实时数据订阅、细粒度的权限控制、事件触发器等功能,使开发者能够快速构建数据驱动的应用程序。

Hasura成立于2018年,目前已成为GraphQL生态系统中重要的组成部分,被众多公司和组织采用,包括Red Hat、Auth0、IBM等。

Hasura的核心特性

1. 自动生成GraphQL API

Hasura能够自动根据PostgreSQL数据库模式生成完整的GraphQL API,包括查询、变更和订阅操作,无需编写任何后端代码。

2. 实时数据订阅

通过GraphQL订阅,客户端可以实时接收数据库变更通知,适用于构建聊天应用、实时仪表盘等需要实时数据的场景。

3. 细粒度的权限控制

Hasura提供了强大的权限系统,可以基于角色和用户定义细粒度的数据访问控制规则,确保数据安全。

4. 事件触发器

Hasura的事件触发器可以在数据库发生变更时触发Webhook,实现业务逻辑处理、通知等功能。

5. 远程Schema集成

Hasura允许集成远程GraphQL服务,将多个GraphQL API合并为一个统一的API。

6. 数据库视图和自定义函数支持

支持PostgreSQL视图和自定义函数,可以在Hasura中直接使用这些数据库对象。

安装和配置Hasura

1. 使用Docker安装

# 创建docker-compose.yml文件
version: '3.6'

services:
postgres:
image: postgres:13
restart: always
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgrespassword

graphql-engine:
image: hasura/graphql-engine:v2.20.0
ports:
- "8080:8080"
depends_on:
- postgres
restart: always
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # 启用控制台
HASURA_GRAPHQL_DEV_MODE: "true" # 开发模式
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
volumes:
db_data:

启动服务:

docker-compose up -d

访问Hasura控制台:http://localhost:8080,使用admin secret key(myadminsecretkey)登录。

2. 使用Hasura Cloud

Hasura Cloud提供了托管的Hasura服务,无需自己管理基础设施:

  1. 访问https://cloud.hasura.io注册账号
  2. 创建新项目
  3. 连接到现有PostgreSQL数据库或创建新数据库
  4. 开始使用Hasura控制台

连接数据库

1. 添加PostgreSQL数据库

  1. 在Hasura控制台中,导航到"Data"标签页
  2. 点击"Connect Database"按钮
  3. 选择"PostgreSQL"
  4. 输入数据库连接信息:
    • 数据库URL:postgresql://username:password@hostname:port/database
    • 数据库名称(可选)
  5. 点击"Connect Database"按钮

2. 跟踪现有表和视图

连接数据库后,Hasura会显示所有可用的表和视图:

  1. 选择要跟踪的表或视图
  2. 点击"Track"按钮
  3. Hasura会自动生成相关的GraphQL查询和变更

3. 创建新表

也可以在Hasura控制台中直接创建新表:

  1. 导航到"Data"标签页
  2. 点击"Create Table"按钮
  3. 定义表结构(表名、字段、类型、约束等)
  4. 点击"Add Table"按钮

GraphQL查询操作

1. 基本查询

Hasura自动为每个表生成查询操作:

query GetUsers {
users {
id
name
email
created_at
}
}

2. 过滤和排序

query GetFilteredUsers {
users(where: { age: { _gt: 18 } }, order_by: { created_at: desc }) {
id
name
age
}
}

3. 分页查询

query GetUsersWithPagination {
users(
limit: 10
offset: 20
order_by: { created_at: desc }
) {
id
name
email
}
users_aggregate {
aggregate {
count
}
}
}

4. 关系查询

Hasura会自动检测和利用数据库中的外键关系:

query GetUserWithPosts {
users_by_pk(id: 1) {
id
name
email
posts {
id
title
content
created_at
}
}
}

GraphQL变更操作

1. 插入数据

mutation InsertUser {
insert_users_one(object: {
name: "张三",
email: "zhangsan@example.com",
age: 25
}) {
id
name
email
}
}

# 批量插入
mutation InsertMultipleUsers {
insert_users(objects: [
{ name: "李四", email: "lisi@example.com" },
{ name: "王五", email: "wangwu@example.com" }
]) {
returning {
id
name
}
}
}

2. 更新数据

mutation UpdateUser {
update_users_by_pk(pk_columns: { id: 1 }, _set: {
name: "张三更新",
age: 26
}) {
id
name
age
}
}

# 条件更新
mutation UpdateMultipleUsers {
update_users(where: { age: { _lt: 18 } }, _set: {
status: "未成年"
}) {
affected_rows
returning {
id
name
status
}
}
}

3. 删除数据

mutation DeleteUser {
delete_users_by_pk(id: 1) {
id
name
}
}

# 条件删除
mutation DeleteMultipleUsers {
delete_users(where: { status: { _eq: "inactive" } }) {
affected_rows
}
}

实时数据订阅

1. 基本订阅

subscription GetRealTimeUsers {
users {
id
name
email
}
}

2. 带过滤条件的订阅

subscription GetRealTimeNewUsers {
users(order_by: { created_at: desc }, limit: 10) {
id
name
email
created_at
}
}

3. 关系数据订阅

subscription GetUserWithPostsRealtime {
users_by_pk(id: 1) {
id
name
posts {
id
title
content
}
}
}

权限控制

1. 创建用户角色

  1. 在Hasura控制台中,导航到"Settings" > "Roles"标签页
  2. 点击"Create New Role"按钮
  3. 输入角色名称(如:user、admin等)
  4. 点击"Save"按钮

2. 定义表级权限

  1. 导航到"Data"标签页,选择要设置权限的表
  2. 点击"Permissions"标签页
  3. 选择角色,然后设置以下权限:
    • Select: 设置查询权限
    • Insert: 设置插入权限
    • Update: 设置更新权限
    • Delete: 设置删除权限
  4. 为每个权限定义过滤条件和列选择限制
  5. 点击"Save Permissions"按钮

3. 权限规则示例

用户只能访问自己的数据

{
"id": {"_eq": "X-Hasura-User-Id"}
}

基于用户角色的权限

{
"role": {"_eq": "X-Hasura-Role"}
}

组合条件

{
"_and": [
{"status": {"_eq": "active"}},
{"visibility": {"_eq": "public"}}
]
}

4. 会话变量

Hasura使用会话变量来实现基于用户的权限控制,常用的会话变量包括:

  • X-Hasura-User-Id: 用户ID
  • X-Hasura-Role: 用户角色
  • 自定义会话变量

这些变量可以通过认证服务或JWT令牌传递给Hasura。

事件触发器

1. 创建事件触发器

  1. 在Hasura控制台中,导航到"Events"标签页
  2. 点击"Create Event Trigger"按钮
  3. 配置触发器:
    • 名称:触发器的唯一标识符
    • 模式:选择数据库模式
    • 表:选择要监听的表
    • 操作:选择要监听的操作(INSERT、UPDATE、DELETE)
    • Webhook URL:事件触发时调用的HTTP端点
  4. 点击"Create"按钮

2. 事件有效载荷示例

当事件被触发时,Hasura会向配置的Webhook URL发送HTTP POST请求,请求体包含事件详情:

{
"event": {
"op": "INSERT",
"data": {
"old": null,
"new": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"created_at": "2023-04-01T10:00:00Z"
}
}
},
"table": {
"name": "users",
"schema": "public"
},
"trigger": {
"name": "user_created"
},
"created_at": "2023-04-01T10:00:01.234Z",
"delivery_info": {
"max_retries": 0,
"current_retry": 0
}
}

3. 重试策略

Hasura支持为事件触发器配置重试策略:

  • 最大重试次数
  • 重试间隔
  • 指数退避

4. 事件队列管理

在"Events"标签页中,可以查看和管理事件队列:

  • 查看待处理事件
  • 重新触发失败的事件
  • 监控事件处理状态

远程Schema集成

1. 添加远程Schema

  1. 在Hasura控制台中,导航到"Remote Schemas"标签页
  2. 点击"Add Remote Schema"按钮
  3. 配置远程Schema:
    • 名称:远程Schema的唯一标识符
    • GraphQL服务器URL:远程GraphQL服务的端点
    • 可选的头部信息(认证令牌等)
  4. 点击"Add Remote Schema"按钮

2. 权限传播

可以为远程Schema配置权限传播,将Hasura的会话变量传递给远程服务:

  1. 编辑远程Schema配置
  2. 在"Headers"部分,添加自定义头部
  3. 使用会话变量作为头部值:{{$x-hasura-user-id}}

3. 示例:集成认证服务

# 远程认证服务的Schema

type AuthPayload {
token: String!
user: User!
}

type Mutation {
login(email: String!, password: String!): AuthPayload!
register(email: String!, password: String!): AuthPayload!
}

集成后,可以在Hasura中直接调用这些突变操作:

mutation Login {
login(email: "user@example.com", password: "password") {
token
user {
id
name
}
}
}

自定义SQL函数

1. 创建自定义函数

可以在PostgreSQL中创建自定义函数,然后在Hasura中使用:

CREATE OR REPLACE FUNCTION public.get_user_post_count(user_id integer) 
RETURNS integer AS $$
SELECT COUNT(*) FROM public.posts WHERE posts.user_id = user_id;
$$ LANGUAGE sql STABLE;

2. 在Hasura中跟踪函数

  1. 在Hasura控制台中,导航到"Data"标签页
  2. 选择"SQL Functions"选项卡
  3. 找到创建的函数(get_user_post_count)
  4. 点击"Track"按钮

3. 在GraphQL查询中使用函数

query GetUserWithPostCount {
users {
id
name
post_count: get_user_post_count(user_id: id)
}
}

视图和物化视图

1. 创建视图

CREATE VIEW public.user_with_post_count AS
SELECT
u.id,
u.name,
u.email,
COUNT(p.id) AS post_count
FROM public.users u
LEFT JOIN public.posts p ON u.id = p.user_id
GROUP BY u.id;

2. 在Hasura中跟踪视图

  1. 在Hasura控制台中,导航到"Data"标签页
  2. 选择"Views"选项卡
  3. 找到创建的视图(user_with_post_count)
  4. 点击"Track"按钮

3. 在GraphQL查询中使用视图

query GetUsersWithPostCount {
user_with_post_count {
id
name
email
post_count
}
}

性能优化

1. 索引优化

为常用查询字段添加索引可以显著提高查询性能:

-- 为users表的email字段添加唯一索引
CREATE UNIQUE INDEX idx_users_email ON public.users(email);

-- 为posts表的user_id和created_at字段添加复合索引
CREATE INDEX idx_posts_user_id_created_at ON public.posts(user_id, created_at DESC);

2. 查询优化

  • 使用_agg查询获取聚合数据
  • 避免在大型数据集上使用无限制的查询
  • 使用分页查询限制返回的数据量
  • 只请求需要的字段,避免过度获取

3. 订阅优化

  • 使用过滤条件减少订阅的数据量
  • 对于频繁更新的数据,考虑使用轮询或批处理更新
  • 监控订阅性能,及时调整策略

4. 数据库优化

  • 定期维护PostgreSQL数据库
  • 调整PostgreSQL配置参数(shared_buffers、work_mem等)
  • 考虑使用连接池提高并发性能

认证集成

1. JWT认证

Hasura支持使用JWT令牌进行认证:

  1. 配置JWT密钥:

    HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"your-secret-key"}'
  2. JWT令牌示例:

    {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": 1516239022,
    "https://hasura.io/jwt/claims": {
    "x-hasura-user-id": "1",
    "x-hasura-role": "user",
    "x-hasura-default-role": "user"
    }
    }

2. Webhook认证

也可以使用自定义Webhook进行认证:

HASURA_GRAPHQL_AUTH_HOOK=http://your-auth-service.com/auth

Webhook需要返回包含Hasura会话变量的JSON响应:

{
"X-Hasura-User-Id": "1",
"X-Hasura-Role": "user",
"X-Hasura-Is-Owner": "true"
}

部署最佳实践

1. 生产环境配置

  • 禁用开发模式和未认证访问
  • 使用强管理员密钥
  • 配置适当的资源限制
  • 启用SSL/TLS加密
# 生产环境环境变量
HASURA_GRAPHQL_ENABLE_CONSOLE=false
HASURA_GRAPHQL_DEV_MODE=false
HASURA_GRAPHQL_ADMIN_SECRET=strong-admin-secret
HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256","jwk_url":"https://your-auth-service.com/.well-known/jwks.json"}'

2. 数据库最佳实践

  • 使用专用的PostgreSQL用户和数据库
  • 配置适当的数据库连接池大小
  • 定期备份数据库
  • 监控数据库性能

3. 高可用性部署

  • 使用多个Hasura实例
  • 配置负载均衡
  • 实现自动扩展
  • 考虑多区域部署

监控和日志

1. 日志配置

Hasura支持多种日志类型:

HASURA_GRAPHQL_ENABLED_LOG_TYPES=startup, http-log, webhook-log, websocket-log, query-log

2. 查询分析

在Hasura控制台中,可以查看和分析查询性能:

  1. 导航到"Settings" > "Logs"标签页
  2. 查看执行的查询和性能指标
  3. 识别慢查询并进行优化

3. 集成监控系统

Hasura可以集成各种监控系统:

  • Prometheus和Grafana
  • Datadog
  • New Relic

Hasura的优缺点

优点

  1. 开发速度快:自动生成GraphQL API,无需编写后端代码
  2. 实时功能强大:内置GraphQL订阅支持
  3. 权限系统灵活:细粒度的访问控制
  4. 易于集成:可以与现有系统和服务集成
  5. 开源免费:核心功能开源免费

缺点

  1. 数据库限制:主要支持PostgreSQL,对其他数据库支持有限
  2. 复杂业务逻辑:复杂的业务逻辑仍需编写自定义服务
  3. 学习曲线:对于GraphQL新手有一定的学习曲线
  4. 自定义功能:某些自定义功能可能需要额外工作

总结

Hasura是一个强大的GraphQL引擎,能够显著加速数据驱动应用的开发。它通过自动生成GraphQL API、提供实时数据订阅、强大的权限控制和事件触发器等功能,使开发者能够专注于业务逻辑的实现,而不必花费大量时间在基础设施和API开发上。

无论是构建原型还是生产级应用,Hasura都能提供高效、灵活的解决方案。通过与PostgreSQL的深度集成和丰富的扩展功能,Hasura为现代Web和移动应用开发提供了强大的支持。