I have had the same issues since release. I have absolutely no problem playing competitive matchmaking but campaign co-op and fire fight with more than 2 people is laggy as hell.
Some time ago Bungie.net addressed the problem where they discussed how co-op and fire fight use a different method of connecting players than competitive. It called “a-synchronous” connection type instead of the usual distributive method that most games use these days.
From Bungie.Net: Q. Why does latency affect the cooperative and multiplayer experiences in such dramatically different ways? Both gameplay modes are using the same network architecture, right? A. We actually use different networking models for our cooperative and multiplayer games. Firefight and campaign co-op use what we call a synchronous or lockstep model, and multiplayer/Forge use a distributed model. A synchronous model works by clients sending controller inputs to the host, who waits for inputs from all players in the game, packages them up into a single message, and sends the message back out to all the machines in the game. Each machine then uses this message to advance the state of their world by a frame, and then the whole cycle repeats. So, same inputs to the game means we all get the same outputs. In a distributed model, the big difference is that each machine is running their “own” world, and we are keeping state synchronized between machines by sending messages about things that are changing. For example, when a player holds down their trigger to fire their SMG, we immediately fire it on their machine, and send a message to the host that the player is firing, and the host sends a message to the other machines in the game to let them know the player is firing. So, one big difference between the two models is latency. With a distributed model most actions like firing your weapon, jumping, running, and meleeing, all feel snappy and responsive. You press the button and your player immediately does them on your screen. In the synchronous model, your input has to make its way to the host, who has to wait for all the other inputs from the other players, who then has to send a message back that you can process and then your world state can react. This means that if you are in LA and your host is in Sydney, the game will feel sluggish and unresponsive. Things like packet loss are acutely felt as well, as your inputs to the host are sent in order, and his messages back to you are sent in order as well, so the entire game needs to wait until dropped packets can be re-transmitted.
Hopefully, 343i can address this issue in the future.