当前位置:首页 > 技术 > 正文内容

Uber 的 MySQL 演进之路:为何 PostgreSQL 未获青睐?

访客 技术 2026年8月15日 1

在软件开发的世界里,尤其是在处理海量数据和高并发场景时,数据库的选择往往至关重要。Uber 曾经面临的挑战,以及他们如何通过深度定制 MySQL 来解决问题,是一个引人入胜的案例。

Uber 初期为何不优先选择 PostgreSQL?

Uber 的业务模式,即时处理庞大的用户、司机数据以及动态的车辆调度,对数据库提出了极高的要求。PostgreSQL 本身是一款功能强大、支持 ACID 事务、拥有标准 SQL 语法和活跃社区的数据库。然而,面对 Uber 级别的数据量(数 PB 级)以及极致的读写、查询和索引压力,PostgreSQL 在某些方面显得力不从心。

尤其是在 I/O 处理能力和水平扩展性方面,PostgreSQL 的原生能力相对较弱,尤其是在分区(Partitioning)功能上,早期版本表现不佳。在分布式数据库解决方案方面,MySQL 的生态系统更为成熟和广泛,拥有像 ShardingSphere、Vitess 这样成熟的代理和中间件,它们大多围绕 MySQL 构建,提供了更便捷的分库分表和数据治理能力。

Java 开发中的连接池陷阱

在 Java 应用中,直接连接 MySQL 进行高并发操作时,务必注意数据库连接池的配置。对于诸如秒杀或实时调度等场景,如果不进行分库分表,很容易导致数据库过载。曾经有开发者在多线程插入数据时,不当的操作直接导致了唯一索引的损坏,引发了系统崩溃。

即使采用了 MySQL 的分表和主从同步方案,Java 应用中的连接池配置也需要谨慎。使用 HikariCP 或 Druid 等连接池时,maximumPoolSize 参数不宜设置过高。一旦出现慢 SQL,过多的连接可能被耗尽,导致整个系统响应缓慢甚至瘫痪。


import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.Connection;
import java.sql.SQLException;

public class DatabaseUtil {

    private static HikariDataSource dataSource;

    static {
        HikariConfig config = new HikariConfig();
        // 替换为实际的数据库连接信息
        config.setJdbcUrl("jdbc:mysql://localhost:3306/uber_db?serverTimezone=UTC");
        config.setUsername("uber_user");
        config.setPassword("secure_password");
        // 合理配置最大连接数,避免资源耗尽
        config.setMaximumPoolSize(30);
        config.setMinimumIdle(10);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);

        dataSource = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void closeDataSource() {
        if (dataSource != null) {
            dataSource.close();
        }
    }

    // 示例:执行一个简单的查询
    public static void main(String[] args) {
        try (Connection conn = getConnection()) {
            // 在这里执行你的 SQL 操作
            System.out.println("Successfully obtained a connection from the pool.");
            // Example: PreparedStatement ps = conn.prepareStatement("SELECT 1");
            // ResultSet rs = ps.executeQuery();
            // if (rs.next()) { System.out.println("Query successful."); }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeDataSource();
        }
    }
}

Uber 对 MySQL 的深度定制

Uber 采取了一种激进的策略:直接修改 MySQL 的源码,并围绕其构建了一个名为 "Schemaless" 的系统。虽然底层内核仍是 MySQL,但该系统极大地增强了 MySQL 的水平扩展能力,实现了自动化的数据分区、分片和负载均衡,显著减少了对 DBA 手动干预的需求。

此外,Uber 还将部分冷数据迁移到其他更适合归档的存储系统中,而将热数据保留在 MySQL 中,从而大幅提升了写入吞吐量。

PostgreSQL 在 Uber 场景下的劣势

需要强调的是,这并非否定 PostgreSQL 的能力。在 Uber 做出选择的那个时期(大约五六年前),PostgreSQL 在大规模、高并发水平扩展方面的原生支持确实不如 MySQL 成熟。PostgreSQL 更适合执行复杂的分析查询、报表生成,或处理具有复杂 SQL 逻辑的场景。

然而,对于 Uber 这种读写密集、追求极致低延迟的在线事务处理(OLTP)系统,PostgreSQL 在水平扩展和高可用性(如热备份)方面存在局限。若要实现分布式部署,往往需要投入大量资源自行开发和维护相关组件,成本较高。

日常开发者的数据库选择考量

对于 Java 开发者而言,MySQL 拥有极其丰富的生态支持,包括 MyBatis、JPA、Hibernate 等成熟的 ORM 框架,使用起来更为便捷。在与 PostgreSQL 交互时,有时会遇到驱动兼容性问题,例如某些版本的时间类型与 Java 的 LocalDateTime 存在差异,这可能增加开发复杂度。

以下是一个使用 PreparedStatement 执行查询的 Java 代码示例,该示例在 MySQL 下通常能获得良好的性能表现,并且有大量的优化经验可循,如主从同步、索引调优等:


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class OrderQuery {

    // 假设 conn 是一个有效的数据库连接
    public void fetchOrdersByUser(Connection conn, long userId) throws SQLException {
        String querySql = "SELECT order_id, order_amount, create_time FROM orders WHERE user_id = ? ORDER BY create_time DESC";
        try (PreparedStatement preparedStmt = conn.prepareStatement(querySql)) {
            preparedStmt.setLong(1, userId);
            try (ResultSet resultSet = preparedStmt.executeQuery()) {
                while (resultSet.next()) {
                    long orderId = resultSet.getLong("order_id");
                    double amount = resultSet.getDouble("order_amount");
                    java.sql.Timestamp createTime = resultSet.getTimestamp("create_time");
                    // 处理查询结果...
                    System.out.println("Order ID: " + orderId + ", Amount: " + amount + ", Time: " + createTime);
                }
            }
        }
    }
}

尽管 PostgreSQL 在功能上同样强大,但许多公司缺乏进行大规模部署和优化的基础设施和专业团队。若出现问题,排查和恢复也更为复杂。

总而言之,Uber 选择 MySQL 并非因为它比 PostgreSQL 优秀,而是因为其独特的业务场景对数据库的水平扩展能力提出了近乎极限的要求。MySQL 及其成熟的周边工具链,在当时为 Uber 提供了更低的迁移成本和更快的迭代速度。对于开发者而言,理解不同数据库的优劣势,并结合自身业务需求进行选择,是做出明智技术决策的关键。

返回列表

上一篇:MyBatis-Plus 核心源码解析

没有最新的文章了...

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。