  Self-adaptation can be realized in various ways. Rule-based approaches
prescribe the adaptation to be executed if the system or environment satisfies
certain conditions. They result in scalable solutions but often with merely
satisfying adaptation decisions. In contrast, utility-driven approaches
determine optimal decisions by using an often costly optimization, which
typically does not scale for large problems. We propose a rule-based and
utility-driven adaptation scheme that achieves the benefits of both directions
such that the adaptation decisions are optimal, whereas the computation scales
by avoiding an expensive optimization. We use this adaptation scheme for
architecture-based self-healing of large software systems. For this purpose, we
define the utility for large dynamic architectures of such systems based on
patterns that define issues the self-healing must address. Moreover, we use
pattern-based adaptation rules to resolve these issues. Using a pattern-based
scheme to define the utility and adaptation rules allows us to compute the
impact of each rule application on the overall utility and to realize an
incremental and efficient utility-driven self-healing. In addition to formally
analyzing the computational effort and optimality of the proposed scheme, we
thoroughly demonstrate its scalability and optimality in terms of reward in
comparative experiments with a static rule-based approach as a baseline and a
utility-driven approach using a constraint solver. These experiments are based
on different failure profiles derived from real-world failure logs. We also
investigate the impact of different failure profile characteristics on the
scalability and reward to evaluate the robustness of the different approaches.
