Sep
28
2023
--

Replace a Live Mongo Node With a New Node

replace a live mongo node

In this blog post, we will discuss replacing a Mongo node. Consider a scenario when a node is going to be decommissioned for some reason or if a node’s data partition is almost full and not extendable. To avoid the disk getting full or decommissioned, we need to replace that node with a new node.

Note: Make sure to have enough oplog window to cover this activity. Make sure you have an up-to-date backup of your data set. To get a consistent backup, stop the writes to the MongoDB instance and take a snapshot of the volume. Here, we will take a hotbackup or EBS snapshot of the node and will use it to replace the node.

If the node that is going to be replaced is part of a replica set Primary-Secondary-Arbiter (PSA) with three voting members, then make sure writeConcern is not set as majority; it may timeout or never be acknowledged.

To replace a live node from shards/replica set

Let’s say it’s an EBS snapshot. An EBS snapshot can be created by selecting the EC2 instance and its respective volume.

EBS snapshot

Select the respective data volume /dev/sdb and create a snapshot. Make sure to select the correct volume ID.

Note: The time to create the snapshot may be several hours, depending on the size of large initial snapshots or subsequent snapshots where many blocks have changed.

Create a new instance of a similar instance type (which is going to be replaced) by using the AMI of one of the current EC2 nodes. 

AMI of one of the current EC2 nodes

Create volume from the EBS snapshot by choosing the correct Snapshot ID. Define the EBS size that suffices for your use case.

 Attach the EBS volume to the newly created instance.

Once attached, connect to the EC2 instance and attach the volume (make sure to keep the correct device name).

Initialize the volume created from the snapshot. For more details, check the Initialize Amazon EBS volumes on Linux doc.

sudo dd if=/dev/xvdf of=/dev/null bs=1M

And then mount the volume to a directory.

sudo mkdir /mongo_data
sudo mount /dev/xvdf /mongo_data/

If it’s a hot backup (learn how to take a hot backup), launch an instance for MongoDB using the AMI of one of the current EC2 nodes and attach the desired volume size to this instance. Copy the hot backups to it.

Here, it may have two cases.

Case 1: When you have members in the replica set as DNS names. In this case, follow the below steps:

  • Add newly launched node to the shard from the existing primary node.
rs.add("newly-launch-host:27018")

  • For now, reduce its priority once it comes in sync, as we don’t want this node to become a Primary. Note down the correct member “_id” of the new node.
cfg = rs.conf()
cfg.members[_id].priority = 0.5
rs.reconfig(cfg)

  • Remove the old node from the replica set, shut down its mongo services, and verify it’s completely removed.
rs.remove("old-shard-host:27018")
rs.conf()

Shut down the mongo service from the old node.

sudo systemctl stop mongod

  • Adjust the newly-launch hostname to the node which we are going to remove.

So, the desired hostname of the newly-launched host would become:

Newly-launch-host ->  old-shard-host

Once the newly launched hostname is changed, adjust its hostname info in /etc/hosts for all nodes of the sharded cluster and application.

Note: Make sure all connectivity is tested between all nodes to the new nodes on mongo port.

  • Connect to the existing primary node of the shards or replica set, and change the hostname of the newly launched node from rs.conf(). Make sure to use correct _id to adjust the hostname of the newly launched node only.
cfg = rs.conf()
cfg.members[_id].hostname = "old-shard-host:27018"
rs.reconfig(cfg)

  • Revert back the priority of the newly launched node to 1. Again, make sure to use correct _id to adjust the priority of the newly launched node only.
cfg = rs.conf()
cfg.members[_id].priority = 1
rs.reconfig(cfg)

Case 2: When you have members in the shard/replica set as IPs, not as DNS name.

  • Start the new node as a standalone mode with attached backups to it, edit the system.replset, and update new node IPs by replacing old node IPs, which are going to be removed. A “role” : “__system” should be granted to the user you are using to connect to the node. 

Note: It gives access to every resource in the system and is intended for internal use only. Do not use this role other than in exceptional circumstances.  

  • Remove the old node from the replica set, shut down its mongo services, and verify it’s completely removed.
rs.remove("old-node-ips:27018")
rs.conf()

  • Shut down the mongo service from the old node.
sudo systemctl stop mongod

  • Re-start the new node in replication mode and add it from the primary.
rs.add("new-node-ips:27018")

Verify the replication status for the newly-launch node. If everything goes well, your old instance has been replaced with the new node.

Conclusion

Nowadays, being on the cloud, it’s common for a node to get retired or decommissioned. With the above-mentioned approach, we can easily replace a Mongo node with a new node.

We encourage you to try our products for MongoDB, like Percona Server for MongoDB, Percona Backup for MongoDB, or Percona Operator for MongoDB. Also, we recommend reading our blog MongoDB: Why Pay for Enterprise When Open Source Has You Covered?

Jul
26
2023
--

Ten Recommendations for Running Your MongoDB Environment

Running Your MongoDB Environment

MongoDB is a non-relational document database that provides support for JSON-like storage. It provides a flexible data model allowing you to easily store unstructured data. First released in 2009, it is the most used NoSQL database and has been downloaded more than 325 million times.

MongoDB is popular with developers as it is easy to get started with. Over the years, MongoDB has had many features introduced that have turned the database into a robust solution able to store terabytes of data for applications.

As with any database, developers and DBAs working with MongoDB should look at how to optimize the performance of their database, especially nowadays with cloud services, where each byte processed, transmitted, and stored costs money. The ability to get started so quickly with MongoDB means that it is easy to overlook potential problems or miss out on simple performance improvements. In this piece, we’ll look at ten essential techniques you can apply to make the most of MongoDB for your applications.

Tip #1:

Always enable authorization for your production environments

Securing your database from the beginning prevents unauthorized access and security breaches. This is especially important in today’s times of escalated hacking attempts.

The bigger the database, the bigger the damage from a leak. There have been numerous data leaks due to the simple fact that authorization and authentication are disabled by default when deploying MongoDB for the first time. While it is not a performance tip, it is essential to enable authorization and authentication right from the start, as it will save you any potential pain over time due to unauthorized access or data leakage.

When you deploy a new instance of MongoDB, the instance has no user, password, or access control by default. In recent MongoDB versions, the default IP binding changed to 127.0.0.1, and a localhost exception was added, which reduced the potential for database exposure when installing it. 

However, this is still not ideal from a security perspective. The first piece of advice is to create the admin user and restart the instance again with the authorization option enabled. This prevents any unauthorized access to the instance. 

To create the admin user:

> use admin
switched to db admin
> db.createUser({
...   user: "zelmar",
...   pwd: "password",
...   roles : [ "root" ]
... })
Successfully added user: { "user" : "zelmar", "roles" : [ "root" ] }
Then, you need to enable authorization and restart the instance, if you are deploying MongoDB from the command line:
mongod --port 27017 --dbpath /data/db --auth
Or if you are deploying MongoDB using a config file, you need to include:
security:
    authorization: "enabled"

 

Tip #2:

Always upgrade to the latest patch set for any given major version

Sometimes companies have to stay in versions that have gone EOL (End-of-Life) due to legacy application or driver dependency issues. It is recommended to upgrade your stack as soon as possible to take advantage of improvements and any security-related software updates.

It is critically important not to use versions that are labeled with “critical issues” or “not recommended for production use” warnings. Those releases have been found to have to include bugs that can cause serious performance impacts or cause issues with data integrity – potentially causing data corruption or data loss.

It should seem obvious, but one of the most common issues we see with production instances is due to developers running a MongoDB version that is actually not suitable for production in the first place. This can be due to the version being outdated, such as with a retired version that should be updated to a newer iteration that contains all the necessary bug fixes. Alternatively, we can choose a version that is too early and not yet tested enough for production use.

This can be due to a few different reasons. As developers, we are normally keen to use our tools’ latest and greatest versions. We also want to be consistent over all the stages of development, from initial build and test through to production, as this decreases the number of variables we have to support, the potential for issues, and the cost to manage all those instances.

For some, this can mean using versions that are not signed off for production deployment yet. For others, it can mean sticking with a specific version that is tried and trusted. This is a problem from a troubleshooting perspective when an issue is fixed in a later version of MongoDB that is approved for production but has not been deployed yet. Alternatively, you may forget about that database instance that is ‘just working’ in the background and miss when you need to implement a patch!

In response to this, you should regularly check if your version is suitable for production using the release notes of each version. For example, MongoDB 5.0 provides the following guidance in its release notes: https://www.mongodb.com/docs/upcoming/release-notes/5.0/ 

The guidance here would be to use MongoDB 5.0.11, as this has the required updates in place. If you don’t update to this version, you will run the risk of losing data.

While it might be tempting to stick with one version, keeping up with upgrades is essential to prevent problems in production. You may want to take advantage of newly added features, but you should put these through your test process to see if there are any problems that might affect your overall performance before moving into production too.

Lastly, you must check the MongoDB Software Lifecycle Schedules and anticipate the upgrades of your clusters before the end of life of each version: https://www.mongodb.com/support-policy/lifecycles

End of life versions do not receive patches, bug fixes, or any kind of improvements. This can leave your database instances exposed and vulnerable.

From a performance perspective, getting the right version of MongoDB for your production applications involves being ‘just right’ – not too near the bleeding edge that you encounter bugs or other problems, but also not too far behind that you miss out on vital updates.

Tip #3:

Always use Replica Sets with at least three full data-bearing nodes for your production environments

A replica set is a group of MongoDB processes that maintains the same data on all the nodes used for an application. It provides redundancy and data availability for your data. When you have multiple copies of your data on different database servers —  or even better, in different data centers worldwide — replication provides a high level of fault tolerance in case of a disaster. 

MongoDB replica sets consist of PRIMARY and SECONDARY nodes. The PRIMARY node receives writes from the application server and then automatically replicates or copies the data to all SECONDARY nodes via the built-in replication process, which apply changes via the oplog. Replication provides redundancy, and having multiple copies of the same data increases data availability.

It is best practice to have an odd number of replica set members to maintain voting quorum. The minimum number of replica set members for a replica set is three nodes. A replica set can currently have up to 50 nodes. Only seven of those members can have voting rights. Those votes determine which member becomes PRIMARY in case of problems, failovers, or elections.

The basic replica set would consist of the following:

  • PRIMARY 
  • SECONDARY 
  • SECONDARY

All the nodes of the replica set will work together, as the PRIMARY node will receive the writes from the app server, and then the data will be copied to the secondaries. If something happens to the primary node, the replica set will elect a secondary as the new primary. To make this process work more efficiently and ensure a smooth failover, it is important to have the same hardware configuration on all the nodes of the replica set. Additionally, secondary nodes can be used to improve or direct reads by utilizing options such as secondaryPreferred or nearest to support hedged reads. 

After you deploy a replica set on production, it is important to check the health of the replica and the nodes. MongoDB has two important commands to check this in practice.

rs.status() provides information on the current status of the replica set using data derived from the heartbeat packets sent by the other members of the replica set. It’s very useful as a tool to check the status of all the nodes in a replica set.

rs.printSecondaryReplicationInfo() provides a formatted report of the replica set status. It’s very useful to check if any of the secondaries are behind the PRIMARY on data replication, as this would affect your ability to recover all your data in the event of something going wrong. If secondaries are too far behind the primary, then you can end up losing a lot more data than you are comfortable with.

However, these commands provide point-in-time information rather than continuous monitoring for the health of your replica set. In a real production environment, or if you have many clusters to check, running these commands can become time-consuming and annoying, so we recommend using a monitor system for your clusters, like Percona Monitoring and Management, to monitor them.

Tip #4:

Avoid the use of Query types or Operators that can be expensive

Sometimes the simplest way to search for something in a database is to use a regular expression or $regex operation. A lot of developers choose this option but it can actually harm your search operations at scale. Instead, you must avoid the use of $regex queries, especially when your database is big.

A $regex query consumes a lot of CPU time and it will normally be extremely slow and inefficient. Creating an index doesn’t help so much and sometimes the performance is worse than without indexes. 

For example, we can use a $regex query on a collection of 10 million documents and use .explain(true) to view how many milliseconds the query takes.

Without an index:

>db.people.find({"name":{$regex: "Zelmar"}}).explain(true)
- -   Output omitted  - -
"executionStats" : {
                "nReturned" : 19851,
                "executionTimeMillis" : 4171,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 10000000,
- -   Output omitted  - -
And if we created an index on "name":
db.people.find({"name":{$regex: "Zelmar"}}).explain(true)
- -   Output omitted  - - 
  "executionStats" : {
                "nReturned" : 19851,
                "executionTimeMillis" : 4283,
                "totalKeysExamined" : 10000000,
                "totalDocsExamined" : 19851,
- -   Output omitted  - -

We can see in this example that the index creation didn’t help to improve the $regex performance.

It’s common to see a new application using $regex operations for search requests. This is because neither the developers nor the DBAs notice any issues in performance to begin with because the size of the collections is small, and the users at the beginning of any application are very few.

However, when the collections become bigger, and more users start to use the application, the $regex operations start to slow down the cluster and become a nightmare for the team. Over time, as your application scales and more users want to carry out search requests, the level of performance can drop significantly.

Rather than using $regex queries, you can use text indexes to support your text search.

This is more efficient than $regex but needs you to prepare in advance by adding text indexes to your data sets. They can include any field whose value is a string or an array of string elements. A collection can only have one text search index, but that index can cover multiple fields.

Using the same collection of the example, we can test how many milliseconds take the same query using text search:

> db.people.find({$text:{$search: "Zelmar"}}).explain(true)
- -   Output omitted  - -
"executionStages" : {
                         "nReturned" : 19851,
                        "executionTimeMillisEstimate" : 445,
                        "works" : 19852,
                        "advanced" : 19851,
- -   Output omitted  - -

In practice, the same query with text search took four seconds less than the $regex query. Four seconds in “database time,” let alone online application time, is a lot.

To conclude, if you can solve the query using Text Search, use it instead of using $regex and reserve $regex for use cases where they are really necessary and always limit the use of other query patterns and operators such as findAndModify and $NIN.  

Tip #5:

Think wisely about your index strategy

Putting some thought into your queries at the start can have a massive impact on performance over time. First, you need to understand your application and the kinds of queries that you expect to process as part of your service. Based on this, you can create an index that supports them. 

Indexing can help to speed up read queries, but it comes with an extra cost of storage, and they will slow down write operations. Consequently, you will need to think about which fields should be indexed so you can avoid creating too many indexes.

For example, if you are creating a compound index, the Equality, Sort, Range rule is a must to follow, and using an index to sort the results improves the speed of the query.

Similarly, you can always check if your queries are really using the indexes that you have created with .explain(). Sometimes we see a collection with indexes created, but the queries either don’t use the indexes or instead use the wrong index entirely. It’s important to create only the indexes that will actually be used for the read queries. Having indexes that will never be used is a waste of storage and will slow down write operations.

When you look at the .explain() output, three main fields are important to observe. For example:

keysExamined:0 
docsExamined:207254 
nreturned:0

In this example, no indexes are being used. That is because the number of keys examined is 0 while the number of documents examined is 207254. Ideally, the query needs to have the ratio nreturned/keysExamined=1. For example:

keysExamined:5 
docsExamined: 0 
nreturned:5

As a final piece of advice, if with .explain() you see a particular query using a wrong index, you can force the query to use a particular index with .hint() This overrides MongoDB’s default index selection and query optimization process, allowing you to specify the index that is used or to carry out a forward collection or reverse collection scan. 

Percona Distribution for MongoDB: Performant, enterprise-grade MongoDB software free of licensing fees and lock-in.

Tip #6:

Watch for changes in query patterns, application changes, or index usage over time

Every database is unique and particular to that application, and they grow and change through time. Nobody knows how an application will grow over time or how the queries will change over time too. Whatever assumptions you make, your prediction will inevitably be wrong, so it is essential to check your database and indexes over time.

For instance, you may plan a specific query optimization approach and a particular index, but after one year, you realize a few queries are using that index, and it’s not necessary anymore. Carrying on with this approach will cost you more in storage while not providing any improvements in application performance.

For this reason, it’s necessary to perform query optimizations and look at the indexes for each collection frequently.

MongoDB has some tools to do query optimization, such as the database profiler or the .explain() method; we recommend using them to find which queries are slow, how the indexes are being used by the queries, and where you may need to improve your optimizations.

Alongside removing indexes that are not used efficiently, look out for duplicate indexes that you don’t need to run as well.

We use some scripts to check if there are duplicate indexes or if there are any indexes that are not being used. You can check and use them from our repository: 

https://github.com/percona/support-snippets/tree/master/mongodb/scripts

Similarly, you can look at how many results you want to get from a query, as providing too many results can have a performance and time impact. You can limit the number of query results with .limit(), as sometimes you only need the first five results of a query rather than tens or hundreds of responses.

Another useful approach is to use projections to get only the necessary data. If you need only one field of the document, use projection instead of getting the entire document and then filter on the app side.

Lastly, if you need to order the results of a query, be sure that you are using an index and take advantage of it to improve your efficiency.

Tip #7:

Don’t run multiple mongoD on the same server

Even if it’s possible to run multiple MongoD on the same server using different processes and ports, we strongly recommend not doing this.

When you run multiple MongoD processes on the same server, it’s very difficult to monitor them and the resources they are consuming (CPU, RAM, Network, etc.). Consequently, if there is any problem, it is extremely difficult to find out what is going on and get to the root cause of that issue.

We have a lot of cases where customers have found a resource problem on the server, and because they are running multiple instances of MongoD it’s impossible to troubleshoot the problem because discovering which specific process has the problem is more difficult.

Similarly, sometimes we can see that developers have implemented a sharded cluster to scale up their application data, but then multiple shards are running on the same server. In these circumstances, the router will send a lot of queries to the same node. This may overload the node leading to poor performance, which is the opposite of what the sharding strategy wants to solve.

The worst-case scenario for these kinds of deployments involves replica sets. Imagine running a replica set for resiliency and availability, and then more than one member of the replica set is running on the same server. This is a recipe for potential disaster and data loss if the physical server that supports those nodes has a problem. Rather than architecting your application for resiliency, you would have made the whole deployment more likely to fail.

If you have a larger sharded environment where you are using many MongoS (query router) processes, it is possible to run multiple MongoS processes on the same nodes. If you choose to do so, it is recommended to run those in separate containers or VMs to avoid “noisy neighbor” resource contention issues and to aid in troubleshooting.

Tip #8:

Employ a reliable and robust backup strategy

So, you have a cluster with replication, but do you want to sleep better? Do backups of your data frequently!

Having backups of your data is a good strategy and allows you to restore the data from an earlier moment if you need to recover it from an unplanned event.

There are different options to backup your data:

Mongodump / Mongorestore: Mongodump reads data from MongoDB and creates a BSON file that Mongorestore can use to populate a MongoDB database. There are efficient tools for backing up small MongoDB deployments. On the plus side, you can select a specific database or collection to back up efficiently, and this approach doesn’t require stopping writes on the node. However, this approach doesn’t back up any indexes you have created, so when restoring, you would need to re-create those indexes again. Logical backups are, in general, very slow and time-consuming, so you would have to factor that time into your restore process. Lastly, this approach is not recommended for sharded clusters that are more complex deployments.

Percona Backup for MongoDB is an open source, distributed, and low-impact solution for consistent backups of MongoDB sharded clusters and replica sets. It enables backups for MongoDB servers, replica sets, and sharded clusters. It can support logical, physical, and point-in-time recovery backups and backups to anywhere, including AWS S3, Azure, or filesystem storage types.

However, it does require initial setup and configuration on all the nodes that you would want to protect.

Physical / File system Backups  You can create a backup of a MongoDB deployment by making a copy of MongoDB’s underlying data files.

You can use different methods for this type of backup, from manually copying the data files, Logical Volume Management (LVM) based snapshots to cloud-based snapshots. These are usually faster than logical backups and can be copied or shared to remote servers. This approach is especially recommended for large datasets, and it is convenient while building a new node on the same cluster.

However, you cannot select a specific database or collection when restoring, and you cannot do incremental backups. 

Lastly, running a dedicated node is recommended for taking the backup as it requires halting writes, affecting application performance.

Any chosen solution must include testing your restore process periodically.

Tip #9:

Know when to shard your replica set and why choosing a shard key is important

Sharding is the most complex architecture you can deploy with MongoDB

As your database grows, you will need to add more capacity to your server. This can involve adding more RAM, more I/O capacity, or even more powerful CPUs to handle processing. This is called vertical scaling. However, if your database grows so much that it goes beyond the capacity of a single machine, then you may have to split the workload up. Several things might lead to this — for instance, there may not be a physical server large enough to handle the workload, or the server instance would cost so much that it would be unaffordable to run. In these circumstances, you need to start thinking about sharding your database, which is called horizontal scaling.

Horizontal Scaling involves dividing the database over multiple servers and adding additional servers to increase capacity as required. For MongoDB, this process is called sharding, and it relies on a sharding key to manage how workloads are split up across machines.

Choosing a sharding key must be the most difficult task on MongoDB. It’s necessary to think, study the datasets and queries, and plan ahead before choosing the key because it’s very difficult to revert the shard once it has been carried out. For versions of MongoDB before version 4.2, assigning a shard key is a one-way process that cannot be undone. For versions of MongoDB over 4.4, it is possible to refine a shard key, while MongoDB 5.0 and above can change the shard key with the reshardCollection command.

If you choose a bad shard key, then a large percentage of documents may go to one of the shards and only a few to another. This will make the sharded cluster unbalanced, affecting performance over time. This typically happens when a key that grows monotonically is chosen to shard a collection, as all the files over a given value would go to one shard rather than being distributed evenly.

Alongside looking at the value used to shard data, you will also need to think about the queries that will take place across the shard. The queries must use the shard key so the MongoS distributes the queries across the sharded cluster. If the query doesn’t use the shard key, then the MongoS will send the query to every shard of the cluster, affecting performance and making the sharding strategy inefficient.

“For versions of MongoDB over 4.4, it is possible to refine a shard key, while MongoDB 5.0 and above can change the shard key with the reshardCollection command.

The ability to reshard is something that developers and DBAs have been requesting for a long time. However, be aware that the resharding process is very resource intensive and can have negative performance impacts, especially when dealing with applications that have heavy write patterns.

Tip #10:

Don’t throw money at the problem

Last, but not least, it’s very common to see teams throwing money at the problems that they have with their databases.

Adding more RAM, more CPU, and moving to a larger instance or a bigger machine can overcome a performance problem. However, carrying this kind of action out without analyzing the real problem or the bottleneck can lead to more of the same kinds of problems in the future. Instead of immediately reaching for the credit card to solve the problem, sometimes it is better to think laterally and imagine a better solution. In most cases, the answer is not spending more money on resources but looking at optimizing your implementation for better performance at the same level.

While cloud services make it easy to scale up instances, the cost can quickly mount up. Worse, this is an ongoing expense that will carry on over time. By looking first at areas like query optimization and performance, it’s possible to avoid additional spending. For some of the customers we worked with, they were able to downgrade their EC2 instances, saving their companies a lot of money monthly.

As a general recommendation, adopt a cost-saving mindset where you can take your time to analyze the problem and think of a better solution than starting with cloud expansions.

Percona Distribution for MongoDB is a freely available MongoDB database alternative, giving you a single solution that combines the best and most important enterprise components from the open source community, designed and tested to work together.

 

Download Percona Distribution for MongoDB Today!

Jul
24
2023
--

Announcing the Availability of Percona Backup for MongoDB 2.2.0

percona backup for mongodb

In the previous minor release, Percona Backup for MongoDB 2.1.0 (PBM) introduced a GA version of incremental physical backups, which can greatly impact both the recovery time and the cost of backup (considering storage and data transfer cost). Back then, we already knew that our customers needed to back up:

  • More data
  • Faster
  • Using existing tools

During all conversations we’ve had with our Community, customers, and prospects, we’ve noticed how popular the usage of snapshot tools is. While AWS EBS snapshots were mentioned the most, the likes of persistent disk snapshots on GCP, Azure-managed disk snapshots, or local storage, as well as k8s snapshot capabilities, were also playing a crucial part in the backup strategies.

To make sure that Percona Backup for MongoDB answers the pains of our customers, we took the common denominator of the pains that anyone using snapshot capabilities faces when performing backups and restores and positioned PBM as the open source, freely available answer to those pains.

Snapshot backup/restore Technical Preview

As already promised during Percona Live 2023, it’s my pleasure to deliver on that promise. I am happy to announce that with PBM 2.2.0, we are launching the technical preview for Percona Backup for MongoDB snapshot CLI.

With the use of this snapshot CLI, you can now build your backup strategy using the snapshot tools at your disposal or include PBM into your existing strategy, even using existing snapshots of Percona Server for MongoDB!

Now why Technical Preview, you may ask? Well, it is because we believe that open source philosophy is not only about the source but also about design and decision-making. We want to ensure that our Community feels that this design we delivered fits their use cases. We hope for a dialogue with you, our users, to make sure we are fixing your pains in the best way we can. So please do not hesitate and:

  • Provide feedback in the feedback form.
  • Engage on our Community pages (there is even a placeholder topic for this!)
  • Contact me through any channels (we do have our Jira open to the Community, my email is available in the footnote, and I am present on LinkedIn).

Physical backups Point in Time Recovery (PITR)

MongoDB Inc. provides only limited backup/restore capabilities with their Community Edition. These are, respectively, the widely adopted mongodump/mongorestore that also Percona Backup for MongoDB uses for what we call logical backups.

While this type of backup is very convenient for smaller data sets, it has certain limitations regarding larger ones. The main limitations are the RPO and RTO. While RPO is addressed with Point in Time Recovery (PITR) that works by default with logical backups, for RTO improvement, we introduced physical backups. In short, for larger datasets, there is a very distinctive speed improvement in recovery.

By default, the PITR capabilities were designed to work with logical backups, and we want to make the user experience as good as physical backups. While for previous versions, PITR works well with physical backups, some operational limitations require some more manual operations.

With PBM 2.2.0, we introduce numerous fixes that put these limitations in the past:

  • Previously the database, after restoring from a full backup, was allowing connections that required manual changes to restrict users from connecting to it before the PITR restore finishes so that the result of the restore process guarantees data integrity.
  • The restore process for physical backups + PITR up until now was not handled in one command, making the user experience not as good as for the logical backups + PITR.

Fixes, bugs, improvements – all is here!

Of course, each release also includes bug fixes and refining some of the existing features. This one is no different. Outside of your typical array of bugs and patches, we have noticed that the way that physical restores handle the remapping of replica sets needs improvement so that you can notice a better-handled experience there.

Feedback is also a contribution

Contribution is not only code. Feedback, adoption and usage data, bug reports, success stories, case studies, testimonials — all these are contributions. Engaging with Community in meaningful discussions is also a contribution. All of these help us grow and help us deliver a better product.

We appreciate any contribution. Again, even negative feedback is something we can use to make the product evolve!

What’s next?

I hope that next, we will close the gap between the capabilities of physical and logical backups by:

  • Selective backup/restore
  • Further improvements on physical PITR, if needed

and, of course, deliver GA capabilities of snapshot backup/restore based on your feedback.

There is also a lot of work around Percona Monitoring and Management (PMM) for MongoDB and some new improvements coming for Percona Operator for MongoDB.

 

Learn more about Percona Backup for MongoDB 2.2.0

Jul
17
2023
--

An Enterprise-Grade MongoDB Alternative Without Licensing or Lock-in

Enterprise-Grade MongoDB Alternative

MongoDB Community Edition software might set the stage for achieving your high-volume database goals, but you quickly learn that its features fall short of your enterprise needs.

So you look at MongoDB Enterprise software, but its costly and complex licensing structure does not meet your budget goals. You’re also not certain its features will always align with your evolving technology needs. What’s more, you’re wary of the expenses and restrictions of vendor lock-in.

Still, you don’t want to ditch the advantages of MongoDB Enterprise software. But you can’t absorb the negatives, either.

Don’t despair; there are alternatives. In this blog, we’ll examine the reasons why people would seek an alternative to MongoDB Enterprise, and we’ll identify some of the most popular NoSQL alternatives. Then, we’ll highlight some reasons why Percona Software for MongoDB might be the alternative you seek.

First, some stage-setting for this blog article.

The popularity of MongoDB

MongoDB has emerged as a popular database platform. It ranks No. 5 among all database management systems and No. 1 among non-relational/document-based systems (DB-Engines, July 2023).

Developers and DBAs like MongoDB’s ease-of-use. Instead of the table-based structure of relational databases, MongoDB stores data in documents and collections, a design for handling large amounts of unstructured data and for real-time web applications. DBAs and developers appreciate its combination of flexibility, scalability, and performance.

More specifically, DBAs and developers like that MongoDB stores data in JSON-like documents with optional schemas. It’s a good setup for real-time analytics and high-speed logging.

Taking a deeper dive, MongoDB is a system for analyzing data because documents are easily shared across multiple nodes and because of its indexing, query-on-demand, and real-time aggregation capabilities. MongoDB replica sets enable data redundancy and automatic failover, setting the stage (there’s that term again) for high availability. MongoDB also provides strong encryption and firewall security. MongoDB is preferable for working with content management systems and mobile apps.

And MongoDB is popular across industries. A survey of 90,240 companies using MongoDB listed the leading uses as Technology and Services (23%), Computer Software (16%), and Internet (6%).

So, if MongoDB provides such a great foundation, why not just step up to MongoDB Enterprise?

Why businesses seek an alternative to MongoDB Enterprise

The reasons for choosing an alternative to MongoDB Enterprise vary depending on business objectives, technical requirements, on-staff expertise, and project specifications. But there are common concerns about MongoDB Enterprise that drive people to seek alternatives.

Those problems (some with shared elements) include:

  • High cost and complicated pricing structure: Many companies say MongoDB has an expensive and complicated pricing structure (Cloud Zero, January 2023). MongoDB Enterprise is a commercial (proprietary) product with licensing fees, as well as support and maintenance charges that can rapidly escalate. With the potentially high costs and complications of tiers, pay-as-you-go, hourly and monthly rates, etc., companies and organizations seek alternatives that offer similar functionality at a lower cost.
  • Limited toolset: MongoDB Enterprise offers advanced features for data encryption, authentication, auditing, access control, and more. But you can be out of luck and forced to spend additional money if business-critical objectives require specific features or capabilities unavailable in MongoDB Enterprise.
  • Not really open source: Even the MongoDB Community version is not open source; it’s source-available and is under the SSPL license (introduced by MongoDB itself). MongoDB Enterprise, built on the Community version, adds proprietary features and database management tools. MongoDB Enterprise is commercial. Customers miss out on the cost-effectiveness, creative freedom, and global community support (for innovation, better performance, and enhanced security) that come with open source solutions and from companies with an open source spirit.
  • Inflexibility: Proprietary software puts a company — and its ability to tailor solutions to fit specific use cases — at the mercy of the software vendor. Conversely, open source database software (and companies that support source-available software with open source terms) provides the flexibility to customize and modify the software to suit specific requirements. Organizations have access to the source code, allowing them to make changes and enhancements as needed. This level of flexibility is particularly valuable for businesses with unique or specialized needs.
  • Vendor lock-in: Relying on contracted MongoDB Enterprise support to address immediate concerns, reduce complexity, and provide a secure database might provide initial comfort, but trepidation about vendor lock-in would be legitimate. Concerns about price hikes, paying for unnecessary technology, and being blocked from new technology can provide the impetus to seek an alternative to MongoDB Enterprise. Companies might opt for alternative databases that offer more of the aforementioned flexibility and the ability to migrate to different platforms or technologies in the future without significant challenges.
  • Infrastructure incompatibility: Organizations might have existing tools and applications that are not readily compatible with MongoDB Enterprise software. If an alternative database has better compatibility or provides specific integrations with the company’s existing technology stack, that might be a compelling reason to seek an alternative to MongoDB Enterprise.
  • Needless complexity: For smaller companies and/or those with simpler needs or limited database budgets and resources, some of the advanced features in MongoDB Enterprise could introduce unwanted complexity in the database environment. Such organizations might seek a more straightforward alternative.

Alternatives to MongoDB Enterprise

There are plenty of alternatives, but we’re not going to cover them all here, of course. Instead, let’s examine a few of the more popular non-relational (NoSQL) database options.

MongoDB Community

We’ve already touched on MongoDB Community’s licensing, but let’s address some of what the software lacks to be a viable technology alternative to its Enterprise sibling.

For starters, MongoDB Community lacks the advanced security features available in MongoDB Enterprise. It also lacks more advanced monitoring and management features like custom alerting, automation, and deeper insights into database performance that are part of MongoDB Enterprise. While it offers basic backup and restore functionality, the Community version lacks advanced features in MongoDB Enterprise, such as continuous backups, point-in-time recovery (PITR), and integration with third-party backup tools.

And from a support standpoint, for the loss of a better word, it’s lacking. The MongoDB Community edition does not come with official technical support or service level agreements (SLAs) from MongoDB Inc.

Redis

Known for exceptional performance, Redis is a popular in-memory data platform. It stores data in RAM, which enables fast data access and retrieval. Redis can handle a high volume of operations per second, making it useful for running applications that require low latency. Redis supports a wide range of data structures, including strings, lists, sets, sorted sets, and hashes. Developers appreciate how Redis supplies appropriate data structures for specific use cases.

Storing large datasets can be a challenge, as Redis’ storage capacity is limited by available RAM. Also, Redis is designed primarily for key-value storage and lacks advanced querying capabilities.

Redis ranks right after MongoDB as the sixth most popular database management system (DB-Engines, July 2023).

Apache Cassandra

Apache Cassandra, with users across industries, ranks as the 12th most popular database management system (DB-Engines, July 2023). It’s an open source distributed NoSQL database that offers high scalability and availability. It manages unstructured data with thousands of writes every second.

Fault tolerance and linear scalability make Cassandra popular for handling mission-critical data. But because Cassandra handles large amounts of data and multiple requests, transactions can be slower, and there can be memory management issues.

Couchbase

Couchbase is a distributed document store with a powerful search engine and built-in operational and analytical capabilities. It’s designed to handle high volumes of data with minimal delay. An in-memory caching mechanism supports horizontal scaling, which enables it to handle large-scale applications and workloads effectively. Couchbase — No. 32 in database popularity (DB-Engines, July 2023) — uses a distributed, peer-to-peer architecture that enables data replication and automatic sharding across multiple nodes. This architecture ensures high availability, fault tolerance, and resilience to failures.

With Couchbase, certain tasks can be more challenging or time-consuming. Its indexing mechanisms are not as well-developed as those of some other database solutions. Additionally, it has its own query language, so the learning curve can be steeper.

Percona’s MongoDB alternative — enterprise advantages with none of the strings

Here’s one more alternative: If you want enterprise-grade MongoDB — without the high cost of runaway licensing fees or restrictions of vendor lock-in — consider Percona Software for MongoDB.

Secure, enterprise-grade Percona Software for MongoDB is freely available and empowers you to operate the production environments you want, wherever you want. Benefits include:

  • High performance without lock-in — Operate production environments requiring high-performance, highly available, and secure databases. Do it without licensing costs and vendor lock-in.
  • Data durability — Ensure it via an open source, distributed, and low-impact solution for consistent backups of MongoDB sharded clusters and replica sets.
  • Scalability — Freely deploy and scale MongoDB in a public or private cloud, on-premises, or hybrid environment—no credit card required.
  • MongoDB database health checks — Monitor, receive alerts, manage backups, and diagnose user-impacting incidents rooted in database configuration.
  • Automated procedures and accelerated value — Automate deployments, scaling, and backup and restore operations of MongoDB on Kubernetes.

For MongoDB users, Percona offers:

  • Percona Server for MongoDB — A source-available, fully compatible drop-in replacement for the MongoDB Community Edition with enterprise security, backup, and developer-friendly features.
  • Percona Backup for MongoDB — This is a fully supported, 100% open source community backup tool for MongoDB. It creates a physical data backup on a running server without notable performance and operating degradation. Percona Backup for MongoDB offers PITR and a backup management interface via Percona Monitoring and Management (PMM).
  • Percona Toolkit for MongoDB A collection of advanced open source command-line tools that are engineered to perform a variety of tasks too difficult or complex to perform manually.
  • Percona Distribution for MongoDB — A collection of Percona for MongoDB software offerings integrated with each other and packed into a single solution that maximizes performance while being more cost-effective for teams to run over time.
  • Percona Monitoring and Management (PMM) — An open source database observability monitoring and management tool that’s ideal for finding MongoDB database issues.

With Percona Software for MongoDB, you can ensure data availability while improving security and simplifying the development of new applications — in the most demanding public, private, and hybrid cloud environments.

And with Percona, you’re never on your own. We back our MongoDB offerings with Percona Support, Managed Services, and Consulting. We’ll provide support that best fits the needs of your company or organization — without a restrictive contract.

 

Learn more about Percona Software for MongoDB

Jul
10
2023
--

MongoDB Version Requirements for Percona Backup for MongoDB

Version Requirements for Percona Backup For MongoDB

Percona Backup for MongoDB (PBM) is a backup utility developed by Percona to address the needs of customers and users who prefer open source tools over proprietary software like MongoDB Enterprise and Ops Manager. PBM offers comprehensive support and ensures cluster-wide consistent backups for MongoDB without additional costs.

MongoDB supported versions

While physical backups and restores are supported on Percona Server for MongoDB v4.2.15-16, v4.4.6-8, v5.0, and higher, incremental backups and restores, which were only recently GA-ed in PBM v2.1.0, do requires newer versions, specifically:

or higher. Using previous Percona Server MongoDB versions is not recommended since you can experience issues with the backup and the MongoDB nodes.

Using the supported Percona Server for MongoDB versions is vital to guarantee compatibility and avoid issues (including crashes). Percona recommends using the latest binaries available for Percona Backup for MongoDB and the minor versions available for your Percona MongoDB instance.

We are committed to continually enhancing PBM, and in future releases, we plan to restrict PBM from performing incremental backups on non-supported MongoDB versions. You can find more details about this task in the following link: PBM-1062.

For reference, here are the tickets detailing issues in older versions, which have resulted in improvements to Percona Server MongoDB, allowing PBM to guarantee consistent backups:

  • PSMDB-1177: Fix incremental backup failure via $backupCursor for PSMDB 4.2/4.4
  • PSMDB-1175: Fix PSMDB behavior when calling $backupCursor with disableIncrementalBackup option

Additional questions

For any additional questions, Percona customers can open a new support ticket.

Community users can use the usual community support channels to request help.

We appreciate your trust in Percona, and we are dedicated to providing you with exceptional solutions for all your MongoDB backup needs.

Why opt for expensive property software like MongoDB Enterprise Advanced and Ops Manager when you can get many of the same benefits without the cost or lock-in?

 

Try Percona Backup for MongoDB today

Jun
29
2023
--

CommitQuorum in Index Creation From Percona Server for MongoDB 4.4

CommitQuorum MongoDB

Before Percona Server for MongoDB 4.4 (PSMDB), the best practice to create an index was doing it in a rolling manner. Many folks used to create directly on Primary, resulting in the first index being created successfully on Primary and then replicated to Secondary nodes.

Starting from PSMDB 4.4, there was a new parameter commitQuorum introduced in the createIndex command. If you are not passing this parameter explicitly with the createIndex command, it will use the default settings on a replica set or sharded cluster and start building the index simultaneously across all data-bearing voting replica set members.

Below is the command used to create an index using commitQuorum as the majority:

db.getSiblingDB("acme").products.createIndex({ "airt" : 1 }, { }, "majority")

The above command will run the index create command on the majority of data-bearing replica set members. There are other options available too when using commitQuorum:

  1. “Voting Members” – This is the default behavior when an index will be created on all data-bearing voting replica set members (Default). A “voting” member is any replica set member where votes are greater than 0.
  2. “Majority” – A simple majority of data-bearing replica set members.
  3. “<int>” – A specific number of data-bearing replica set members. Specify an integer greater than 0.
  4. “Tag name” – A replica set tag name of a node is used.

Now we will see the scenarios of what happens when the index is created with the default and majority commitQuorum.

  1. When all data-bearing replica set members are available, and the index is created with default commitQuorum, below are the details from the Primary and the Secondary nodes. Create index:
    rs1:PRIMARY> db.products.createIndex({ "airt" : 1 })

    Primary logs:

    {"t":{"$date":"2023-06-26T12:33:18.417+00:00"},"s":"I",  "c":"INDEX",    "id":20384,   "ctx":"IndexBuildsCoordinatorMongod-0","msg":"Index build: starting","attr":{"namespace":"acme.products","buildUUID":{"uuid":{"$uuid":"58f4e7bf-7b8f-4eb6-8de0-0ad774c4b51f"}},"properties":{"v":2,"key":{"airt":1.0},"name":"airt_1"},"method":"Hybrid","maxTemporaryMemoryUsageMB":200}}

    Secondary logs:

    {"t":{"$date":"2023-06-26T12:33:18.417+00:00"},"s":"I",  "c":"INDEX",    "id":20384,   "ctx":"IndexBuildsCoordinatorMongod-0","msg":"Index build: starting","attr":{"namespace":"acme.products","buildUUID":{"uuid":{"$uuid":"58f4e7bf-7b8f-4eb6-8de0-0ad774c4b51f"}},"properties":{"v":2,"key":{"airt":1.0},"name":"airt_1"},"method":"Hybrid","maxTemporaryMemoryUsageMB":200}}}

    Secondary logs:

    {"t":{"$date":"2023-06-26T12:33:28.445+00:00"},"s":"I",  "c":"INDEX",    "id":20384,   "ctx":"IndexBuildsCoordinatorMongod-0","msg":"Index build: starting","attr":{"namespace":"acme.products","buildUUID":{"uuid":{"$uuid":"58f4e7bf-7b8f-4eb6-8de0-0ad774c4b51f"}},"properties":{"v":2,"key":{"airt":1.0},"name":"airt_1"},"method":"Hybrid","maxTemporaryMemoryUsageMB":200}}

    We can see the above index was created simultaneously on all the data-bearing voting replica set members.

  2. When one secondary is down, and the index is created with default commitQuorum, below are the details from the Primary and the Secondary nodes.

    Status of nodes:

    rs1:PRIMARY> rs.status().members.forEach(function (d) {print(d.name) + " " + print(d.stateStr)});
    127.0.0.1:27017
    PRIMARY
    localhost:27018
    SECONDARY
    localhost:27019
    (not reachable/healthy)
    rs1:PRIMARY>

    Index command:

    rs1:PRIMARY> db.products.createIndex({ "airt" : 1 })

    Replication status:

    rs1:PRIMARY> db.printSecondaryReplicationInfo()
    source: localhost:27018
            syncedTo: Mon Jun 26 2023 17:56:30 GMT+0000 (UTC)
            0 secs (0 hrs) behind the primary
    source: localhost:27019
            syncedTo: Thu Jan 01 1970 00:00:00 GMT+0000 (UTC)
            1687802190 secs (468833.94 hrs) behind the primary
    rs1:PRIMARY>

    Index status:

    rs1:PRIMARY> db.currentOp(true).inprog.forEach(function(op){ if(op.msg!==undefined) print(op.msg) })
    Index Build: draining writes received during build
    rs1:PRIMARY> Date()
    Mon Jun 26 2023 18:07:26 GMT+0000 (UTC)
    rs1:PRIMARY>

    CurrentOp:

    "active" : true,
          "currentOpTime" :"2023-06-26T19:04:33.175+00:00",
          "opid" : 329147,
      "lsid" : {
               "id" :UUID("dd9672f8-4f56-47ce-8ceb-31caf5e8baf8"),
               "uid": BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
                },
     "secs_running" : NumberLong(4214),
     "microsecs_running" : NumberLong("4214151233"),
     "op" : "command",
     "ns" : "acme.products",
     "command" : {
                  "createIndexes" : "products",
                  "indexes" : [
                                  {
                                   "key" : {
                                            "airt" : 1
                                            },
                                   "name" : "airt_1"
                                  }
                               ],
                   "lsid" : {
                   "id" :UUID("dd9672f8-4f56-47ce-8ceb-31caf5e8baf8")
                             },
                   "$clusterTime" : {
                                     "clusterTime" : Timestamp(1687801980, 1),
                                     "signature" : {
                                     "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                                     "keyId" : NumberLong(0)
                                            }
                                    },
                    "$db" : "acme"
                            }

    Logs from Primary node:

    {"t":{"$date":"2023-06-26T17:54:21.419+00:00"},"s":"I",  "c":"STORAGE",  "id":3856203, "ctx":"IndexBuildsCoordinatorMongod-1","msg":"Index build: waiting for next action before completing final phase","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}}}}

     Logs from up-and-running Secondary node:

    {"t":{"$date":"2023-06-26T17:54:21.424+00:00"},"s":"I",  "c":"STORAGE",  "id":3856203, "ctx":"IndexBuildsCoordinatorMongod-1","msg":"Index build: waiting for next action before completing final phase","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}}}}

    You can see above that when one node is down, and the index is created with default commitQuorum, the index command will keep running till that third data-bearing voting node comes up. Now we can check if the index is created on Primary or not:

    rs1:PRIMARY> db.products.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_"
            },
            {
                    "v" : 2,
                    "key" : {
                            "airt" : 1
                    },
                    "name" : "airt_1"
            }
    ]
    rs1:PRIMARY>

    We can see the index is created, but you will not be able to use the above index as the index is not marked as completed.

    Below is the explain plan of a query, where we can see the query is doing COLLSCAN instead of IXSCAN:

    rs1:PRIMARY> db.products.find({"airt" : 1.9869362536440427}).explain()
    {
            "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "acme.products",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                            "airt" : {
                                    "$eq" : 1.9869362536440427
                            }
                    },
                    "queryHash" : "65E2F79D",
                    "planCacheKey" : "AA490985",
                    "winningPlan" : {
                            "stage" : "COLLSCAN",
                            "filter" : {
                                    "airt" : {
                                            "$eq" : 1.9869362536440427
                                    }
                            },
                            "direction" : "forward"
                    },
                    "rejectedPlans" : [ ]
            },
            "serverInfo" : {
                    "host" : "ip-172-31-82-235.ec2.internal",
                    "port" : 27017,
                    "version" : "4.4.22-21",
                    "gitVersion" : "be7a5f4a1000bed8cf1d1feb80a20664d51503ce"
    }

    Now I will bring up the third node, and we will see that index op will complete.

    Index status:

    rs1:PRIMARY> db.products.createIndex({ "airt" : 1 })
    {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 1,
            "numIndexesAfter" : 2,
            "commitQuorum" : "votingMembers",
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1687806737, 3),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1687806737, 3)
    }
    rs1:PRIMARY>

    Now will run the same query, and we can see index (IXSCAN) is getting used as the index was created successfully above:

    rs1:PRIMARY> db.products.find({"airt" : 1.9869362536440427}).explain()
    {
            "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "acme.products",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                            "airt" : {
                                    "$eq" : 1.9869362536440427
                            }
                    },
                    "queryHash" : "65E2F79D",
                    "planCacheKey" : "AA490985",
                    "winningPlan" : {
                            "stage" : "FETCH",
                            "inputStage" : {
                                    "stage" : "IXSCAN",
                                    "keyPattern" : {
                                            "airt" : 1
                                    },
                                    "indexName" : "airt_1",
                                    "isMultiKey" : false,
                                    "multiKeyPaths" : {
                                            "airt" : [ ]
                                    },
                                    "isUnique" : false,
                                    "isSparse" : false,
                                    "isPartial" : false,
                                    "indexVersion" : 2,
                                    "direction" : "forward",
                                    "indexBounds" : {
                                            "airt" : [
                                                    "[1.986936253644043, 1.986936253644043]"
                                            ]
                                    }
                            }
                    },
                    "rejectedPlans" : [ ]
            },
            "serverInfo" : {
                    "host" : "ip-172-31-82-235.ec2.internal",
                    "port" : 27017,
                    "version" : "4.4.22-21",
                    "gitVersion" : "be7a5f4a1000bed8cf1d1feb80a20664d51503ce"
            }

    Primary logs once the third node came up and the index was created successfully:

    {"t":{"$date":"2023-06-26T19:12:17.450+00:00"},"s":"I",  "c":"STORAGE",  "id":3856201, "ctx":"conn40","msg":"Index build: commit quorum satisfied","attr":{"indexBuildEntry":{"_id":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"},"collectionUUID":{"$uuid":"a963b7e7-1054-4a5f-a935-a5be8995cff0"},"commitQuorum":"votingMembers","indexNames":["airt_1"],"commitReadyMembers":["127.0.0.1:27017","localhost:27018","localhost:27019"]}}}
    
    {"t":{"$date":"2023-06-26T19:12:17.450+00:00"},"s":"I",  "c":"STORAGE",  "id":3856204, "ctx":"IndexBuildsCoordinatorMongod-1","msg":"Index build: received signal","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}},"action":"Commit quorum Satisfied"}}
    
    {"t":{"$date":"2023-06-26T19:12:17.451+00:00"},"s":"I",  "c":"INDEX",    "id":20345,   "ctx":"IndexBuildsCoordinatorMongod-1","msg":"Index build: done building","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}},"namespace":"acme.products","index":"airt_1","commitTimestamp":{"$timestamp":{"t":1687806737,"i":2}}}}
    
    {"t":{"$date":"2023-06-26T19:12:17.452+00:00"},"s":"I",  "c":"STORAGE",  "id":20663,   "ctx":"IndexBuildsCoordinatorMongod-1","msg":"Index build: completed successfully","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}},"namespace":"acme.products","uuid":{"uuid":{"$uuid":"a963b7e7-1054-4a5f-a935-a5be8995cff0"}},"indexesBuilt":1,"numIndexesBefore":1,"numIndexesAfter":2}}
    
    {"t":{"$date":"2023-06-26T19:12:17.554+00:00"},"s":"I",  "c":"INDEX",    "id":20447,   "ctx":"conn34","msg":"Index build: completed","attr":{"buildUUID":{"uuid":{"$uuid":"46451b37-141f-4312-a219-4b504736ab5b"}}}}
    
    {"t":{"$date":"2023-06-26T19:12:17.554+00:00"},"s":"I",  "c":"COMMAND",  "id":51803,   "ctx":"conn34","msg":"Slow query","attr":{"type":"command","ns":"acme.products","appName":"MongoDB Shell","command":{"createIndexes":"products","indexes":[{"key":{"airt":1.0},"name":"airt_1"}],"lsid":{"id":{"$uuid":"dd9672f8-4f56-47ce-8ceb-31caf5e8baf8"}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1687801980,"i":1}},"signature":{"hash":{"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"0"}},"keyId":0}},"$db":"acme"},"numYields":0,"reslen":271,"locks":{"ParallelBatchWriterMode":{"acquireCount":{"r":3}},"FeatureCompatibilityVersion":{"acquireCount":{"r":1,"w":4}},"ReplicationStateTransition":{"acquireCount":{"w":5}},"Global":{"acquireCount":{"r":1,"w":4}},"Database":{"acquireCount":{"w":3}},"Collection":{"acquireCount":{"r":1,"w":1,"W":1}},"Mutex":{"acquireCount":{"r":3}}},"flowControl":{"acquireCount":3,"timeAcquiringMicros":7},"storage":{"data":{"bytesRead":98257,"timeReadingMicros":3489}},"protocol":"op_msg","durationMillis":4678530}}

    Above, you can see how much time it took to complete the index build; the op was running till the third node was down.

  3. When one secondary is down, and the index is created with commitQuorum as the majority, below are the details from the Primary and the Secondary nodes. Status of nodes:
    rs1:PRIMARY> rs.status().members.forEach(function (d) {print(d.name) + " " + print(d.stateStr)});
    127.0.0.1:27017
    PRIMARY
    localhost:27018
    SECONDARY
    localhost:27019
    (not reachable/healthy)
    rs1:PRIMARY>

    Index command:

    rs1:PRIMARY> db.products.createIndex({ "airt" : 1 }, { }, "majority")
    {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 1,
            "numIndexesAfter" : 2,
            "commitQuorum" : "majority",
            "ok" : 1,
            "$clusterTime" : {
                    "clusterTime" : Timestamp(1687808148, 4),
                    "signature" : {
                            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                            "keyId" : NumberLong(0)
                    }
            },
            "operationTime" : Timestamp(1687808148, 4)
    }
    rs1:PRIMARY>

    Logs from Primary node:

    {"t":{"$date":"2023-06-26T19:35:48.821+00:00"},"s":"I",  "c":"STORAGE",  "id":3856201, "ctx":"conn7","msg":"Index build: commit quorum satisfied","attr":{"indexBuildEntry":{"_id":{"$uuid":"5f8f75ee-aa46-42a6-b4c2-59a68fea47a7"},"collectionUUID":{"$uuid":"a963b7e7-1054-4a5f-a935-a5be8995cff0"},"commitQuorum":"majority","indexNames":["airt_1"],"commitReadyMembers":["127.0.0.1:27017","localhost:27018"]}}}
    
    {"t":{"$date":"2023-06-26T19:35:48.821+00:00"},"s":"I",  "c":"STORAGE",  "id":3856204, "ctx":"IndexBuildsCoordinatorMongod-3","msg":"Index build: received signal","attr":{"buildUUID":{"uuid":{"$uuid":"5f8f75ee-aa46-42a6-b4c2-59a68fea47a7"}},"action":"Commit quorum Satisfied"}}
    
    {"t":{"$date":"2023-06-26T19:35:48.822+00:00"},"s":"I",  "c":"INDEX",    "id":20345,   "ctx":"IndexBuildsCoordinatorMongod-3","msg":"Index build: done building","attr":{"buildUUID":{"uuid":{"$uuid":"5f8f75ee-aa46-42a6-b4c2-59a68fea47a7"}},"namespace":"acme.products","index":"airt_1","commitTimestamp":{"$timestamp":{"t":1687808148,"i":3}}}}
    
    {"t":{"$date":"2023-06-26T19:35:48.824+00:00"},"s":"I",  "c":"STORAGE",  "id":20663,   "ctx":"IndexBuildsCoordinatorMongod-3","msg":"Index build: completed successfully","attr":{"buildUUID":{"uuid":{"$uuid":"5f8f75ee-aa46-42a6-b4c2-59a68fea47a7"}},"namespace":"acme.products","uuid":{"uuid":{"$uuid":"a963b7e7-1054-4a5f-a935-a5be8995cff0"}},"indexesBuilt":1,"numIndexesBefore":1,"numIndexesAfter":2}}
    
    {"t":{"$date":"2023-06-26T19:35:48.923+00:00"},"s":"I",  "c":"INDEX",    "id":20447,   "ctx":"conn34","msg":"Index build: completed","attr":{"buildUUID":{"uuid":{"$uuid":"5f8f75ee-aa46-42a6-b4c2-59a68fea47a7"}}}}
    
    {"t":{"$date":"2023-06-26T19:35:48.923+00:00"},"s":"I",  "c":"COMMAND",  "id":51803,   "ctx":"conn34","msg":"Slow query","attr":{"type":"command","ns":"acme.products","appName":"MongoDB Shell","command":{"createIndexes":"products","indexes":[{"key":{"airt":1.0},"name":"airt_1"}],"commitQuorum":"majority","lsid":{"id":{"$uuid":"dd9672f8-4f56-47ce-8ceb-31caf5e8baf8"}},"$clusterTime":{"clusterTime":{"$timestamp":{"t":1687808123,"i":1}},"signature":{"hash":{"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"0"}},"keyId":0}},"$db":"acme"},"numYields":0,"reslen":266,"locks":{"ParallelBatchWriterMode":{"acquireCount":{"r":3}},"FeatureCompatibilityVersion":{"acquireCount":{"r":1,"w":4}},"ReplicationStateTransition":{"acquireCount":{"w":5}},"Global":{"acquireCount":{"r":1,"w":4}},"Database":{"acquireCount":{"w":3}},"Collection":{"acquireCount":{"r":1,"w":1,"W":1}},"Mutex":{"acquireCount":{"r":3}}},"flowControl":{"acquireCount":3,"timeAcquiringMicros":7},"storage":{},"protocol":"op_msg","durationMillis":2469}}

    Above, we can see when one node is down, and we used commitQuorum as majority while creating the index, index op got completed as per expected behavior as two voting (majority) nodes were up and running.

So far, we have discussed how to use commitQuorum and when to use it. Now we will see a scenario when one node (voting) is down for any reason, and someone created an index with default commitQuorum. The op will keep running, and you want to kill the op.

I created the index with the default commitQuorum when one node is down.

Status of nodes:

rs1:PRIMARY> rs.status().members.forEach(function (d) {print(d.name) + " " + print(d.stateStr)});
127.0.0.1:27017
PRIMARY
localhost:27018
SECONDARY
localhost:27019
(not reachable/healthy)
rs1:PRIMARY>

CurrentOp:

"active" : true,
"currentOpTime" : "2023-06-26T21:27:41.304+00:00",
"opid" : 536535,
"lsid" : {
          "id" : UUID("dd9672f8-4f56-47ce-8ceb-31caf5e8baf8"),
          "uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
 },
 "secs_running" : NumberLong(264),
 "microsecs_running" : NumberLong(264345444),
 "op" : "command",
 "ns" : "acme.products",
 "command" : {
              "createIndexes" : "products",
              "indexes" : [
                      {
                           "key" : {
                                     "airt" : 1
                                    },
                           "name" : "airt_1"
                       }
                            ],
 "lsid" : {
               "id" : UUID("dd9672f8-4f56-47ce-8ceb-31caf5e8baf8")
           },
               "$clusterTime" : {
                                "clusterTime" : Timestamp(1687814589, 2),
                                "signature" : {
                                               "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                                 "keyId" : NumberLong(0)
                                 }
                                },
                                "$db" : "acme"
                        }

Now you need to kill the above opid to release the above op:

rs1:PRIMARY> db.killOp(536535)
{
        "info" : "attempting to kill op",
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1687815189, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1687815189, 2)
}
rs1:PRIMARY>
rs1:PRIMARY> db.products.createIndex({ "airt" : 1 })
{
        "operationTime" : Timestamp(1687815192, 2),
        "ok" : 0,
        "errmsg" : "operation was interrupted",
        "code" : 11601,
        "codeName" : "Interrupted",
        "$clusterTime" : {
                "clusterTime" : Timestamp(1687815192, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
rs1:PRIMARY>
rs1:PRIMARY> db.products.getIndexes()
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
rs1:PRIMARY>

Above, we can see when we killed the op, and the index creation op got killed.

Conclusion

We have seen how commitQuorum works while creating indexes from PSMDB 4.4. Still, the best practice is to create indexes in a rolling manner.

We recommend checking out our products for Percona Server for MongoDB, Percona Backup for MongoDB, and Percona Operator for MongoDB. We also recommend checking out our blog MongoDB: Why Pay for Enterprise When Open Source Has You Covered?

Jun
27
2023
--

MongoDB Monitoring With Percona Alerting in PMM

MongoDB Monitoring

Percona Alerting was introduced in Percona Monitoring and Management (PMM) 2.31, and it brought a range of custom alerting templates that makes it easier to create Alert rules to monitor your databases.

In this article, we will go over how to set up Alerting in PMM running on Docker and receive notifications via emails when such alerts are triggered. We will also leverage Grafana’s notification templates to customize the alert emails to reduce noise.

Configuring PMM with Grafana SMTP

To configure SMTP for Grafana, we need to provide the following environment variables:

  • GF_SMTP_ENABLED: When true, enables Grafana to send emails.
  • GF_SMTP_HOST: Host address of your SMTP server.
  • GF_SMTP_USER: Username for SMTP authentication.
  • GF_SMTP_PASSWORD: Password for SMTP authentication
  • GF_SMTP_SKIP_VERIFY: When true, verifies SSL for the SMTP server.
  • GF_SMTP_FROM_ADDRESS: Email address to be used when sending out emails.
  • GF_SMTP_FROM_NAME: Name to be used when sending out emails.

Create a .env file in your preferred working directory and add your SMTP credentials as follows:

GF_SMTP_ENABLED=true
GF_SMTP_HOST=smtp.gmail.com:587
GF_SMTP_USER=<YOUR_EMAIL@DOMAIN.COM>
GF_SMTP_PASSWORD=<YOUR_SMTP_PASSWORD>
GF_SMTP_SKIP_VERIFY=false
GF_SMTP_FROM_ADDRESS=<YOUR_EMAIL@DOMAIN.COM>
GF_SMTP_FROM_NAME=Percona Alerting

If you are using your Gmail’s SMTP credentials, as shown above, you will have to generate an app password and fill it in as the value of your $GF_SMTP_PASSWORD variable.

Next, start your PMM instance with the created .env file using the docker command below:

docker run --env-file=.env -p 443:443 -p 80:80 --name=pmm-alerting percona/pmm-server:2

Adding MongoDB services

With our PMM instance up and running, let us add a new MongoDB service for PMM to monitor. Start up a MongoDB container in Docker with the command below:

docker run -d -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin --name mongo-pmm-alerting percona/percona-server-mongodb --bind_ip=0.0.0.0

Next, run the Docker command below to get the Host IP. This is needed as we will use it as our host address in the next step.

docker network inspect bridge -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'

In your PMM dashboard, go to the “Add Instance” page on PMM ($HOST/graph/add-instance) and click the MongoDB tile.

PMM screen showing options to add instance of different databases

On the next page, fill in the details of your MongoDB instance. The Hostname is the Host IP we got from the docker command above, while the username and password are the values of MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD we set while starting the Mongo container.

MongoDB instance

NB: Using the default root credentials is not recommended in production environments, and you can find details on setting up a user for PMM in the Percona documentation.

You can verify the newly added service on the PMM inventory page (at http://localhost/inventory), which should look like the one below: Don’t worry about the ‘N/A’ status of the newly added service, though, as it typically flips to ‘OK’ after a few health checks are performed.

Customizing emails with notification templates

By default, Alert emails from Grafana can get noisy as it includes all the alert labels in the subject line (among other things). To tone things down, we will create a new subject template for our own alerts. Head over to the Contact Points tab in the Alerting section and click the New Template button. In the New Template page, use pmm_subject as your template name and add the code below in the “Content” field:

{{ define "pmm_subject" }}
[{{ .Status | toUpper }}
{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}
  {{ if gt (.Alerts.Resolved | len) 0 }}
    RESOLVED:{{ .Alerts.Resolved | len }}
  {{ end }}
{{ end }}]
{{ range .CommonLabels.SortedPairs -}}
  {{ if eq .Name "alertname" }}
    {{ .Value }}
  {{ end }}
  {{ if eq .Name "cluster" }}
    - {{ .Value }}
  {{ end }}
  {{ if eq .Name "service_name" }}
    - {{ .Value }}
  {{ end }}
{{ end }}
{{ end }}

In the template above, we define the name (using the same name from the template name field). We then extract the alert status (Firing or Resolved) as well as the number of alerts in each status. In the second section, we loop through a sorted list of the alert labels and extract the alert name, cluster name, and service name in order. That way, our subject line is in the form:

FIRING: 1 MongoDB is down - prod-cluster - mongo-eu-1

Where prod-cluster is our cluster name, and mongo-eu-1 is our service name.

To learn more about Grafana’s notification templates and Go templating generally, you can check out the Grafana documentation and the template package documentation, respectively. Our next step is to register the created template with Grafana. Click the edit icon beside the default contact point and update the email address(es) on the settings page.

Next, expand the optional settings and add the following text to the subject field:

{{ template "pmm_subject" . }}

This will register the template we created earlier and direct Grafana to use it as alerting email subject. At this point, you can go ahead and test your configuration using the “Test” button on the contacts point settings page.

To get a feel of a real alert, though, we will set up an Alert rule based on the Mongo down Alerting template that comes with PMM.

Alert Rules from Percona Alert Templates

PMM includes a set of default templates with common events and expressions for alerting. These templates can then be used as a basis for your alert rules (or even your own templates), and you can find them in the “Alert Rule Templates” tab. Our next step is to create an alert rule based on one of these templates, specifically, the “Mongo down” alerting template. Click the “+” icon beside the template name (highlighted below), and it will take you to the “New Alert rule page”.

Most of the fields are already pre-filled (since the rule is based on a template), and we only need to specify a Folder/Alerting Group. In our case, we will go with the “MongoDB” folder. Select that and click the “Save” button.

Our new alerting rule is now ready and should appear as “Normal” in the “Alert Rule” tab.

To trigger the alert specified in our rule from the last section, stop the MongoDB docker container and wait for 60 seconds (the default evaluation time set for the alert). The alert should now be firing on both your PMM dashboard and if your email was set up correctly, you’ll also get an email about it.

 

Conclusion

Percona Alerting templates further help simplify the process of setting up alerting for your environment. In this blog post, we’ve reviewed how to do that, for example, in a MongoDB setup. You can install PMM and further explore Alerting, or ask questions/give your feedback on the PMM forums.

 

Percona Monitoring and Management is a best-of-breed open source database monitoring solution. It helps you reduce complexity, optimize performance, and improve the security of your business-critical database environments, no matter where they are located or deployed.

 

Download Percona Monitoring and Management Today

May
15
2023
--

MongoDB 4.2 EOL… And Its Implications

MongoDB 4.2 EOL

Enjoy it while it lasts, as everything has its end.

It sounded a bit more cryptic than it was planned, but I hope that it gets the attention it needs, as it’s important to know that MongoDB 4.2 in April has reached its End of Life (EOL), and more versions are soon going to be decommissioned as well.

What does that mean for me?

If you are a user of MongoDB 4.2, whether the MongoDB Inc. version or Percona Server for MongoDB one, your database will no longer receive bug fixes, patches, or minor releases.

As defined in our Lifecycle Policy:

We will provide Operational Support for customers running EOL software on active platforms. For EOLed platforms, we provide Community Support.

And as stated in our Lifecycle Overview:

For software that Percona bases on an upstream build, we match the upstream EOL dates.

Our MongoDB Server follows the upstream EOL dates. This means that bug fixes and software builds will no longer be generated also for our release of MongoDB.

Also, with the Percona Server for MongoDB 4.2 reaching its end of life, the implications are as follows:

  • Percona Distribution for MongoDB 4.2 will no longer receive updates and bug fixes
  • Percona Backup for MongoDB (PBM) will no longer support 4.2 either. That means that testing with 4.2 has ceased, and while PBM may still successfully perform backups and restores, we cannot guarantee it anymore.

That being said, rest assured, you will not be left alone. Those that have or would like to sign up for a Percona Support Subscription will continue to receive operational support and services. Operational support includes but is not limited to:

  • Query optimization
  • MongoDB tuning (replica sets and sharded clusters)
  • MongoDB configuration, including our enterprise features such as LDAP
  • Upgrade support (from EOL versions, so, i.e., 3.6->4.0->4.2->…)
  • Setup and configuration of MongoDB clusters and tools such as Percona Backup for MongoDB and Percona Monitoring and Management (respecting the tool limitation for the EOL-ed version).
  • In case of crashes, although we do not report bugs, we can still track down known bugs and provide recommendations.

Still have questions about the 4.2 EOL?

In her recent blog post, MongoDB V4.2 EOL Is Coming: How To Upgrade Now and Watch Out for the Gotchas!, our MongoDB Tech Lead, Kimberly Wilkins, has covered the ins and outs of a MongoDB upgrade.

She has also hosted a webinar on the MongoDB 4.2 EOL common questions and challenges.

If you are our customer, please create a ticket for more assistance. Remember also that our Percona Community Forum is always open for any users of our software, as we believe that community is very important in building our products!

What’s next

I do not want to be the bearer of bad news, but we have seen the great popularity of MongoDB 4.2 and 4.4. If you are on 4.2 right now, it makes all the difference to move away from it ASAP. This version has just become a possible threat to your security.

As you see, 4.4 was mentioned as well. That’s right, this highly popular, last version in the 4.x family is scheduled to be EOL in February 2024. That’s less than one year to make preparations for upgrading.

Mongo 4.2 EOL

MongoDB EOL for the upcoming year or so.

While at it, notice that 5.0 is planned to be EOL in October 2024 as well, so next year, it’s worth considering upgrading to 6.0 to have at least till 2025 for the next EOL.

MongoDB eol

MongoDB 6.0 still has two years of life now.

If such an upgrade seems challenging and you want some help or at least advice around it, consider some of our premium services from MongoDB experts that can help you with migration by:

  • Support – Answering any operational questions
  • Managed Services – Playing the role of the remote DBA that handles all maintenance (including upgrades) for you
  • Consulting – Professionals that can come in and advise or even do the upgrade for you at any time
  • Training – So that your team can feel more comfortable with running the upgrades

Percona Distribution for MongoDB is a freely available MongoDB database alternative, giving you a single solution that combines the best and most important enterprise components from the open source community, designed and tested to work together.

Download Percona Distribution for MongoDB Today!

May
09
2023
--

Restoring a Snapshot of a Sharded MongoDB Cluster to a Kubernetes-Based MongoDB Environment

Kubernetes-Based MongoDB Environment

Many MongoDB clusters use storage-level snapshots to provide fast and reliable backups. In this blog post, you’ll learn how to restore such a snapshot from a traditional VM-based sharded MongoDB cluster to a freshly deployed Percona Operator for MongoDB cluster on Kubernetes.

Background story

I recently worked with a company running a large four-shard MongoDB Enterprise Server database cluster on VMs on premises that decided to migrate to the Google Cloud Platform. After careful consideration and pros-and-con evaluation, the customer chose to go with Percona Distribution for MongoDB run on Kubernetes – specifically using Percona Operator for MongoDB. There are four main factors that contributed to this decision:

  1. The total cost of ownership: K8s resources are significantly cheaper than running a popular DBaaS on the same cloud
  2. Ease of deployments: Percona Operator for MongoDB makes day-1 and day-2 operations a breeze
  3. Preference for open-source tools and cloud-native solutions: applications are already migrated to Kubernetes – running the entire solution that way simplifies operations. 
  4. This approach frees the deployment from cloud (and any other vendor) lock-in.

To start realistic compatibility and performance testing, we needed to restore the filesystem snapshot backup that was stored on NetApp volume in GCP into a Google Kubernetes Engine (GKE) cluster running Percona Operator for MongoDB. It’s not a trivial task due to the requirements for restoring a sharded cluster backup into a new cluster. I will show you why and how we did it.

Requirements

Let’s look at the overall requirements for the cluster where I want to restore the snapshot to:

  1. The same major (ideally minor, too) MongoDB version
  2. The same number of shards
  3. The same name of all shards
  4. The same name of the Config RS
  5. The same hostnames of all nodes (this is how Config RS connects to the specific shard)
  6. The same MongoDB configuration with regards to how files are stored on the disk

This seems to be straightforward; however, there are a couple of special considerations to make when it comes to the environment controlled by Percona Operator for MongoDB, specifically:

  • You can’t control the name of Config RS
  • You can’t change the hostnames and those will certainly be different within Kubernetes
  • Percona Operator needs specific users to be present in your cluster in order to control it – and those won’t be present in your backup.

All of the above makes it impossible to simply adjust the Operator configuration and copy all the files from your snapshot backup in the specific volumes.

Plan

The high-level plan consists of the following steps:

  1. Deploy the cluster on K8s
  2. Restore snapshot files
    1. Pause the cluster on K8s
    2. Mount storage volumes to a separate VM
    3. Copy snapshot files to respective volumes
  3. Prepare each replica set in the standalone mode (hostnames, sharding configuration, users)
  4. Start the cluster on K8s and initialize each replica set

The following approach is applicable regardless of what “flavor” of MongoDB your source environment uses. This can be MongoDB Enterprise Server, MongoDB Community Edition, or Percona Server for MongoDB.

Step one: Deploy the cluster on K8s

In order to deploy Percona Server for MongoDB (PSMDB) on the K8s cluster, follow the documentation. Before you execute the last step (deploying cr.yaml), however, make sure to adjust the following elements of the configuration. This will make the cluster “fit” the one that we took the backup from.

  1. Set spec.image to a specific image version. It needs to be the version that matches the major version of the source cluster, for example:

    spec:
      image: percona/percona-server-mongodb:5.0.11-10
  2. Create as many shard replica sets as in the source cluster. Copy the default replica set definition (entire section) in spec.replsets[]. For example, if your source cluster has two shards with the names “shard1” and “shard2” (names must match the ones from the source cluster):

    replsets:
     - name: shard1
       size: 3
       [...]
     - name: shard2
       size: 3
       [...]

    Unfortunately, you can’t set the name of Config RS. We’ll deal with that later.

  3. If your source cluster WiredTiger configuration is different than default, adjust the mongod configuration of each replica set to match it. Specifically, two MongoDB configuration items are critical: storage.directoryPerDB and storage.wiredTiger.engineConfig.directoryForIndexes. You can do it in the following way:

    replsets:
      - name: shard1
        size: 3
        configuration: |
          storage:
            directoryPerDB: true
          wiredTiger:
            engineConfig:
              directoryForIndexes: true
  4. Save changes and start the cluster using the modified cr.yaml file

Step two: Restore snapshot files

Your cluster should be started at this point and it is important that all PersistentVolumes required for it be created.  You can check your cluster state with kubectl get psmdb, see all deployed pods with kubectl get pods, or check PVs with kubectl get pv. In this step, you need to mount volumes of all your database nodes to an independent VM as we’ll make changes in MongoDB standalone mode. You need those VMs temporarily to perform the required operations.

  1. Pause the PSMDB cluster on K8s by setting spec.pause: true in your cr.yaml file. That will cause the entire cluster to stop and make it possible to mount volumes elsewhere.
  2. Check zones where your PerstistentVolumes were created. You can use kubectl describe pv pv_name or find it in the cloud console.
  3. Create a VM in each zone, then mount volumes corresponding to PersistentVolumes to a VM in its zone. It’s critical that you can easily identify the volume’s purpose (which replica set in your MongoDB cluster it refers to and which node – primary or secondary). As an example, this is how you can mount a volume to your VM using gcloud API:

    # attach disk to an instance
    gcloud compute instances attach-disk vm_name 
    --disk disk_name 
    --zone=us-central1-a
    
    # check volume on vm
    sudo lsblk
    
    # create a mountpoint
    sudo mkdir -p /dir_name (e.g. rs0-primary)
    
    # mount the volume
    sudo mount -o discard,defaults /dev/sdb /dir_name

     

  4. Delete all files from each volume mounted to your VMs – primaries, and secondaries.
  5. Copy files from the snapshot to the respective volume, directly to the main directory of the mounted volume. Do it just for volumes related to primary nodes (leave secondaries empty).
  6. Install Percona Server for MongoDB on each of your VMs. Check installation instructions and install the same version as your Mongo cluster on K8s. Don’t start the server yet!

Step three: Prepare each replica set in the standalone mode

Now, you need to start PSMDB for each volume with data (each primary of each replica set, including Config RS) separately. We will then log in to mongo shell and edit the cluster configuration manually so that when we bring volumes with data back to Kubernetes, it can start successfully.

Execute the steps below for each replica set, including Config RS:

  1. On the VM, when your Config RS primary volume is mounted, edit /etc/mongod.conf. Specifically, adjust storage.dbPath (to the directory where you mounted the volume), storage.directoryPerDB, and storage.wiredTiger.engineConfig.directoryForIndexes.
  2. Start PSMDB with sudo mongod –config /etc/mongod.conf
  3. Connect to PSMDB with mongo command (authentication is not required). Once you successfully log in, we can start making changes to the cluster configuration.
  4. Delete the local replica set configuration with the following commands:

    use local;
    db.dropDatabase();
  5. [This step applies only to Config RS]
    Replace shards configuration. Execute the following command for each shard separately (you can list them all with db.shards.find() ). Replace in the following string: shard_name, cluster_name, namespace_name with values specific to your cluster:

    use config;
    
    db.shards.updateOne(
      { "_id" : "shard_name" },
      { $set :
        { "host" : "shard_name/cluster_name-shard_name-0.cluster_name-shard_name.namespace_name.svc.cluster.local:27017,cluster_name-shard_name-1.cluster_name-shard_name.namespace_name.svc.cluster.local:27017,cluster_name-shard_name-2.cluster_name-shard_name.namespace_name.svc.cluster.local:27017"}
    });
  6. [This step applies to shard RS only] Clear shard metadata

    use admin
    db.system.version.deleteOne( { _id: "minOpTimeRecovery" } )
  7. [This step applies to shard RS only] Replace Config RS connection string in shardIdentity with the following command. Replace cluster_name, namespace_name with your values.

    use admin
    
    db.system.version.updateOne(
     { "_id" : "shardIdentity" },
     { $set :
       { "configsvrConnectionString" : "cfg/cluster_name-cfg-0.cluster_name-cfg.namespace_name.svc.cluster.local:27017,cluster_name-cfg-1.cluster_name-cfg.namespace_name.svc.cluster.local:27017,cluster_name-cfg-2.cluster_name-cfg.namespace_name.svc.cluster.local:27017"}
     });
  8. Percona MongoDB Operator requires system-level MongoDB users to be present in a database. We must create those users for the operator, as our backup doesn’t have them. If you haven’t changed default secrets.yaml during the deployment of the cluster, you can find default passwords either in the file or here in the documentation. To create required users and roles, use the Mongo commands below:

    use admin;
    //drop user in case they already exist in your backup
    db.dropUser("userAdmin");
    db.dropUser("clusterAdmin");
    db.dropUser("clusterMonitor");
    db.dropUser("backup");
    db.dropUser("databaseAdmin");
    
    //create missing role
    db.createRole({"role" : "explainRole",
                   "privileges" : [{"resource": {"db" : "","collection" : "system.profile"},
                    "actions" :   ["collStats","dbHash","dbStats","find","listCollections","listIndexes"]}],
                    roles: []});
    
    //create system users
    db.createUser({ user: "userAdmin",
                    pwd: "userAdmin123456",
                    roles: [ { role: "userAdminAnyDatabase", db: "admin" }]
                  });
    
    db.createUser({ user: "clusterAdmin",
                   pwd: "clusterAdmin123456",
                   roles: [ { role: "clusterAdmin", db: "admin" }]
                  });
    
    db.createUser({ user: "clusterMonitor",
                    pwd: "clusterMonitor123456",
                    roles: [{ role: "explainRole", db: "admin" },
                            { role: "read", db: "local" },
                            { role: "clusterMonitor", db: "admin" }]
                  });
    
    db.createUser({ user: "databaseAdmin",
                    pwd: "databaseAdmin123456",
                    roles: [{ role: "readWriteAnyDatabase", db: "admin" },
                            { role: "readAnyDatabase", db: "admin" },
                            { role: "dbAdminAnyDatabase", db: "admin" },
                            { role: "backup", db: "admin" },
                            { role: "restore", db: "admin" },
                            { role: "clusterMonitor", db: "admin" },]
                  });
    
    db.createUser({ user: "backup",
                    pwd: "backup123456",
                    roles: [{ role: "backup", db: "admin" },
                            { role: "restore", db: "admin" },
                            { role: "clusterMonitor", db: "admin" }]
                  });
  9. Shut down the server now using db.shutdownServer();
  10. The operator runs mongod process with “mongodb” user (not as a standard “mongod”!). Therefore, we need to fix permissions before we unmount the volume. Add the following line to your /etc/passwd file:

    mongodb:x:1001:0:Default Application User:/home/mongodb:/sbin/nologin
  11. Set permissions:

    cd /your_mountpoint
    sudo chown -R mongodb:1001 ./
  12. Unmount the volume and detach it from the VM. As an example, this is how you can unmount a volume from your VM using gcloud API:

    sudo umount /dir_name
    
    gcloud compute instances detach-disk vm_name 
    --disk disk_name 
    --zone=us-central1-a

     

Step four: Start the cluster on K8s and initialize each replica set

You’re ready to get back to K8s. Start the cluster (it will start with previously used volumes). It will be in a pending state because we broke (intentionally) replica sets. Only one pod per Replica Set will start. You must initialize replica sets one by one.

To unpause the PSMDB cluster set spec.pause: false in your cr.yaml file and apply it with kubectl. Then, repeat the steps below for all replica sets, starting with Config RS.

  1. Login to the shell of “pod 0” of the replica set with kubectl exec –stdin –tty cluster_name-cfg-0 — /bin/bash (for Config RS)
  2. Login to PSMDB with mongo command
  3. Authenticate as clusterAdmin using the following command (assuming you used default passwords):

    use admin;
    db.auth("clusterAdmin", "clusterAdmin123456");
  4. Initialize the replica set as below. Replace cluster_name and namespace_name and shard_name with your own values.

    # version for Config RS
    
    rs.initiate(
       {
         _id: "cfg",
          members: [
             { _id: 0, host : "cluster_name-cfg-0.cluster_name-cfg.namespace_name.svc.cluster.local:27017" },
             { _id: 1, host : "cluster_name-cfg-1.cluster_name-cfg.namespace_name.svc.cluster.local:27017" },
             { _id: 2, host : "cluster_name-cfg-2.cluster_name-cfg.namespace_name.svc.cluster.local:27017" },
          ]
       }
    );
    
    # version for other RS (shards)
    rs.initiate(
       {
         _id: "shard_name",
          members: [
             { _id: 0, host : "cluster_name-shard_name-0.cluster_name-shard_name.namespace_name.svc.cluster.local:27017" },
             { _id: 1, host : "cluster_name-shard_name-1.cluster_name-shard_name.namespace_name.svc.cluster.local:27017" },
             { _id: 2, host : "cluster_name-shard_name-2.cluster_name-shard_name.namespace_name.svc.cluster.local:27017" },
          ]
       }
    );
  5. After a few seconds, your node will become PRIMARY. You can check the health of the replica set using the rs.status() command. Remember that if your dataset is large, the initial synchronization process may take a long time (as with any MongoDB deployment).

That’s it! You now successfully restored a snapshot backup into Percona Server for MongoDB deployed on K8s with Percona Operator. To verify that you have successfully done that run kubectl get pods or kubectl get psmdb – the output should be similar to the one below.

$ kubectl get psmdb
NAME              ENDPOINT                                        STATUS   AGE
my-cluster-name   my-cluster-name-mongos.ns-0.svc.cluster.local   ready    156m

 

The Percona Kubernetes Operators automate the creation, alteration, or deletion of members in your Percona Distribution for MySQL, MongoDB, or PostgreSQL environment.

Learn More About Percona Kubernetes Operators

Apr
28
2023
--

Add More Security to Your Percona Server for MongoDB With AWS IAM integration!

MongoDB With AWS IAM Integration

Did you notice that Percona Server for MongoDB 6.0.5-4 was released just a few days ago? This time around, it introduced improvements to the way we handle master key rotation for data at rest encryption as well as AWS IAM integration.

One key to rule them all — improvements to master key rotation

With the improvements introduced in Percona Server for MongoDB 6.0.5-4, one key path can be used for all servers in a clustered environment. This allows us to use one vault key namespace for all nodes in a deployment while at the same time preserving key versions and allowing each node to perform key rotation without impact to the other nodes.

Changes introduced with Percona Server for MongoDB 6.0.5-4 now allow using the same key for all the members of a replica set if the user chooses so, without impact on functionality.

Why should you care about AWS IAM integration?

With all the systems users need to access daily, password management becomes a more pressing issue. The introduction of IAM systems to an enterprise has become somewhat of a security standard in large enterprises.

Our users approached us about integration with AWS IAM, commonly used in their organizations. It’s an integration missing from MongoDB Community Edition (CE) that is important for compliance with enterprise security policies of many companies. Integration with AWS IAM allows:

MongoDB AWS IAM integration

To set up this integration, follow the steps outlined in our documentation, and configure either the user or the role authentication. This will allow AWS Security Token Service (STS) to play the part of Identity Provider (IDP) in a SAML 2.0-based federation.

Your feedback matters!

We take pride in being open to feedback in Percona. Please do not hesitate to contact us via the community forums or this contact form.

What’s next

We are looking into the problems affecting large size datastores that are a pain to our users. Please let us know if there are any particular issues you are struggling with in MongoDB; we are always open to suggestions!

Learn more about Percona Server for MongoDB

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com