What's the difference between gdbserver and remote gdb (i.e. over SSH)? Why do they coexist? The Unix philosophy suggests the software should do one thing well, i.e. debug local programs. It seems to me that gdb violates this principle by doing another thing in addition to that - interacting with gdbserver.
gdbserver is smaller than GDB and has fewer dependencies, so it can be run on a system which is resource constrained such that GDB itself can't be run. Or maybe GDB just can't be run for some other reason, e.g. the target platform doesn't have Python, and you want to use some of the Python features of GDB.
Next, but kind of related, the target platform might not be the same architecture as the host platform (on which GDB runs), maybe compiling GDB, Python, syntax-highlighting libraries, etc for a small target isn't what you want to do with your time, instead you can just compile gdbserver, and then run GDB on your local machine.
Finally, though gdbserver is useful in itself, it also serves as a useful mechanism to test GDB's remote serial protocol support. This protocol is documented in the GDB manual and allows software other than gdbserver to interact with GDB, for example OpenOCD, and QEMU, both support GDB's remote protocol, this allows GDB to debug baremetal targets on which neither GDB, nor gdbserver could ever run.
You are correct to observe that this basically means that GDB has two methods of debug, its native target support, and its remote target support. If we wanted to be ideologically pure then we could (in theory) remove the native target support from GDB, and just make use of the gdbserver in all cases, i.e. when you try to debug a program on the local machine, GDB would automatically start gdbserver, connect to it, and debug through that interface. I don't expect to see that change any time soon though.