我在 AWS EC2 m4.large 实例上运行 MongoDB(v3.4 社区版)。我按照此步骤安装它MongoDB 教程。我没有修改任何 MongoDB 配置。我没有配置任何副本集或分片。我有一个 Jersey API,它使用以下方式与 MongoDB 交互org.mongodb.morphia (v1.3.2) Java 驱动程序。
我使用 SoapUI 创建了一个负载测试,其中我调用了 100 次 API,从而为 MongoDB 创建了 100 次写入操作(每次写入操作在一个集合中创建一个文档)。我运行了 24 小时的测试。最后,我看到我的 Web 服务器尝试与 Mongo 服务器通信,但连接超时,主机 CPU 以 100% 的运行速度运行。我得出结论,MongoDB 服务器正在阻塞。
然后我尝试了这个基准测试,仍然使用托管在 m4.large 上的数据库。在 923.133 秒内创建了 50,000,000 条记录,即每秒插入 54,113 条。速度快了 500 多倍!
如果 MongoDB 性能如此出色,那么为什么在使用 JAVA 驱动程序时,每秒插入 100 条数据就会卡住?Java 驱动程序慢吗?我对 Java 驱动程序的使用是否错误?我的 EC2 实例大小是否太小?添加复制(RAID 和副本集)是否有帮助?
我是 MongoDB 托管的新手,非常感谢您的学习帮助。
更新:
负载测试配置:
客户端:SoapUI (v5.3)、Web 服务器:Tomcat 8、Java:v1.8、MongoDB:v3.4。我的所有服务器都在 AWS 孟买地区运行。我在同一个 EC2 实例 (m4.large) 上托管 Web 服务器和 MongoDB 服务器,并在 Windows 机器 (t2.micro) 上运行客户端。
经过进一步调查,我认为瓶颈在于我的代码。我使用了蒙哥斯塔特实用程序来查看 mongodb 的行为。我发现,开始时有两个连接。一旦启动负载测试,连接数就会跳转到 102(即使每秒有 1000 个请求,连接数也不会超过 102,MongoDB 会在很长时间后关闭它们)。负载是每秒 100 个请求。以下是显示此行为的 gif。
我发现了一些有类似问题的问题,但答案并没有透露太多信息。我已经采纳了这些建议。以下是一些示例,
https://stackoverflow.com/questions/21580147/mongo-connection-leak-with-morphia
https://stackoverflow.com/questions/31469656/spring-data-mongodb-not-closing-mongodb-connections
Java代码:
创建连接:我按照 MongoDB 的建议为我的应用程序使用一个连接。实现单例模式。
public class DatabaseConnection {
private static volatile MongoClient instance;
private static String cloudhost="localhost";
private DatabaseConnection() { }
public synchronized static MongoClient getMongoClient() {
if (instance == null ) {
synchronized (DatabaseConnection.class) {
if (instance == null) {
ServerAddress addr = new ServerAddress(cloudhost, 27017);
List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
MongoCredential credentia = MongoCredential.createCredential(
"test", "test", "test".toCharArray());
credentialsList.add(credentia);
instance = new MongoClient(addr, credentialsList);
}
}
}
return instance;
}
}
示例数据访问对象类:
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.dao.BasicDAO;
import Sample;
public class SampleDao extends BasicDAO<Sample, String>{
public SampleDao(Class<Sample> entityClass, Datastore ds) {
super(entityClass, ds);
}
}
示例存储库类:此类负责与数据库交互并持久保存文档
public class SampleRepository {
private SampleDao sampleDao;
public SampleRepository ()
{
try
{
MongoClient mongoClient = DatabaseConnection.getMongoClient();
Datastore ds = new Morphia().map(Pour.class)
.createDatastore(mongoClient, "test");
sampleDao = new SampleDao(Sample.class,ds);
}
catch (Exception e)
{
logger.error("Error while creating SampleDao", e);
}
}
public String createSample (Sample sample)
{
try
{
Sample2Repository repo = new Sample2Repository ();
Sample2 sample2 = repo.getSample2(sample.getSampleId());
Sample.setSample2Id(sample2.getId());
retur sampleDao.save(sample).getId().toString();
}
catch (Exception e)
{
logger.error("Error while creating sample.", e);
return null;
}
}
}
示例文档:我认为我的文档大小不会对 MongoDB 造成问题。负载测试期间没有调用其他查询。只有 CreateSample 操作正在运行。
{
"sample2Id":"593e346cfeaa9e62d1706bb5"
, "sample3Id" : "593e4159729f5d04db7b6da2"
, "actualTime":"21/06/2017 09:18:00"
, "uploadTime":"21/06/2017 09:18:00"
}