暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

如何将 Heroku Java 应用程序连接到云原生数据库

原创 谭磊Terry 恩墨学院 2022-09-14
250

在这篇文章中,通过查看 Heroku 和 YugabyteDB Managed 的​​几个连接选项,继续使用 Java 创建一个地理分布式信使。

喂,伙计!我从一个短暂的假期回来,准备继续我的宠物项目:Java 中 的地理分布式信使!

如果您对我的开发之旅是如何开始(以及将要进行的)感兴趣,请查看本系列之前的文章:

  • 地理什么?地理分布式应用程序简介
  • 是什么让地理分布式应用程序的架构与众不同?
  • 如何使用 Vaadin、YugabyteDB 和 Heroku 在几天内构建多区域 Java 应用程序。

在上一篇文章中,我启动了我的应用程序的第一个版本,它在Heroku中运行,并使用 YugabyteDB Managed 作为云原生分布式数据库。我现在有信心地理信使可以容忍区域级中断。今天,我将介绍 Heroku 和 YugabyteDB Managed 的​​几个连接选项。

您可能会问,“这两个 SaaS 产品之间的连接有什么问题?”

首先,一旦部署,您的 YugabyteDB 托管实例将不会对整个 Internet 可见。您必须提供应用程序、服务、VM 等的 IP 地址才能连接到数据库。这是云原生数据库常见且合理的需求。对于 MongoDB Atlas、Amazon Aurora 以及任何其他认真对待安全性的云原生数据库来说都是如此。

默认情况下,YugabyteDB 托管 IP 允许列表为空。这意味着我的地理信使的请求将被拒绝。

image.png

你可能会笑着说:“来吧,丹尼斯,在 Heroku 中找到你的应用的静态 IP 地址,然后将其添加到 YugabyteDB!”

这是我的确切想法,伙计!但是,Heroku 在Common Runtime Environment中不提供静态 IP 地址。所以我要么需要切换到包含私人空间的企业计划,要么找到其他选择。考虑到成本(即:便宜),我选择了后者。

所以,如果你在这段旅程中仍然和我在一起,那么,就像海盗们常说的那样,“All Hand Hoy!” 这意味着,“甲板上的每个人!” 让我们回顾一下我使用我的应用程序验证的各种连接选项。

允许所有连接

蛮力解决方案是允许所有连接到我的 YugabyteDB 托管实例。我通过将0.0.0.0/0地址添加到 IP 允许列表来做到这一点。
image.png

如果您处于早期开发阶段(并且希望专注于编码而不是基础设施设置),或者如果您正在 VPC 网络中部署完整的解决方案,我建议您使用此选项。我不停地编码,不想分心,所以我用这个0.0.0.0/0解决方案作为捷径。

一旦我的编码速度变慢,我决定为 Heroku 和 YugabyteDB 托管连接问题找到一个更优雅的解决方案。显然,我不希望我的数据库实例对整个互联网保持开放。

我的下一步是什么?好吧,作为一名在科技行业拥有近 20 年经验的工程师,我完全知道该怎么做:我打开浏览器并在 Google 上搜索“ heroku static ip address java ”。

我很快意识到这个问题是如此普遍,以至于 Heroku 市场上到处都是可以通过静态 IP 地址代理 Heroku 请求的附加组件。(顺便说一句,如果您想提供代理,这是一个很好的商机:创办一家初创公司怎么样?)

然后我浪费了一个小时尝试不同的代理。没有任何效果。YugabyteDB 拒绝了我的地理信使的请求。我挠了挠头,然后又挠了挠。在第三次摸不着头脑之前,我意识到所有这些代理插件仅适用于 HTTP 流量:REST、GraphQL和其他依赖 HTTP 的协议。我的应用程序使用 JDBC 驱动程序,该驱动程序打开与数据库的直接套接字连接并在 PostgreSQL 线路级协议中交换消息。

我的下一步是什么?相信你已经猜到了!我再次求助于谷歌,这次搜索“ heroku socks5 proxy for postgres”,最后发现了对我有用的Fixie Socks插件。

分步说明如下:
1.我安装了 Fixie Socks 插件heroku addons:create fixie-socks:handlebar -a geo-distributed-messenger。您可以将“车把”换成另一层。对于 2,000 个请求,我每月花费 9 美元。还有一个每月 100 个请求的免费选项,称为“grip”。
2.我在仪表板上找到了我的静态 IP,您可以使用以下命令启动:
heroku addons:open fixie-socks.
3.我将这些 IP 添加到 YugabyteDB 托管IP 允许列表中。
4.然后我介绍了自定义环境变量USE_FIXIE_SOCKS,它指示我的应用程序使用或绕过代理heroku config:set USE_FIXIE_SOCKS=true -a geo-distributed-messenger。

当USE_FIXIE_SOCKS设置为 true 时,应用程序配置两个 JVM 级别的属性 (socksProxyHost和socksProxyPort) 要求 Java 通过代理发送所有网络请求:

 if (System.getenv("USE_FIXIE_SOCKS") != null) {
 	boolean useFixie = Boolean.valueOf(System.getenv("USE_FIXIE_SOCKS"));

   if (useFixie) {
     System.out.println("Setting up Fixie Socks Proxy");

     // The FIXIE_SOCKS_HOST variable is added by the add-on to the environment
     String[] fixieData = System.getenv("FIXIE_SOCKS_HOST").split("@");
     String[] fixieCredentials = fixieData[0].split(":");
     String[] fixieUrl = fixieData[1].split(":");

     String fixieHost = fixieUrl[0];
     String fixiePort = fixieUrl[1];
     String fixieUser = fixieCredentials[0];
     String fixiePassword = fixieCredentials[1];

     System.setProperty("socksProxyHost", fixieHost);
     System.setProperty("socksProxyPort", fixiePort);

     System.out.println("Enabled Fixie Socks Proxy:" + fixieHost);

     Authenticator.setDefault(new ProxyAuthenticator(fixieUser, fixiePassword));
   }
 }

在 Heroku 中重新启动应用程序后,我可以连接到 YugabyteDB Managed 并查看应用程序工作区、通道和消息。
image.png

仅对 YugabyteDB 连接使用代理
即使 SOCKS5 代理方法有效,我仍然对我的实现并不完全满意。怎么了?看看这两行:

System.setProperty("socksProxyHost", fixieHost);
System.setProperty("socksProxyPort", fixiePort);

这些是与 JVM 相关的设置,要求每个 TCP/IP 连接都通过我的代理。那是矫枉过正。我只需要连接到 YugabyteDB Managed 的​​代理。

幸运的是,这个任务在 Java 中很容易解决。您只需要提供自定义ProxySelector的实现。这就是我通过引入自己的DatabaseProxySelector类所做的:

public class DatabaseProxySelector extends ProxySelector {

    private String proxyHost;
    private int proxyPort;

    public DatabaseProxySelector(String proxyHost, int proxyPort) {
        this.proxyHost = proxyHost;
        this.proxyPort = proxyPort;
    }

    @Override
    public List<Proxy> select(URI uri) {
        // YugabyteDB Managed host always ends with `ybdb.io`
        if (uri.toString().contains("ybdb.io")) {
            System.out.println("Using the proxy for YugabyteDB Managed: " + uri);

            final InetSocketAddress proxyAddress = InetSocketAddress
                    .createUnresolved(proxyHost, proxyPort);
            return Collections.singletonList(new Proxy(Type.SOCKS, proxyAddress));
        }

        return Collections.singletonList(Proxy.NO_PROXY);
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        new IOException("Failed to connect to the proxy", ioe).printStackTrace();
    }

}

如您所见,DatabaseProxySelector仅对 YugabyteDB 托管 URI 启用 Fixie Socks 代理。最后,选择器实例在应用程序启动时创建:

if (System.getenv("USE_FIXIE_SOCKS") != null) {
  boolean useFixie = Boolean.valueOf(System.getenv("USE_FIXIE_SOCKS"));

  if (useFixie) {
    System.out.println("Setting up Fixie Socks Proxy");

    String[] fixieData = System.getenv("FIXIE_SOCKS_HOST").split("@");
    String[] fixieCredentials = fixieData[0].split(":");
    String[] fixieUrl = fixieData[1].split(":");

    String fixieHost = fixieUrl[0];
    String fixiePort = fixieUrl[1];
    String fixieUser = fixieCredentials[0];
    String fixiePassword = fixieCredentials[1];

    DatabaseProxySelector proxySelector = new DatabaseProxySelector(fixieHost, Integer.parseInt(fixiePort));
    ProxySelector.setDefault(proxySelector);

    Authenticator.setDefault(new ProxyAuthenticator(fixieUser, fixiePassword));

    System.out.println("Enabled Fixie Socks Proxy:" + fixieHost);
  }
}

探索私人空间

一开始,我提到 Heroku 私人空间功能也应该可以工作(如果相信 Heroku 的技术文档的话)。为了完整起见,我在文章中添加了这个选项。从理论上讲,您可以在 Heroku 中设置这些私有空间,并使用 YugabyteDB 托管 VPC 网络对等空间,但我会让您验证这一点!

地平线上有什么?

好吧,伙计。本文总结了我对在单个云区域中运行的当前应用程序版本的想法。现在,让我在进入下一个里程碑之前稍作休息:接下来,我需要地理信使在多个云区域中运行。我将研究 Google Cloud 工具来自动化部署。我会及时向大家发布!

原文标题:How To Connect a Heroku Java App to a Cloud-Native Database
原文作者: Denis Magda
原文地址:https://dzone.com/articles/how-to-connect-a-heroku-app-to-a-yugabytedb-manage

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论