您可以将复制用作扩展解决方案;也就是说,在某些合理限制内,您希望将数据库查询的负载拆分到多个数据库服务器上。You can use replication as a scale-out solution; that is, where you want to split up the load of database queries across multiple database servers, within some reasonable limitations.
因为复制是从一个源分发到一个或多个副本,所以在扩展环境中使用复制最适合在读操作多而写/更新操作少的环境中使用。大多数网站都符合这一类别,用户在浏览网站、阅读文章、帖子或查看产品时。更新通常只在会话管理期间发生,或者在进行购买或向论坛添加评论/消息时发生。Because replication works from the distribution of one source to one or more replicas, using replication for scale-out works best in an environment where you have a high number of reads and low number of writes/updates. Most websites fit into this category, where users are browsing the website, reading articles, posts, or viewing products. Updates only occur during session management, or when making a purchase or adding a comment/message to a forum.
在这种情况下,复制使您能够将读取操作分布到各个副本上,同时仍然允许您的 Web 服务器在需要写操作时与源进行通信。您可以在 图 19.1,“使用复制在扩展过程中提高性能” 中看到此场景的示例复制布局。Replication in this situation enables you to distribute the reads over the replicas, while still enabling your web servers to communicate with the source when a write is required. You can see a sample replication layout for this scenario in Figure 19.1, “Using Replication to Improve Performance During Scale-Out”.
如果负责数据库访问的代码部分已经被适当抽象/模块化,那么将其转换为使用复制设置应该非常顺利和容易。将数据库访问的实现更改为将所有写入发送到源数据库,并将读取发送到源数据库或副本。如果你的代码没有这种抽象级别,设置复制系统为你提供了整理它的机会和动机。首先创建一个封装库或模块,实现以下函数:If the part of your code that is responsible for database access has been properly abstracted/modularized, converting it to run with a replicated setup should be very smooth and easy. Change the implementation of your database access to send all writes to the source, and to send reads to either the source or a replica. If your code does not have this level of abstraction, setting up a replicated system gives you the opportunity and motivation to clean it up. Start by creating a wrapper library or module that implements the following functions:
safe_writer_connect()safe_reader_connect()safe_reader_statement()safe_writer_statement()
safe_ 在每个函数名中表示该函数会处理所有错误情况。你可以为函数使用不同的名称。重要的是要有一个统一的接口来进行读取连接、写入连接、执行读取以及执行写入。safe_ in each function name means that the
function takes care of handling all error conditions. You can use
different names for the functions. The important thing is to have
a unified interface for connecting for reads, connecting for
writes, doing a read, and doing a write.
然后将你的客户端代码转换为使用包装库。这一过程一开始可能会很痛苦和令人害怕,但从长远来看是值得的。所有使用上述方法的应用程序都能够利用源/副本配置,即使涉及多个副本。代码更容易维护,并且添加故障排除选项非常简单。你只需要修改一两个函数(例如,记录每条语句耗时,或者记录已执行的语句中出现错误的语句)。Then convert your client code to use the wrapper library. This may be a painful and scary process at first, but it pays off in the long run. All applications that use the approach just described are able to take advantage of a source/replica configuration, even one involving multiple replicas. The code is much easier to maintain, and adding troubleshooting options is trivial. You need modify only one or two functions (for example, to log how long each statement took, or which statement among those issued gave you an error).
如果你已经写了很多代码,你可能会想通过编写转换脚本来自动化转换任务。理想情况下,你的代码使用一致的编程风格规范。如果没有,那么你可能最好还是重新编写它,或者至少手动整理,使其使用一致的风格。If you have written a lot of code, you may want to automate the conversion task by writing a conversion script. Ideally, your code uses consistent programming style conventions. If not, then you are probably better off rewriting it anyway, or at least going through and manually regularizing it to use a consistent style.
